1 #!/usr/bin/env python
2 """
3 购物系统
4
5 aim :
6 1. 登录-三次失败锁定; 账户锁定可通过验证码解锁重新设置密码
7 2. 展示商品-分页,当前页焦点
8 3. 购物记录-文件,用户退出会生成一个已购物日志文件.
9 4. 余额浮点数
10 5. 查看购物车支持模糊查询,不区分大小写
11 6. 区分游客和正式用户;游客可直接浏览商品,可直接加入购物车;但购买需登录
12 7. 游客浏览只有登录和购物车两个选项
13 8. 登录后,取消登录选项,增加结账,充值和退出三个选项
14 9. 游客状态的购物车,在登录后仍然保留;可直接进行结账操作.
15 10. 用户登录后,选购商品,不结账,购物车保存. 退出下次登录购物车仍然有上次的记录,结账后清空.
16 11. 购物车实现删除功能.
17
18 need :
19 1. 用户输入
20 2. 商品信息文件
21 3. 用户信息文件
22
23 待完善:
24 1. 终端输出有待优化
25 {
26 1. 格式化字符串
27 2. 提示语
28 }
29 4. None
30 """
31
32
33 # vars and funcs
34
35 # 格式化打印清单; 返回消费总金额
36 def show_card(dic):
37 sum_money = 0
38 top_str = ">>您选购的商品列表<<"
39 print('\n' + top_str.center(100, ' '))
40 print("-" * 100)
41 print("{}\t\t{}\t\t{}\t\t{}".format("小计", "数量", "单价", "商品").expandtabs(10))
42 print("-" * 100)
43 for ITEM in dic:
44 sum_money += float(get_price(ITEM)) * int(dic[ITEM])
45 print('%.2f\t\t%d\t\t%.2f\t\t%s'.expandtabs(10) % (
46 float(get_price(ITEM)) * int(dic[ITEM]), int(dic[ITEM]),
47 float(get_price(ITEM)), ITEM))
48 print("-" * 100)
49 return sum_money
50
51
52 # 判断是否是浮点数
53 def is_floated(para):
54 try:
55 float(para)
56 return True
57 except:
58 return False
59
60
61 # 生成随机验证码
62 def get_random_code():
63 import random
64 random_code = ''
65 for i in range(4):
66 cur = random.randrange(0, 4)
67 if cur != i:
68 temp = chr(random.randint(65, 90))
69 else:
70 temp = random.randint(0, 9)
71 random_code += str(temp)
72 return random_code
73
74
75 # 解锁账户
76 def unlock_account(username):
77 print('\n解锁账户须进行以下验证')
78 while True:
79 code_random = get_random_code()
80 print('验证码: ', code_random)
81 user_code = input('请输入上述的验证码: ')
82 if str(user_code).strip() == code_random:
83 print('验证通过,请重新设置密码.')
84 new_pass = input('请输入新密码: ')
85 confirm_pass = input('请再输一遍密码: ')
86 if new_pass == confirm_pass:
87 for user_item in user_detail_list:
88 if user_item['name'] == username:
89 user_item['pwd'] = confirm_pass
90 user_item['times'] = 0
91 return True
92 else:
93 print('输入错误,请重新设置.')
94 else:
95 print('验证码输入错误,请重新输入.')
96
97
98 # 判断是否有登录在线用户, 返回用户的姓名,登录状态,总金额,用户列表在总用户列表里面的下标
99 def user_is_auth():
100 rt_list = []
101 for user_dic in user_detail_list:
102 if user_dic['status'] == 1:
103 rt_list.append(user_dic['name'])
104 rt_list.append(user_dic['status'])
105 rt_list.append(user_dic['money'])
106 rt_list.append(user_detail_list.index(user_dic))
107 return rt_list
108
109
110 # 返回10条记录, 可根据page_numb来展示
111 def get_ten_record(pas_list, page_numb=1):
112 return_list = []
113 start_num = (int(page_numb) - 1) * 10
114 end_num = int(page_numb) * 10
115 for ITEM in range(start_num, end_num):
116 if ITEM < len(pas_list):
117 return_list.append(pas_list[ITEM])
118 return return_list
119
120
121 # 获取商品价格
122 def get_price(goods_name):
123 with open('goods.info', 'r', encoding='utf-8') as file_goods:
124 for goods in file_goods.readlines():
125 goods = goods.strip().split('---')
126 if goods_name in goods:
127 return goods[-1]
128
129
130 # 打印10条记录
131 def show_ten_record(return_list, num):
132 print('\n%s\t\t%s\t\t%s'.expandtabs(10) % ('商品ID', '商品价格', '商品名称'))
133 print('-' * 80)
134 for K, ITEM in enumerate(return_list, 1000 + 10 * (num - 1) + 1):
135 print('%d\t\t%.2f¥\t\t%s'.expandtabs(10) % (K, float(ITEM[1]), ITEM[0]))
136 id_list.append(K)
137 print()
138 print_str = ''
139 for i in range(1, end_with):
140 if i != end_with - 1:
141 print_str = print_str + ' ' + str(i) + ' | '
142 else:
143 print_str = print_str + ' ' + str(i) + ' '
144 print(print_str.replace(' ' + str(num) + ' ', ' < ' + str(num) + ' > ') + '\n')
145
146
147 # ########################## 用户信息文件处理 start ##########################
148 # 存放用户信息
149 # user_detail_list = [
150 # {
151 # 'name': 'alex',
152 # 'pwd': 12121212,
153 # 'times': 2,
154 # 'money': 120000.00,
155 # 'status': 0
156 # }
157 # ...
158 # ]
159 user_detail_list = []
160
161 with open('db', 'r') as f_user:
162 for user_info in f_user.readlines():
163 user_detail = user_info.split('|')
164 user_detail_list.append({
165 'name': user_detail[0].strip(),
166 'pwd': user_detail[1].strip(),
167 'times': user_detail[2].strip(),
168 'money': user_detail[3].strip(),
169 'status': 0 # 登录状态,未登录0,登录1
170 })
171
172 # 用户消费记录列表
173 record_user_crash = []
174 # ########################## 用户信息文件处理 end ##########################
175 # ########################## 商品信息文件处理 start ##########################
176 # 将商品信息从文件里面取出来,每行一个列表,存在列表里面
177 book_all_list = []
178 with open('goods.info', 'r', encoding='utf-8') as f_goods:
179 for line in f_goods.readlines():
180 book_list = line.strip().split('---')
181 book_all_list.append(book_list)
182
183 # 定义空列表,用来存放展示的商品ID,由于可变;因此选择list
184 id_list = []
185 # 定义页码元组
186 lens = len(book_all_list)
187 if lens % 10:
188 end_with = lens // 10 + 2
189 else:
190 end_with = lens // 10 + 1
191 pn_list = tuple(range(1, lens))
192 # 定义用户操作行为元组
193 uc_tuple = ('登录', '购物车')
194 uc_login_tup = ('充值', '结账', '购物车', '退出')
195
196 # 定义缺省购物车
197 # 购物车设计
198 # default_goods_dic = {
199 # '老男孩Mysql私房菜': 3
200 # }
201 default_goods_dic = {}
202 # ########################## 商品信息文件处理 end ##########################
203 # main start
204 print('''\n
205 欢迎来到老男孩购物商城
206 提示:
207 a. 您可以直接输入商品ID将商品加入购物车
208 b. 您也可以直接登录、查看购物车
209 c. 您也可以输入页码进行翻页
210 ''')
211 print('商品首页')
212
213 page_num = 1
214 while True:
215 # 默认显示首页
216 show_ten_record(get_ten_record(book_all_list, page_num), page_num)
217
218 # 获取登录状态
219 res_auth = user_is_auth()
220
221 # 登录判断
222 if res_auth:
223 # 用户文件名 - 字符串
224 user_record_file = user_is_auth()[0] + '.info'
225
226 # 用户登录,生成用户所属购物车文件
227 user_choice_file = user_is_auth()[0] + '.car'
228 import os
229
230 if os.path.exists(user_choice_file):
231 if os.path.getsize(user_choice_file):
232 with open(user_choice_file, 'r') as fw_shop:
233 for line in fw_shop.readlines():
234 shop_record = line.strip().split('---')
235 default_goods_dic[shop_record[0]] = shop_record[-1]
236 os.remove(user_choice_file)
237 # print(default_goods_dic)
238 # 一次性操作,登录后去掉登录显示
239 uc_temp = uc_login_tup
240 # 打印功能列表
241 for k, v in enumerate(uc_temp, 101):
242 print('{0}. {1}'.format(k, v))
243
244 user_choice_num = input('\n欢迎你, ' + res_auth[0] + ' 请开始你的表演: ')
245 else:
246 # 未登录时,显示登录
247 uc_temp = uc_tuple
248 # 打印功能列表
249 for k, v in enumerate(uc_temp, 101):
250 print('{0}. {1}'.format(k, v))
251
252 user_choice_num = input('\n游客,您好; 请开始你的表演: ')
253
254 if user_choice_num.isdigit():
255 user_num = int(user_choice_num)
256 if user_num in pn_list:
257 page_num = user_num
258 print('\n当前您正在浏览第 {} 页'.format(page_num))
259 elif 100 < user_num < 105:
260 # 登录 默认显示
261 if uc_temp[user_num - 100 - 1] == '登录':
262 print('login')
263 flag = True
264 # 退出次数
265 exit_flag = 3
266 # main process
267 while flag:
268 user_name = input("用户名: ")
269 # 遍历用户信息列表
270 for item in user_detail_list:
271 # 判断用户名是否存在
272 if user_name == item['name']:
273 # 用户存在判断是否锁定
274 if int(item['times']) < exit_flag:
275 user_pwd = input("密码: ")
276 # 校验密码
277 if user_pwd == item['pwd']:
278 print('登录成功\n\n')
279 # 更新字典
280 item['times'] = 0
281 # 写入登录状态
282 item['status'] = 1
283 # 更新while循环标志位
284 flag = False
285 # 退出for循环
286 break
287 else:
288 print('密码错误')
289 # 更新字典
290 item['times'] = int(item['times']) + 1
291 # 退出for循环,继续输入用户名
292 break
293 else:
294 print("用户已经锁定")
295 while True:
296 lock_choice = input('1. 更换账户\t2. 找回密码\n >> ')
297 if lock_choice.isdigit():
298 if int(lock_choice) == 1:
299 break
300 elif int(lock_choice) == 2:
301 if unlock_account(user_name):
302 print('重置密码成功,请重新登录')
303 break
304 break
305 else:
306 print('用户名不存在')
307
308 # 充值 登录后显示
309 if uc_temp[user_num - 101] == '充值':
310 charge_money = input('请输入要充值的金额: ')
311 if is_floated(charge_money):
312 charge_money = float(charge_money)
313 item_money = float(res_auth[2])
314 item_money += charge_money
315 user_detail_list[res_auth[-1]]['money'] = item_money
316 print('您已成功充值%.2f元, 账户余额%.2f' % (charge_money, item_money))
317 else:
318 print('输入无效')
319
320 # 结账 登录后显示
321 if uc_temp[user_num - 101] == '结账':
322 import time
323
324 crash_money = 0
325 if default_goods_dic:
326 crash_money = show_card(default_goods_dic)
327 if float(crash_money) > float(res_auth[2]):
328 print('您本次消费总共:%.2f ;余额不足,您至少需要充值 %.2f 人民币!' % (crash_money, crash_money - float(res_auth[2])))
329 else:
330 user_detail_list[res_auth[-1]]['money'] = float(res_auth[2]) - crash_money
331 print('您本次消费总共:%.2f ;\n\t\t账户余额: %.2f !' % (crash_money, float(res_auth[2]) - crash_money))
332 # 将购物记录记录到文件
333 for item in default_goods_dic:
334 each_str = u'{}在{}购买了{}本单价为{}人民币的{}\n'.format(
335 user_is_auth()[0], time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())),
336 default_goods_dic[item], get_price(item), item)
337 record_user_crash.append(each_str)
338 # 结账完毕,清空购物车
339 default_goods_dic.clear()
340 else:
341 print('购物车为空')
342
343 # 查看购物车 默认显示 支持删除
344 if uc_temp[user_num - 101] == '购物车':
345 crash_money = 0
346 if default_goods_dic:
347 while True:
348 show_card(default_goods_dic)
349 crash_choice = input('结账请先登录, 查询请输入S/s, 删除请输入D/d, 返回请按Q/q')
350 if crash_choice.strip().lower() == 's':
351 while True:
352 sc_name = input('请输入要查询的商品名[支持模糊查询,退出请按Q/q]: ')
353 if sc_name.strip().lower() != 'q':
354 for item in default_goods_dic.keys():
355 if sc_name.lower() in item.lower() and sc_name.strip() != '':
356 print('%.2f\t\t%d\t\t%.2f\t\t%s'.expandtabs(20) % (
357 float(get_price(item)) * default_goods_dic[item],
358 default_goods_dic[item],
359 float(get_price(item)), item))
360 else:
361 break
362 elif crash_choice.strip().lower() == 'd':
363 while True:
364 if default_goods_dic:
365 del_name = input('请输入要删除的商品名称, 退出请按Q/q: ')
366 if del_name.strip().lower() != 'q':
367 try:
368 v = default_goods_dic.pop(del_name)
369 print('您已经从购物车移除{}本{}'.format(v, del_name))
370 except KeyError:
371 print('移除失败')
372 else:
373 break
374 else:
375 print('购物车已被清空')
376 elif crash_choice.strip().lower() == 'q':
377 break
378 else:
379 print('购物车为空')
380
381 # logout
382 if uc_temp[user_num - 101] == '退出':
383 print('欢迎下次光临')
384 # 更新用户status
385 user_detail_list[user_is_auth()[-1]]['status'] = 0
386 if default_goods_dic:
387 with open(user_choice_file, 'w') as fw_record:
388 for item in default_goods_dic.items():
389 fw_record.writelines(item[0] + '---' + str(item[1]) + '\n')
390
391 break
392
393 elif user_num in id_list:
394 # # 添加商品到购物车,若未登录则添加到默认购物车dict,登录成功则创建用户自己的购物车dict
395 # 获取页码数
396 # page_num = int(str(user_num)[-2]) + 1
397 page_num = int(str(user_num - 1)[-2]) + 1
398 # 获取商品列表下标
399 goods_index = int(str(user_num)[-1]) - 1
400 # 得到当前页当前id的商品信息 list
401 goods_info = get_ten_record(book_all_list, page_num)[goods_index]
402 # print(good_info)
403 # 往用户购物车添加记录,若无登录则使用default
404 if goods_info[0] not in default_goods_dic:
405 default_goods_dic[goods_info[0]] = 1
406 else:
407 default_goods_dic[goods_info[0]] += 1
408 print('\n提示: 您已成功将一本 {} 添加到购物车, 目前数量 {} 本'.format(goods_info[0], default_goods_dic[goods_info[0]]))
409 else:
410 print('表演不满意,请重新开始你的表演\n')
411
412 # 最后,将用户信息写入文件
413 # 写入文件
414 with open('db', 'w') as f_user:
415 for item in user_detail_list:
416 f_user.truncate()
417 item_str = '{name}|{pwd}|{times}|{money}|{status}\n'.format_map(item)
418 # print(item_str)
419 f_user.writelines(item_str)
420
421 # 写入用户的购物记录
422 with open(user_record_file, 'a') as uw_file:
423 uw_file.writelines(record_user_crash)
424 record_user_crash.clear()