1 # -*-coding:utf-8 -*-
2 # 使用openpyxl操作xlsx文件数据,可以在同一excel中新建其他sheet
3 import pandas as pd
4 import time
5 import openpyxl
6 import openpyxl.styles # 设置格式
7 file_path = r'E:学习PythonPandas模块的导入及学习-数据分析ank.xlsx' # 若是同一项目下的文件,可直接使用'./bank.xlsx'文件路径即可
8 bank_file = openpyxl.load_workbook(file_path)
9 bank = bank_file['user']
10 bank_error = bank_file['input_error']
11
12
13 def home_page(): # 主界面
14 print('欢迎使用ATN银行自助系统'.center(40, '='))
15 print('1.登录账户'.center(40, ' '))
16 print('2.注册账户'.center(40, ' '))
17 print('3.退出系统'.center(40, ' '))
18 print('欢迎使用ATM银行自助系统'.center(40, '='))
19
20
21 def welcome_page(): # 登录成功界面
22 print('欢迎使用银行ATM自助服务系统'.center(60, '='))
23 print('* 您好 %s *'.center(60, ' ') % input_name)
24 print()
25 print('1.查询余额 2.自助取款'.center(60, ' '))
26 print('3.自助存款 4.修改密码'.center(60, ' '))
27 print('5.查询操作历史 6.回主菜单'.center(60, ' '))
28 print(' 7.退出系统 '.center(60, ' '))
29 print()
30 print('欢迎使用银行ATM自助服务系统'.center(60, '='))
31
32
33 def judge(input_date): # 判断输入的时间是否正确
34 date = input_date.split('-') # 用-符将数据分隔开
35 list1 = []
36 if len(date) == 3:
37 for j in range(len(date)):
38 if date[j].isdigit():
39 list1.append(int(date[j]))
40 else:
41 print('输入数据非纯数字,请重新输入')
42 break
43 else: # 都是数字执行完后,执行的内容
44 year, month, day = list1[0], list1[1], list1[2]
45 if len(str(year)) == 4: # int型数据无len
46 if 0 < month <= 12:
47 if (month in (1, 3, 5, 7, 8, 10, 12)) and (day > 31 or day <= 0):
48 print(f'输入日期有误,{month}为大月,天数最多为31天,请重新输入!')
49 elif (month in (4, 6, 9, 11)) and (day > 30 or day <= 0):
50 print(f'输入日期有误,{month}为小月,天数最多为30天,请重新输入!')
51 elif month == 2:
52 if ((year % 4 == 0) and (year % 100 != 0)) or (year % 400 == 0):
53 if (day > 29) or (day <= 0):
54 print('输入的日期有误,该年2月为闰年2月,最多29天。请重新输入!')
55 else:
56 if (day > 28) or (day <= 0):
57 print('输入的日期有误,该年2月为平年2月,最多28天。请重新输入!')
58 else:
59 return True
60 else:
61 print('输入的月份错误,每年只有12个月,请重新输入')
62 else:
63 print('输入日期有误,年份必须是四位数,请重新输入')
64 else:
65 print('输入的日期长度有误,请重新输入')
66
67
68 def bank_list(): # 将name/password列表化
69 global name_list, password_list,error_name_list
70 name_list, password_list, error_name_list = [], [], []
71 error_row = bank_error.max_row
72 row = bank.max_row
73 # bank_file中各sheet的行和列写在此处,否则excel中的数据不是即时的数据,保存后继续执行可能无法立即查询到
74 # 此步骤涉及到login()处bank_error添加登录错误的新成员、add_user()处bank添加账户的新成员问题
75 for i in range(1, row + 1): # 将password这一列转为字符串类型
76 str(bank.cell(i, 2).value)
77 for j in range(2, row+1):
78 name_list.append(bank.cell(j, 1).value) # name第一列数据,从第2行开始读取
79 password_list.append(bank.cell(j, 2).value) # password第二列数据,....
80 for k in range(2, error_row+1):
81 error_name_list.append(bank_error.cell(k, 1).value) # error_name第一列数据...
82
83
84 def re_password(): # 修改密码
85 old_password = input('请输入原6位数密码:')
86 if old_password == password_list[new_index]:
87 while True:
88 new_password = input('请输入新6位数密码:')
89 again_password = input('请再次输入新6位数密码:')
90 if new_password == '' or again_password == '':
91 print('密码不能为空,请重新输入')
92 elif new_password == again_password and new_password != '':
93 if new_password.isdigit(): # 判断是否是纯数字
94 if len(new_password) == 6: # 判断长度是否为6
95 print('密码修改成功')
96 bank.cell(new_index + 2, 2, new_password)
97 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 修改密码')
98 bank.cell(new_index + 2, 4, str(history_list))
99 bank_file.save(file_path)
100 break
101 else:
102 print('密码长度错误,请重新输入6位有效数字密码!')
103 else:
104 print('密码应为纯数字密码,请输入6位有效数字密码!')
105 elif new_password != again_password:
106 print('两次密码输入不一致,请重新输入')
107
108 elif old_password != password_list[new_index]:
109 print('原密码输入错误,请重新输入')
110 re_password()
111 else:
112 print('请输入有效的数字')
113
114
115 def search_record(): # 查询历史记录
116 while True:
117 start_date = input('请输入查询开始时间Y-m-d:') # 若想精确到时分秒,切片10变成取到19即可
118 if judge(start_date):
119 while True:
120 end_date = input('请输入查询结束时间Y-m-d:')
121 if judge(end_date):
122 start_time = pd.to_datetime(start_date) # 将输入的文本转化为时间格式
123 end_time = pd.to_datetime(end_date)
124 if start_time > end_time:
125 print('开始时间大于结束时间,请重新输入时间')
126 break
127 else:
128 print(f'查询开始时间为:{start_date}')
129 print(f'查询结束时间为:{end_date}')
130 record = []
131 for j in history_list:
132 if start_time <= pd.to_datetime(j[0:10:]) <= end_time: # 对列表中的时间进行切片处理并转为时间格式
133 print(j)
134 record.append(j)
135 else: # for正常执行完,会执行else内容,不正常结束,不执行else内容--可避免筛选出一条记录跟着打印出一条提示内容
136 if len(record) != 0:
137 print(f'该时间段的操作记录有{len(record)}条')
138 # 该时间段的历史记录导出到新excel中
139 out_put = input('是否导出到新excel?1.是,2.否--')
140 if out_put == '1': # 导出
141 new_excel = openpyxl.Workbook()
142 new_sheet = new_excel.active # 当前活跃的sheet,默认第一个sheet,也可使用create_sheet
143 new_sheet.title = f'{start_date}-{end_date}时间段的历史记录'
144 new_sheet.append(['时间', '操作记录'])
145 font = openpyxl.styles.Font('宋体', size=11, bold=True, color='000000') # 设置单元格格式
146 new_sheet['A1'].font = font
147 new_sheet['B1'].font = font
148 list_record = []
149 for i in record:
150 list_record.append(i[0:19])
151 list_record.append(i[23::]) # 将时间字段与操作名称拆开放入列表中
152 temp_list = zip(*(iter(list_record),) * 2) # 将列表中的数据拆成2个元素组成一个列表
153 for j in temp_list:
154 new_sheet.append(list(j)) # 数据写入到new_sheet中
155 """
156 将列表中的数据拆成2个元素组成一个列表也可写成下面这种代码:
157 for k in range(0, len(list_record), 2):
158 list2 = list()
159 list2.append(list1[k])
160 list2.append(list1[k+1])
161 new_sheet.append(list2)
162 """
163 filename = 'C://Users//Administrator//Desktop//'
164 + f'{input_name}的{start_date}-{end_date}间的操作记录' + '.xlsx'
165 # 这里的路径是进行组合的,因此不能写成r‘/’的形式,这种形式无法组合,写成//路径即可实现组合
166 new_excel.save(filename)
167 print('历史记录导出成功')
168 else:
169 input('>>按确定键继续为您服务<<')
170 else:
171 print('该时间段无操作记录')
172 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 查询历史')
173 bank.cell(new_index + 2, 4, str(history_list))
174 bank_file.save(file_path)
175 break
176 break
177
178
179 def work(): # 主界面程序
180 while True:
181 welcome_page()
182 action_str2 = input('请输入您的操作:')
183 if action_str2 == '1': # 查询余额
184 print(f'你的账户余额是:{bank.cell(new_index+2, 3).value} 元')
185 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 查询余额')
186 bank.cell(new_index+2, 4, str(history_list))
187 # bank.cell(new_index+2, 4).value = str(history_list)
188 bank_file.save(file_path)
189 input('>>按确定键继续为您服务<<')
190 elif action_str2 == '2': # 取款
191 money_out = int(input('请输入取款金额:'))
192 if money_out <= bank.cell(new_index+2, 3).value:
193 bank.cell(new_index+2, 3).value -= money_out
194 print(f"您的取款金额为{money_out}元,剩余金额为{bank.cell(new_index+2, 3).value}元")
195 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 取款'
196 + str(money_out)+'元')
197 bank.cell(new_index + 2, 4, str(history_list))
198 bank_file.save(file_path)
199 else:
200 print('您的余额不足,请重新选择金额')
201 input('>>按确定键继续为您服务<<')
202 elif action_str2 == '3': # 存款
203 money_in = int(input('请输入存款金额:'))
204 bank.cell(new_index+2, 3).value += money_in
205 print(f"您的存款金额为{money_in}元,剩余金额为{bank.cell(new_index+2, 3).value}元")
206 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 存款' + str(money_in)+'元')
207 bank.cell(new_index + 2, 4, str(history_list))
208 bank_file.save(file_path)
209 input('>>按确定键继续为您服务<<')
210 elif action_str2 == '4': # 修改密码
211 re_password()
212 print('即将退出当前界面,重新登录')
213 input('>>按确定键继续为您服务<<')
214 main_menu()
215 elif action_str2 == '5': # 查询操作记录
216 # 历史记录太多,也可再建一个sheet专门放历史记录,列名为客户名、时间、操作记录,(建议再加一个客户id号,同名的人查询不会出错)
217 # 也就是每一步操作后再sheet.append([input_name,操作的时间,操作的记录]),相应的查询操作历史处代码也要跟着改变
218 search_record()
219 while True:
220 action_str3 = input('请输入您的操作1.继续查询历史;2.回到操作界面---')
221 if action_str3 == '1':
222 search_record()
223 elif action_str3 == '2':
224 break
225 else:
226 print('输入错误,请重新输入')
227 input('>>按确定键继续为您服务<<')
228 elif action_str2 == '6': # 回主菜单
229 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 退回主界面')
230 bank.cell(new_index + 2, 4, str(history_list))
231 bank_file.save(file_path)
232 main_menu()
233 elif action_str2 == '7': # 退出系统
234 input('>>按确定键退出系统<<')
235 print('欢迎您的下次光临')
236 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 退出系统')
237 bank.cell(new_index + 2, 4, str(history_list))
238 bank_file.save(file_path)
239 exit()
240 else:
241 print('您的输入有误,请重新输入')
242 input('>>按确定键继续为您服务<<')
243
244
245 def login(): # 登录账户
246 global input_name,history_list,new_index
247 while True:
248 bank_list()
249 input_name = input('请输入您的姓名:')
250 input_password = input('请输入您的密码:')
251 if input_name in name_list and input_password != '':
252 new_index = name_list.index(input_name)
253 if input_password == password_list[new_index]:
254 # ps:单纯的姓名与密码登录不够严谨,因为若有同名的,只要保证输入的密码是其中一个就能登录成功,因此可再加入身份证,id等字段验证
255 history_list = eval(bank.cell(new_index+2, 4).value) # # 转化为原列表形式
256 history_list.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())+' 登录系统')
257 bank_file.save(file_path)
258 work()
259 else: # 输入名字不在,创建数据;输入名字在列表中,时间为今天,先判断次数,再继续计算次数;时间不是今天,将时间设为今天,次数变为1,与创建数据一致
260 print('账户和密码不匹配,请重新输入')
261 error_time = time.strftime('%Y-%m-%d', time.localtime())
262 if input_name not in error_name_list:
263 value = [input_name, 1, error_time]
264 bank_error.append(value)
265 bank_file.save(file_path)
266 print('今日已输入错误1次,还剩2次机会')
267 # 加入的名字,执行后,不在error_name_list里是因为bank_error表的行数没有跟着更新,因此在bank_list()处写行数,而不是开头
268 else:
269 error_index = error_name_list.index(input_name)
270 if error_time == bank_error.cell(error_index+2, 3).value:
271 if bank_error.cell(error_index+2, 2).value == 3: # 先判断今日已输入的错误次数,再进行次数计算
272 print('今日输入次数已达上限,请明日再来')
273 break
274 else:
275 bank_error.cell(error_index + 2, 2).value += 1
276 bank_file.save(file_path)
277 if bank_error.cell(error_index + 2, 2).value == 2:
278 print('今日已输入错误2次,还剩1次机会')
279 elif bank_error.cell(error_index + 2, 2).value == 3:
280 print('今日已输入错误3次,无输入机会,请明日再来')
281 else:
282 bank_error.cell(error_index + 2, 1, input_name)
283 bank_error.cell(error_index + 2, 2, 1)
284 bank_error.cell(error_index + 2, 3, error_time)
285 bank_file.save(file_path)
286 print('今日已输入错误1次,还剩2次机会')
287 elif input_name == '' or input_password == '':
288 print('姓名或密码不能为空,请重新输入')
289 elif input_name not in name_list:
290 print('此用户不存在,请重新输入')
291
292
293 def add_user(): # 添加账户
294 while True:
295 while True:
296 bank_list()
297 new_name = input('请输入新账户名:')
298 if new_name in name_list:
299 print('该账户名已存在,请重新输入')
300 elif new_name == '':
301 print('账户名不得为空,请重新输入')
302 elif new_name not in name_list and new_name != '':
303 new_user = {'name': new_name}
304 break
305
306 while True:
307 set_new_password = input('请输入6位数密码:')
308 re_set_new_password = input('请再次确认6位数密码:')
309 if set_new_password == '' or re_set_new_password == '':
310 print('密码不能为空,请重新输入')
311 elif set_new_password == re_set_new_password and set_new_password != '':
312 if set_new_password.isdigit():
313 if len(set_new_password) == 6:
314 print('恭喜您,新用户注册成功')
315 new_user['password'] = set_new_password
316 break
317 else:
318 print('密码长度错误,请重新输入6位有效数字密码!')
319 else:
320 print('密码应为纯数字密码,请输入6位有效数字密码!')
321 elif set_new_password != re_set_new_password:
322 print('两次密码输入不一致,请重新输入')
323
324 # 新用户预存金额
325 select = input('是否需要预存金额,需要请输入“1”后按确认键:')
326 if select == '1':
327 new_balance = int(input('请输入您的预存金额:'))
328 new_user['balance'] = new_balance
329 print(f'预存款成功,存款金额为:{new_balance}元')
330 else:
331 new_user['balance'] = 0
332
333 new_history = list() # 先声明其是空列表,若直接用[]赋值,会警告
334 # 或者直接这种赋值 new_history = [time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 注册账户']
335 new_history.append(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) + ' 注册账户')
336 new_user['history'] = str(new_history)
337 new_user_list = []
338 for key, value in new_user.items():
339 new_user_list.append(value)
340 bank.append(new_user_list)
341 bank_file.save(file_path) # 时效性问题,即刚注册完接着登录时是找不到该用户的,因为登录时读取的bank_file是之前打开的
342 # 因此在name_list()处读取各sheet的行列,此时的数据都是添加保存后的数据,而不是把行列写在开头处
343 input('>>按确定键继续为您服务<<')
344 break
345
346
347 def main_menu(): # 主函数
348 while True:
349 home_page()
350 action_str = input('请输入您的选择1-登录账户,2-注册账户,3-退出系统: ')
351 if action_str == '1':
352 # 登录账户
353 login()
354 elif action_str == '2':
355 # 注册账户
356 add_user()
357 elif action_str == '3':
358 input('>>按确定键退出系统<<')
359 print('欢迎您的下次光临')
360 bank_file.close() # 关闭文件
361 exit()
362 else:
363 print('您的输入有误,请重新输入')
364 input('>>按确定键继续为您服务<<')
365
366
367 if __name__ == '__main__':
368 main_menu()