目录
一、项目视图分析
通过上图,我们可以看到,一个完整的项目,基本包括三个部分:用户视图层、接口层、数据处理层,其中,用户视图层是用来接收用户的数据输入的,比如:有户名,密码;接口层是要接收用户视图层传来的数据,然后做判断:名字是否存在、密码是否正确,这就要求接口层调用数据处理层的方法;数据处理层就需要接收接口层的参数,把接口层需要的增、删、改、查的数据结果返回给接口层,接口层再把判断的结果返回给用户层。
二、文件结构分析
文件主要有以下几个部分:conf(setting.py-参数配置,比如:日志文件的配置、路径等)、core(src.py\\admin.py-用户视图层,分为图通用户和管理员)、interface(接口层,里面有很多接口:用户接口,购物接口,银行接口,管理员接口,分这么细是为了“解耦合”)、db(用户数据存放;数据处理层:主要负责数据的增、删、改、查)、lib(公共方法:比如登录功能的装饰器)、log(日志文件)、readme(文档说明)、strat启动
三、完整代码
1.start.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:59 @Author : Rice @CSDN : C_小米同学 @FileName: start.py \'\'\' \'\'\' 程序的入口 \'\'\' import sys import os #添加解释器的环境变量 sys.path.append( os.path.dirname(__file__) ) #导入用户视图层 from core import src # 开始执行项目函数 if __name__ == \'__main__\': # 1.先执行用户视图层 src.run()
2.conf
-settings.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:49 @Author : Rice @CSDN : C_小米同学 @FileName: settings.py \'\'\' \'\'\' 存放配置信息 \'\'\' import os #获取项目根目录路劲 BASE_PATH = os.path.dirname( os.path.dirname(__file__) ) # 获取user_data文件夹目录路径 USER_DATA_PATH = os.path.abspath(os.path.join(BASE_PATH, \'db\',\'user_data\')) #USER_DATA_PATH2 = os.path.join(BASE_PATH, \'db\',\'user_data\').replace(\'\\\\\',\'/\') username = \'rice\' user_path = os.path.abspath(os.path.join(USER_DATA_PATH, f\'{username}.json\')).replace(\'\\\\\',\'/\') \"\"\" logging配置 \"\"\" BASE_PATH2 = os.path.dirname(os.path.dirname(__file__)) logfile_dir = os.path.abspath(os.path.join(BASE_PATH2,\'log\')).replace(\'\\\\\',\'/\') logfile_name = \'atm.log\' #如果不存在定义的日志目录就创建一个 if not os.path.isdir(logfile_dir): os.mkdir(logfile_dir) #log文件的全路径 logfile_path = os.path.join(logfile_dir, logfile_name).replace(\'\\\\\',\'/\') standard_format = \'[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]\' \\ \'[%(levelname)s][%(message)s]\' simple_format = \'[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s\' test_format = \'%(asctime)s] %(message)s\' # 3、日志配置字典 LOGGING_DIC = { \'version\': 1, \'disable_existing_loggers\': False, \'formatters\': { \'standard\': { \'format\': standard_format }, \'simple\': { \'format\': simple_format }, }, \'filters\': {}, \'handlers\': { # 打印到终端的日志 \'console\': { \'level\': \'DEBUG\', \'class\': \'logging.StreamHandler\', # 打印到屏幕 \'formatter\': \'simple\' }, # 打印到文件的日志,收集info及以上的日志 \'default\': { \'level\': \'DEBUG\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,日志轮转 \'formatter\': \'simple\', # 可以定制日志文件路径 # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # log文件的目录 # LOG_PATH = os.path.join(BASE_DIR,\'a1.log\') \'filename\': logfile_path, # 日志文件 \'maxBytes\': 1024 * 1024 * 5, # 日志大小 5M \'backupCount\': 5, \'encoding\': \'utf-8\', # 日志文件的编码,再也不用担心中文log乱码了 }, }, \'loggers\': { # logging.getLogger(__name__)拿到的logger配置 \'\': { \'handlers\': [\'default\', \'console\'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 \'level\': \'DEBUG\', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制) \'propagate\': True, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递 }, }, } if __name__ == \'__main__\': print(user_path)
3.core
-src.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:51 @Author : Rice @CSDN : C_小米同学 @FileName: src.py \'\'\' \'\'\' 用户视图层 \'\'\' from interface import user_interface from lib import common from interface import bank_interface from interface import shop_interface #全局变量,记录用户是否已登录 login_user = None # 1.注册功能 def register(): while True: # 1)让用户输入用户名和密码校验 username = input(\'请输入用户名:\').strip() password = input(\'请输入密码:\').strip() re_password = input(\'请确认密码:\').strip() #可以输入自定义的金额 # 小的逻辑错误:比如两次密码是否一致 if password == re_password: #2)调用接口层的注册接口,将用户名与密码交给接口层来进行处理 #一个元祖 flag, msg = user_interface.register_interface(username, password) # 3)根据flag判断用户注册是否成功,用于控制break if flag: print(msg) break else: print(msg) # 2.登录功能 #成功登录了之后,一定会修改全局变量:login_user def login(): #登录视图 while True: #1)让用户输入用户名和密码 username = input(\'请输入用户名:\').strip() password = input(\'请输入密码:\').strip() #2)调用接口层,将数据传给登录接口 flag, msg = user_interface.login_interface(username, password) if flag: print(msg) global login_user login_user = username break else: print(msg) #有一个小bug,输入错误后,我想返回主页 #d #成功登录了# # 3.查看余额 @common.login_auth def check_balance(): #1.直接调用查看余额接口,获取用户余额 #装饰器本身是有login_user balance = user_interface.check_bal_interface(login_user) print(f\'用户{login_user} 账户余额为:{balance}\') # 4.提现功能 @common.login_auth def withdraw(): while True: #1)让用户输入提现金额 input_money = input(\'请输入提现金额:\').strip() #2)判断用户输入的金额是否是数字 if not input_money.isdigit(): #isdigit()-可以判断字符串 print(\'请输入\') continue #3)用户提现金额,将数据提现的金额交给接口层处理 flag, msg = bank_interface.withdraw_interface(login_user, input_money) if flag: print(msg) break # 5.还款功能 @common.login_auth def repay(): \'\'\' 银行卡还款,无论是信用卡或储蓄卡,是否能任意大小的金额 :return: \'\'\' while True: #1) 让用户输入还款金额 input_money = input(\'请输入需要还款的金额:\').strip() #2)判断用户输入的是否是数字 if not input_money.isdigit(): print(\'请输入正确的金额\') continue input_money = int(input_money) #3)判断用户输入的金额大于0 if input_money > 0: #4)调用还款接口 flag, msg = bank_interface.repay_interface(login_user, input_money) if flag: print(msg) break else: print(\'输入的金额不能小于0\') # 6.转账功能 @common.login_auth def transfer(): \'\'\' 1.接收 用户输入的 转账金额 2.接收用户输入的 转账目标用户 :return: \'\'\' while True: #1) 让用户输入转账用户与金额 to_user = input(\'请输入转账目标用户\').strip() money = input(\'请输入转账金额\').strip() #2)数据判断 if not money.isdigit(): print(\'请输入数字\') continue money = int(money) if money > 0: #调用转账接口 flag, msg = bank_interface.transfer_interface( login_user,to_user,money ) if flag: print(msg) break else: print(msg) else: print(\'请输入正确的金额\') # 7.查看流水 @common.login_auth def check_flow(): #直接调用查看流水接口 flow_list = bank_interface.check_flow_interface(login_user) if flow_list: for flow in flow_list: print(flow) else: print(\'当前用户没有流水!\') # 8.购物功能 @common.login_auth def shop(): #不从文件中读取商品数据,直接写 #创建商品列表 # shop_list = { # \'0\': {\'name\': \'包子\', \'price\': 30} # } shop_list = [ [\'包子\', 3], #0 [\'可乐\', 5], #1 [\'book\', 200], [\'pc\', 9999], ] #初始化当前购物车 shopping_car = {} #{\'商品名称\':[\'单价\',\'数量\']]} while True: #枚举:enumerate(可迭代对象)--->元祖(可迭代对象的索引,索引对应的值) for index, shop in enumerate(shop_list): shop_name, shop_price = shop print(f\'商品编号为{index}, 商品名称{shop_name}, 商品单价:{shop_price}\') print(shop) choice = input(\'请输入商品编号:(是否结账输入y or n)\').strip() #让用户根据商品编号进行选择 #输入的是y进行支付结算功能 if choice == \'y\': if not shopping_car: print(\'购物车是空的,不能支付,请重新输入\') continue #调用支付接口进行支付 flag, msg = shop_interface.shopping_interface(login_user,shopping_car) if flag: print(msg) break else: print(msg) #输入的是n添加购物车(把shopping_car添加到json中) elif choice == \'n\': #调用添加购物车接口 if not shopping_car: print(\'购物车是空的,不能添加,请重新输入\') continue flag, msg = shop_interface.add_shop_car_interface(login_user, shopping_car) if flag: print(msg) break else: print(msg) if not choice.isdigit(): print(\'请输入正确的编号!\') continue if not choice.isdigit(): print(\'请输入正确的编号!\') continue choice = int(choice) if choice not in range(len(shop_list)): print(\'请输入正确的编号!\') continue shop_name, shop_price = shop_list[choice] #加入购物车 #判断用户选择的商品是否重复,重复加1 if shop_name in shopping_car: #添加商品数量 shopping_car[shop_name][1] += 1 else: #否则数量默认为1 shopping_car[shop_name] = [shop_price, 1] # 9.查看购物车 @common.login_auth def check_shop_car(): shop_car = shop_interface.check_shop_car_interface(login_user) print(shop_car) # 10.管理员功能 @common.login_auth def admin(): \'\'\' 管理员功能:课后作业 :return: \'\'\' from core import admin admin.admin_run() # 创建函数功能字典 func_dic = { \'1\': register, \'2\': login, \'3\': check_balance, \'4\': withdraw, \'5\': repay, \'6\': transfer, \'7\': check_flow, \'8\': shop, \'9\': check_shop_car, \'10\': admin } # 视图层主程序 def run(): while True: print(\'\'\' ======= ATM + 购物车 ======= 1.注册功能 2.登录功能 3.查看余额 4.提现功能 5.还款功能 6.转账功能 7.查看流水 8.购物功能 9.查看购物车 10.管理员功能 ========== end ============ \'\'\') choice = input(\'请输入功能编号:\').strip() if choice not in func_dic: print(\'请输入正确的功能编号!\') continue func_dic.get(choice)()
-admin.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/04 11:50 @Author : Rice @CSDN : C_小米同学 @FileName: admin.py \'\'\' from core import src from interface import admin_interface # 添加用户 def add_user(): src.register() # 修改用户额度 def change_balance(): while True: change_user = input(\'请输入需要修改额度的用户\').strip() money = input(\'请输入需要修改的用户额度:\').strip() if not money.isdigit(): print(\'请输入数字\') continue flag, msg = admin_interface.change_balance_interface(change_user, money) if flag: print(msg) break else: print(msg) break # 输入修改额度 # 输入修改用户 # 调用修改额度接口 # 冻结账户 def lock_user(): while True: change_user = input(\'请输入需要修改额度的用户:\').strip() flag, msg = admin_interface.lock_user_interface(change_user) if flag: print(msg) break else: print(msg) break # 管理员功能字典 admin_dic = { \'1\': add_user, \'2\': change_balance, \'3\': lock_user } def admin_run(): while True: print(\'\'\' 1、添加用户 2、修改额度 3、冻结账户 \'\'\') choice = input(\'请输入管理员功能编号:\').strip() # 判断功能编号是否存在 if choice not in admin_dic: print(\'请输入正确的功能编号!\') continue # 调用用于选择的功能函数 admin_dic.get(choice)()
4.interface
-user_interface.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:52 @Author : Rice @CSDN : C_小米同学 @FileName: user_interface.py \'\'\' \'\'\' 逻辑接口层 用户接口 \'\'\' import json import os from conf import settings from db import db_handler from lib import common user_logger = common.get_logger(\'user\') #user_logger.setLevel(10) #注册接口 def register_interface(username, password, balance=5000): # 2)查看用户是否存在 #2.1)调用 数据处理层中的select函数,会返回用户字典或None user_dic = db_handler.select(username) #若用户存在,则return,告诉用户重新输入(是通过用户名来判断是否存在的,跟密码没关系) if user_dic: return False, \'用户名已存在!\' #3)用户不存在,则保存用户数据 #做密码加密 password = common.get_pwd_md5(password) user_dic = { \'username\': username, \'password\': password, \'balance\': balance, # 用于记录用户流水的列表 \'flow\': [], # 用于记录用户购物车 \'shop_car\': {}, # locked: 用于记录用户是否被冻结 # False:未冻结 True:已冻结 \'locked\': False } #3.2)保存数据 db_handler.save(user_dic) msg = f\'{username} 用户注册成功\' #记录日志 user_logger.info(msg) return True, msg #登录接口 def login_interface(username, password): #1)先查看当前用户数据是否存在 user_dic = db_handler.select(username) #2)判断用户是否存在 #若有冻结用户,则需要判断是否被锁定 if user_dic: if user_dic.get(\'locked\'): return False, \'当前用户已被锁定\' #给用户输入的密码做一次加密 password = common.get_pwd_md5(password) #3)校验密码是否一致 if password == user_dic.get(\'password\'): msg = f\'用户{username}登录成功!\' user_logger.info(msg) return True, msg else: msg = f\'用户{username}密码错误!\' user_logger.warn(msg) return False, msg msg = f\'用户{username}不存在!\' user_logger.warn(msg) return False, msg #查看余额接口 def check_bal_interface(username): user_dic = db_handler.select(username) return user_dic[\'balance\']
-shop_interface.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:53 @Author : Rice @CSDN : C_小米同学 @FileName: shop_interface.py \'\'\' \'\'\' 商城购物接口层 \'\'\' from db import db_handler #商品准备结算接口 def shopping_interface(login_user, shopping_car): #计算消费金额 cost = 0 for price_number in shopping_car.values(): price, number = price_number cost += (price*number) #导入银行接口 from interface import bank_interface #逻辑校验成功后,在调用银行支付接口 flag = bank_interface.pay_interface(login_user,cost) if flag: return True, \'支付成功,准备发货\' return False, \'支付失败,金额不足\' #购物车添加接口 def add_shop_car_interface(login_user, shopping_car): #获取当前用户的购物车 user_dic = db_handler.select(login_user) shop_car = user_dic.get(\'shop_car\') #添加购物车 for shop_name, price_number in shopping_car.items(): #每个商品的数量 number = price_number[1] if shop_name in shop_car: user_dic[\'shop_car\'][shop_name] += number db_handler.save(user_dic) print(\'添加到json成功\') else: user_dic[\'shop_car\'].update({shop_name: price_number}) db_handler.save(user_dic) print(\'添加到json成功\') return True, \'添加购物车成功\' #查看购物车接口 def check_shop_car_interface(username): user_dic = db_handler.select(username) return user_dic.get(\'shop_car\')
-bank_interface.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:53 @Author : Rice @CSDN : C_小米同学 @FileName: bank_interface.py \'\'\' \'\'\' 银行先关业务的接口 \'\'\' from db import db_handler #提现接口(手续费5%) def withdraw_interface(username, money): #1)先获取用户字典 user_dic = db_handler.select(username) #校验用户的钱是否足够 balance = int(user_dic.get(\'balance\')) #本金+手续费 momey2 = int(money) * 1.05 #money是str,用int类型转换 #判断用户金额是否足够 if balance >= momey2: #2)修改用户字典中的金额 balance -= momey2 user_dic[\'balance\'] = balance #记录流水 flow = f\'用户{username} 提现金额{money}成功,手续费是:{momey2 - float(money)}$ 剩余{balance}\' user_dic[\'flow\'].append(flow) #3)再保存数据,或更新数据 db_handler.save(user_dic) # money是str,用int类型转换 return True, flow def repay_interface(username, money): \'\'\' 1.获取用户的金额 2.给用户加钱操作 :param username: :param money: :return: \'\'\' #1.获取用户字典 user_dic = db_handler.select(username) #2.直接做加钱的操作 user_dic[\'balance\'] += money #记录流水 flow = f\'用户{username} 还款{money}成功! 当前额度为{user_dic[\"balance\"]}\' user_dic[\'flow\'].append(flow) #3.调用数据处理层,将修改后的数据进行更新 db_handler.save(user_dic) return True, flow def transfer_interface(login_user, to_user, money): \'\'\' 1.获取\'当前用户\' 数据 2.获取\'目标用户\' 数据 3.获取转账金额 :return: \'\'\' login_user_dic = db_handler.select(login_user) to_user_dic = db_handler.select(to_user) if not to_user_dic: return False, \'目标用户不存在\' #4)若用户存在,则判断\'当前用户的转账金额\' 是足够的 if login_user_dic[\'balance\'] >= money: login_user_dic[\'balance\'] -= money to_user_dic[\'balance\'] += money #当前用户流水 login_user_flow = f\'用户{login_user} 给用户 {to_user} 转账 {money}$ 成功\' login_user_dic[\'balance\'].append(login_user_flow) #目标用户流水 to_user_flow = f\'用户{to_user} 给用户 {login_user} 转账 {money}$ 成功\' to_user_dic[\'flow\'].append(to_user_flow) #调用数据处理层,保存数据 db_handler.save(login_user_dic) db_handler.save(to_user_dic) return True, login_user_flow return False, \'当前用户转账金额不足\' def check_flow_interface(login_user): user_dic = db_handler.select(login_user) return user_dic.get(\'flow\') #支付接口 def pay_interface(login_user, cost): user_dic = db_handler.select(login_user) #判断用户金额 if user_dic.get(\'balance\') >= cost: user_dic[\'balance\'] -= cost flow = f\'用户消费金额:{cost}$\' user_dic[\'flow\'].append(flow) #保存数据 db_handler.save(user_dic) return True return False
-admin_interface.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/04 12:39 @Author : Rice @CSDN : C_小米同学 @FileName: admin_interface.py \'\'\' from db import db_handler from lib import common admin_logger = common.get_logger(\'admin\') #修改额度接口 def change_balance_interface(username, money): user_dic = db_handler.select(username) if user_dic: #修改额度 user_dic[\'balance\'] = int(money) db_handler.save(user_dic) msg = f\'管理员修改用户:{username}额度修改成功\' admin_logger.info(msg) return True, \'额度修改成功!\' return False, \'修改额度用户不存在\' #冻结账户接口 def lock_user_interface(username): user_dic = db_handler.select(username) if user_dic: user_dic[\'locked\'] = True db_handler.save(user_dic) return True, f\'用户{username}冻结成功\' return False, \'冻结用户不存在\'
5.db
-db_handler.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:57 @Author : Rice @CSDN : C_小米同学 @FileName: db_handler.py \'\'\' \'\'\' 数据处理层 -专门用户处理数据 \'\'\' import json import os from conf import settings #查看数据 def select(username): #1)接收接口层传过来的username用户名,拼接用户json文件路劲 user_path = os.path.abspath(os.path.join(settings.USER_DATA_PATH, f\'{username}.json\')).replace(\'\\\\\', \'/\') #2)校验用户json文件是否存在 if os.path.exists(user_path): #3)打开数据,并返回给接口层 with open(user_path, \'r\', encoding=\'utf-8\') as f: user_dic = json.load(f) # 导出数据 return user_dic #3)不return,默认返回return None #保存数据 def save(user_dic): #1)拼接用户的数据字典 username = user_dic.get(\'username\') user_path = os.path.abspath(os.path.join(settings.USER_DATA_PATH, f\'{username}.json\')).replace(\'\\\\\', \'/\') #2)保存用户数据 with open(user_path, \'w\', encoding=\'utf-8\') as f: # 导入数据(ensure_ascii=False,让文件中的中文数据显示更美观) json.dump(user_dic, f, ensure_ascii=False)
6.lib
-common.py
# -*- coding: utf-8 -*- \'\'\' @Time : 2022/09/02 14:50 @Author : Rice @CSDN : C_小米同学 @FileName: common.py \'\'\' \'\'\' 存放公共方法 \'\'\' import hashlib import logging.config from conf import settings def get_pwd_md5(password): md5_obj = hashlib.md5() md5_obj.update(password.encode(\'utf-8\')) #传入的数据需要时\"字节串\" salt = \'rice这是一个ATM\' md5_obj.update(salt.encode(\'utf-8\')) return md5_obj.hexdigest() #登录认证装饰器 def login_auth(func): from core import src def inner(*args, **kwargs): if src.login_user: res = func(* args, ** kwargs) return res else: print(\'使用功能前,请先登录\') src.login() return inner #添加日子功能:(日志功能在接口层使用) #获取日志功能 #获取日志对象 def get_logger(log_type): \'\'\' :param log_type: 比如是user日子,bank日子,购物商城日志 :return: \'\'\' #1、加载日志配置信息 logging.config.dictConfig(settings.LOGGING_DIC) #2、获取日志对象 logger = logging.getLogger(log_type) return logger
7.readme
# 项目说明书 ## 项目:ATM + 购物车 # 项目需求 模拟实现一个ATM + 购物商城程序 1.额度 15000或自定义 ->注册功能 2.实现购物商城,买东西加入 购物车,调用信用卡接口结账-》购物、支付 3.可以提现,手续费5%-》提现功能 4.支持多账户登录-》登录功能 5.支持账户间转账 -》转账功能 6.记录日常消费流水-》记录流水功能 7.提供还款接口 -》还款功能 8.ATM记录操作日志 —》记录日志功能 9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。-》管理员功能 10.用户认证用装饰器-》登录认证装饰器 ## \"用户视图层\"展示给用户选择的功能 1.注册功能 2.登录功能 3.查看余额 4.提现功能 5.还款功能 6.转账功能 7.查看流水 8.购物功能 9.查看购物车 10.管理员功能 # 一个项目如何从无到有 ## 一 需求分析 1.拿到项目,想在客户那里讨论需求 商量项目的功能能否实现,周期,价格,得到需求文档 2.最后在公司内部需要开一次会议,得到最终的开发文档, 交给不同的岗位的程序员进行开发 -Python:后端,爬虫 -不同的岗位: -UI界面设计: -设计软件的布局,会根据软件的外观切成一张张图片 -前端: -拿到UI交给他的图片,去搭建网页页面 -设计一些页面中,哪些位置需要接收数据,需要进行数据交互 -后端: -直接核心的业务逻辑,调度数据库进行数据的增删 -测试: -会给代码进行全面测试,比如压力测试,界面测试 -运维 -部署项目 ## 二 程序的架构设计 ### 1、程序设计的好处 1)思路不清晰 2)不会出现写一半推翻重写 3)方便自己或以后的同时更好维护 ### 2、 三层架构设计的好处 1)每个功能都分成三部分 2)如果用户更换不同的用户界面或不同的数据储存机制,这样 都不会影响接口层的核心逻辑代码。拓展性强 3)可以在接口层,准确的记录接口和流水 ### 3、三层架构 #### 一 用户视图层 用于与用户交互的,可以接受用户输入,打印接口返回的数据 #### 二 逻辑接口层 接受 用户视图层 传递过来的参数,根据逻辑判断调用数据层加以处理, 并返回一个结果给用户视图层 #### 三 数据处理层 接受接口层传递过来的参数,做数据的 - 保存 save() - 查看数据 select() - 更新数据 - 删除数据 ## 三 分任务开发 ## 四 测试 ## 五 上线 # 统计代码
以上就是Python实战之ATM取款机的实现的详细内容,更多关于Python ATM取款机的资料请关注其它相关文章!
© 版权声明
THE END
暂无评论内容