• 项目开发流程

    1.需求分析:品经理与架构师,根据客户的需求,理出一套比较容易编写的流程
    2.架构设计:架构师根据具体的业务需求选择 具体的开发编程语言与项目框架,所需要的数据库(主库,从库)。与开发目录规范,项目功能划分。项目的报价
    3.分组开发:将项目拆分成多个小项目交给不同开发部门下的多个程序员
    4.提交测试:测试人员对项目进行全方面的测试
    5.交付上线:打包给运维人员进行维护
  • 项目需求分析

    大致功能如下(可拓展):
    1.注册功能:支持多账户注册
    2.登陆功能
    3.查看余额
    4.提现功能:提现需要设置手续费,比例可以由管理员定义
    5.充值功能
    6.转账功能:支持给已注册用户转账
    7.查看流水
    8.添加购物车
    9.查看购物车
    10.结算购物车
    11.管理员功能
  • 项目涉及内容

1.数据类型内置方法
2.函数的基本用法及特点
3.内置模块,自定义模块用法
  • 项目架构设计

    三层架构
    1.用户交互层:也称展示层,主要功能是和用户交互,展示功能
    2.核心逻辑层:也称逻辑层,存放所有逻辑判断功能
    3.数据处理层:数据层,做数据的增删改查并且和系统交互,返回给第二层
  • 项目目录搭建

1.bin
start.py # 存放启动脚本
2.conf
settings.py # 存放配置文件
3.lib
common # 存放公共功能
4.log # 存放项目日志
5.core
src.py # 展示层
6.interface # 核心逻辑层
shop_interface # 购物车接口
bank_interface # 银行接口
user_interface # 用户接口
admin_interface # 管理员接口 db
db_handlerl.py # 数据处理层
readme # 说明
  • 项目功能搭建

    空函数 功能字典 循环匹配
  • 框架搭建(src.py文件代码:)

is_login= {'username':''}  # 全局变量 保存登录信息

# 用户注册
def register():
pass
# 用户登录
def login():
pass # 查看余额
def check_balance():
pass # 余额提现
def Withdraw():
pass # 账户充值
def pay():
pass # 转账
def tranfer():
pass # 查看流水
def check_flow():
pass # 添加购物车
def add_shop_car():
pass # 查看购物车
def check_shop_car():
pass # 结算
def pay_shop_car():
pass # 管理员
def admin():
pass # 功能字典
func_dict = {
'1': register,
'2': login,
'3': look_balance,
'4': Withdraw,
'5': pay,
'6': tranfer,
'7': cheak_water,
'8': add_shop_car,
'9': view_shop_car,
'10': clear_shop_car,
'11': admin } while True:
print("""
1.用户注册
2.登录功能
3.查看余额
4.余额提现
5.账户充值
6.金额转账
7.查看流水
8.添加购物车
9.查看购物车
10.结算购物车
11.管理员功能
""") choice = input('请输入功能编号>>>:').strip()
if choice in func_dict:
func_name = func_dict.get(choice)
func_name()
else:
print('好好输!')
  • 启动文件(start.py文件代码)
import os
import sys base_dir = os.path.dirname(os.path.dirname(__file__)) # 1.找到根目录
sys.path.append(base_dir) # 2.在将根目录添加至环境变量,不受用户和路径限制 if __name__ == '__main__':
from core import src
src.run() # 3.调用run()函数,开始展示功能
  • 配置文件(setting.py文件代码)
import os

#  获取根目录路径,如果不存在则创建
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
DB_DIR = os.path.join(BASE_DIR, 'db')
if not os.path.exists(DB_DIR):
os.mkdir(DB_DIR) MONETY_RATE = 0.05 # 定义手续费费率,因为不常修改所以放在配置文件大写 # 记录日志字典
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' # 其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' LOG_DIR = os.path.join(BASE_DIR, 'log')
if not os.path.isdir(LOG_DIR):
os.mkdir(LOG_DIR)
LOGFILE_PATH = os.path.join(LOG_DIR, 'ATM.log') 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': 'standard',
'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',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '购物车记录': {
# 'handlers': ['default','console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
  • 公共文件(common文件代码)
"""
代码中加密,装饰器,判断数字是否符合要求,日志都是公共功能,因此放在common中
"""
import hashlib
import logging
import logging.config
from core import src
from conf import settings def get_hash(user_pwd):
md5 = hashlib.md5()
md5.update(user_pwd.encode('utf8'))
return md5.hexdigest() def login_auth(func):
def inner(*args, **kwargs):
if src.is_login.get('username'):
res = func(*args, **kwargs)
return res
else:
print('您尚未登陆,请先登陆')
src.login()
return inner def get_num(target_money):
try:
target_money = float(target_money)
except:
return False, '请输入整数或小数'
else:
return True, target_money def get_logger(msg):
logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
return logger1
  • 数据库操作相关代码(db_handler文件代码)
"""
此文件主要用于数据库文件的存取,存取需要多次用到,所以直接封成函数放在数据库操作文件中方便使用
"""
import os
import json
from conf import settings def save(user_dict):
user_name = user_dict.get('username')
user_file_path = os.path.join(settings.DB_DIR, f'{user_name}.json')
with open(user_file_path, 'w', encoding='utf8') as f:
json.dump(user_dict, f, ensure_ascii=False) def select(user_name):
user_file_path = os.path.join(settings.DB_DIR, f'{user_name}.json')
if os.path.exists(user_file_path):
with open(user_file_path, 'r', encoding='utf8') as f:
return json.load(f)
  • 注册功能
"""
注册功能应首先在第一层获取用户输入,简单逻辑判断之后传给第二层,进行逻辑判断,涉及是否已注册功能及存取需要用到db_handler中的函数
"""
src代码:
def register():
user_name = input('请输入您的用户名>>>:').strip() # 1.获取用户输入
user_pwd = input('请输入您的密码>>>:').strip()
confirm_pwd = input('请再次输入您的密码>>>:').strip()
if not user_pwd == confirm_pwd: # 2.将用户两次输入的密码进行对比,如果不一致则退出运行,重新选择任务编号
print('两次密码输入不一致,请再次输入')
return
flag, msg = user_interface.register_interface(user_name, user_pwd) # 3.用两个变量名接收interface层注册函数的返回值
"""
由于本项目部分函数需要返回两个返回值,因此统一用两个变量名来接收函数的返回值,部分函数返回值可能用不上,只是为了统一格式
"""
print(msg) user_interface代码:
def register_interface(user_name, user_pwd): # 1.定义注册接口函数
user_dict = db_handler.select(user_name) # 2.通过db_handler中的select()函数获取函数的返回值
if user_dict: # 3.如果有返回值,说明用户已存在,结束注册功能
return False, f'用户名{user_name}已注册'
user_pwd = common.get_hash(user_pwd) # 4.给传入的密码加密
user_dict = { # 5.构造字典
'username': user_name,
'password': user_pwd,
'balance': 15000,
'shop_car': {},
'is_lock': False,
'water_flow': []
}
db_handler.save(user_dict) # 6.调用db_handler中的save()函数来保存构造的字典
logger.info(f'用户{user_name}注册成功')
return True, f'用户{user_name}注册成功' # 7.返回返回值
  • 登陆功能
src代码:
def login():
user_name = input('请输入您的用户名>>>:').strip() # 1.获取用户输入
user_pwd = input('请输入您的密码>>>:').strip()
flag, msg = user_interface.login_inrterface(user_name, user_pwd)
if flag: # 3.用两个变量名接收interface层注册函数的返回值
is_login['username'] = user_name # 4.记录登录状态
print(msg) interface代码:
def login_inrterface(user_name, user_pwd):
user_dict = db_handler.select(user_name) # 1.通过select()函数来返回用户字典或None
if not user_dict: # 2.逻辑判断:如果没有返回字典,说明用户未注册,将合适的返回值返回给用户
return False, f'用户{user_name}未注册'
user_pwd = common.get_hash(user_pwd) # 3.如果用户已注册,先获取加密后的密码
if user_pwd == user_dict.get('password'): # 4.将用户输入后的密码和存储的密码进行对比(都是加密后的密码)
logger.info(f'用户{user_name}登陆成功')
return True, '登陆成功'
return False, '密码错误' # 5.如果对比不成功返回布尔值和密码错误
  • 查看余额

src代码:
@common.login_auth # 1.通过添加装饰器来限制用户执行该功能前必须先登陆
def check_balance():
user_name = is_login.get('username') # 2.因为用户登录成功时修改了登录状态,所以可以直接通过is_login拿到用户的用户名
flag, msg = bank_interface.check_balance_interface(user_name) # 3.用2个变量名来接收interface()函数的返回值
print(msg) # 4.打印返回的信息 interface代码:
def check_balance_interface(username):
user_dict = db_handler.select(username) # 1.通过传入的用户名从select()函数中通过返回值拿到用户字典
user_balance = user_dict.get('balance') # 2.获取到用户的余额
logger.debug(f'用户{username}查看了自己的账户余额')
return True, f'尊敬的{username},您的账户余额为{user_balance}' # 3.将布尔值True和账户余额返回给src中的msg
  • 提现功能
src代码:
@common.login_auth
def withdraw():
user_name = is_login.get('username') # 1.通过is_login拿到用户的用户名
target_money = input('请输入您想要提现的金额>>>:').strip() # 2.获取用户提现金额
flag, msg = bank_interface.withdraw_interface(user_name, target_money) # 3.用2个变量名来接收interface()函数的返回值
print(msg) interface代码:
def withdraw_interface(username, target_money):
flag, value = common.get_num(target_money) # 1.通过common中的get_num()函数来判断数字是否符合要求
if not flag: # 2.如果不符合将返回值返回给第一层,重新输入
return False, '请输入符合要求的金额'
user_dict = db_handler.select(username) # 3.通过select()获取用户字典,因为此时是从is_login获取到的用户名,所以字典肯定存在,无需判断
user_balance = user_dict.get('balance') # 4.获取用户余额
if user_balance >= value * (1 + settings.MONETY_RATE): # 5.判断用户余额是否大于提现金额加手续费,因为手续费不常修改,所以放在settings中大写
user_dict['balance'] -= value * (1 + settings.MONETY_RATE) # 6.修改用户字典中的余额,考虑手续费
ctime = time.strftime('%Y-%m-%d %H:%M:%S') # 7.记录时间,用于记录流水
user_dict['water_flow'].append(
f'{username}于{ctime}提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}')
db_handler.save(user_dict) # 8.添加流水
logger.debug(f'用户{username}提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}')
return True, f'尊敬的{username}成功提现{value},手续费{value * settings.MONETY_RATE},账户余额{user_dict.get("balance")}'
return False, f'尊敬的{username}, 您的账户余额不足,无法提现' # 9.通过逻辑判断返回不同的返回值
  • 充值功能
src代码:
@common.login_auth
def pay_back():
user_name = is_login.get('username')
target_money = input('请输入您想充值的金额>>>:').strip()
flag, msg = bank_interface.pay_back_interface(user_name, target_money)
print(msg) interface代码:
def pay_back_interface(user_name, target_money):
flag, value = common.get_num(target_money)
if not flag:
return False, '请输入符合要求的金额数字'
user_dict = db_handler.select(user_name)
user_dict['balance'] += value
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
user_dict['water_flow'].append(f'{user_name}于{ctime}充值{value},账户余额{user_dict.get("balance")}')
db_handler.save(user_dict)
logger.debug(f'用户{user_name}充值{value},账户余额{user_dict.get("balance")}')
return True, f'尊敬的{user_name},您于{ctime}成功充值{value},账户余额{user_dict.get("balance")}'
  • 转账功能
src代码:
@common.login_auth
def transfer():
user_name = is_login.get('username')
target_name = input('请输入您想转账的用户名>>>:').strip()
target_money = input('请输入您想转账的金额>>>:').strip()
flag, msg = bank_interface.transfer_interface(user_name, target_name, target_money)
print(msg) interface代码:
def transfer_interface(user_name, target_name, target_money):
target_dict = db_handler.select(target_name)
if not target_dict:
return False, f'用户{target_name}未注册'
flag, value = common.get_num(target_money)
if not flag:
return False, '请输入符合要求的数字'
user_dict = db_handler.select(user_name)
if user_dict.get('balance') >= value:
user_dict['balance'] -= value
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
user_dict['water_flow'].append(
f'尊敬的{user_name},您于{ctime}给{target_name}转账{value},账户余额{user_dict.get("balance")}')
target_dict['balance'] += value
target_dict['water_flow'].append(
f'尊敬的{target_name},{user_name}于{ctime}给您转账{value},账户余额{target_dict.get("balance")}')
db_handler.save(user_dict)
db_handler.save(target_dict)
logger.debug(
f'用户{user_name}给{target_name}转账{value},{user_name}账户余额{user_dict.get("balance")},{target_name}账户余额{target_dict.get("balance")}')
return True, f'尊敬的{user_name}, 您于{ctime}给{target_name}转账{value},账户余额{user_dict.get("balance")}'
return False, f'您的账户余额不足,无法转账'
  • 查看流水
src代码:
@common.login_auth
def check_flow():
user_name = is_login.get('username')
flag, msg = bank_interface.check_flow_interface(user_name)
if flag:
for data in msg:
print(data)
else:
print(msg) interface代码:
def check_flow_interface(username):
user_dict = db_handler.select(username)
if user_dict.get('water_flow'):
logger.debug(f'用户{username}查看了流水')
return True, user_dict.get('water_flow')
else:
logger.debug(f'用户{username}查看了流水')
return False, '您暂无流水'
  • 添加购物车
"""
添加购物车主要功能可以写在第二层,第一层主药方用户交互功能
"""
src代码:
@common.login_auth
def add_shop_car():
user_name = is_login.get('username')
flag, msg = shop_interface.add_shop_car_interface(user_name)
print(msg) interface代码:
def add_shop_car_interface(user_name):
tem_list = {}
while True:
good_list = [
['挂壁面', 3],
['印度飞饼', 22],
['极品木瓜', 666],
['土耳其土豆', 999],
['伊拉克拌面', 1000],
['董卓戏张飞公仔', 2000],
['仿真玩偶', 10000]
]
for i, j in enumerate(good_list, start=1):
print(f"""
商品编号:{i} | 商品名称:{j[0]} | 商品单价:{j[1]}
""")
choice = input('请输入您的商品编号(q)>>>:').strip()
if choice == 'q':
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car')
for i in tem_list:
if i in shop_car:
shop_car.get(i)[0] += tem_list.get(i)[0]
else:
shop_car[i] = tem_list.get(i)
user_dict['shop_car'] = shop_car
db_handler.save(user_dict)
logger.info(f'用户{user_name}添加了购物车')
return True, f'用户{user_name}购物车添加完毕' if not choice.isdigit():
print('商品编号必须是纯数字')
continue
choice = int(choice)
if not choice in range(1, len(good_list) + 1):
print('没有该商品')
continue
num = input(f'请输入您购买{good_list[choice - 1][0]}的数量>>>:')
if not num.isdigit():
print('商品数量必须是纯数字')
continue
num = int(num)
target_list = good_list[choice - 1]
target_good = target_list[0]
if target_good in tem_list:
tem_list.get(target_good)[0] += num
else:
tem_list[target_good] = [num, target_list[1]]
  • 查看购物车功能
src.py代码:
@common.login_auth
def check_shop_car():
user_name = is_login.get('username')
flag, msg = shop_interface.check_shop_car_interface(user_name)
if flag:
for i in msg:
print(f"""
商品名称:{i} | 商品数量:{msg.get(i)[0]} | 商品单价:{msg.get(i)[1]}
""")
else:
print(msg) interface代码:
def check_shop_car_interface(user_name):
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car')
if shop_car:
logger.info(f'用户{user_name}查看了购物车')
return True, shop_car
else:
logger.info(f'用户{user_name}查看了购物车')
return False, '您的购物车为空'
  • 结算购物车功能
src代码:
@common.login_auth
def pay_shop_car():
user_name = is_login.get('username')
flag, msg = shop_interface.pay_shop_car_interface(user_name)
print(msg) interface代码:
def pay_shop_car_interface(user_name):
user_dict = db_handler.select(user_name)
shop_car = user_dict.get('shop_car') # {'极品木瓜': [9, 666], '伊拉克拌面': [5, 1000]}
current_balance = user_dict.get('balance')
money = 0
for i in shop_car.values(): # i:[9, 666]
money += i[0] * i[1]
if money > current_balance:
return False, f'您的账户余额不足,无法结算'
current_balance -= money
shop_car = {}
user_dict['balance'] = current_balance
user_dict['shop_car'] = {}
user_dict['water_flow'].append(f'{user_name},您本次消费{money},账户余额{user_dict.get("balance")}')
db_handler.save(user_dict)
logger.info(f'用户{user_name}结算了购物车,本次消费{money},账户余额{user_dict.get("balance")}')
return True, f'尊敬的{user_name},您本次消费{money},账户余额{user_dict.get("balance")}'

ATM购物车大作业的更多相关文章

  1. java大作业博客--购物车

    Java 大作业----使用MySQL的购物车 一.团队介绍 姓名 任务 李天明.康友煌 GUI设计及代码编写 谢晓淞 业务代码编写.MySQL服务器平台部署.git代码库 严威 类和包的结构关系设计 ...

  2. day19 十九、ATM+购物车

    项目:ATM+购物车 作业需求:模拟实现一个ATM + 购物商城程序1.额度 15000或自定义 2.实现购物商城,买东西加入 购物车,调用信用卡接口结账 3.可以提现,手续费5% 4.每月22号出账 ...

  3. 数据库大作业--由python+flask

    这个是项目一来是数据库大作业,另一方面也算是再对falsk和python熟悉下,好久不用会忘很快. 界面相比上一个项目好看很多,不过因为时间紧加上只有我一个人写,所以有很多地方逻辑写的比较繁琐,如果是 ...

  4. 程设大作业xjb写——魔方复原

    鸽了那么久总算期中过[爆]去[炸]了...该是时候写写大作业了 [总不能丢给他们不会写的来做吧 一.三阶魔方的几个基本定义 ↑就像这样,可以定义面的称呼:上U下D左L右R前F后B UD之间的叫E,LR ...

  5. 大作业NABC分析结果

    大作业NABC分析结果 这次的大作业计划制作一款关于七巧板的游戏软件.关于编写的APP的NABC需求分析: N:需求 ,本款软件主要面向一些在校的大学生,他们在校空闲时间比较多,而且热衷于一些益智类游 ...

  6. [留念贴] C#开发技术期末大作业——星月之痕

    明天就要去上海大学参加 2015赛季 ACM/ICPC最后一场比赛 —— EC-Final,在这之前,顺利地把期末大作业赶出来了. 在这种期末大作业10个人里面有9个是从网上下载的国内计算机水平五六流 ...

  7. Hadoop综合大作业

    Hadoop综合大作业 要求: 用Hive对爬虫大作业产生的文本文件(或者英文词频统计下载的英文长篇小说)词频统计. 用Hive对爬虫大作业产生的csv文件进行数据分析 1. 用Hive对爬虫大作业产 ...

  8. 爬虫综合大作业——网易云音乐爬虫 & 数据可视化分析

    作业要求来自于https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 爬虫综合大作业 选择一个热点或者你感兴趣的主题. 选择爬取的对象 ...

  9. 期末Java Web大作业----简易的学生管理系统

    学生信息管理系统(大作业) 2018-12-21:此文章已在我的网站更新,添加视图介绍等信息,源码请移步下载https://www.jeson.xin/javaweb-sims.html PS:首先不 ...

  10. CSAPP HITICS 大作业 hello's P2P by zsz

    摘 要 摘要是论文内容的高度概括,应具有独立性和自含性,即不阅读论文的全文,就能获得必要的信息.摘要应包括本论文的目的.主要内容.方法.成果及其理论与实际意义.摘要中不宜使用公式.结构式.图表和非公知 ...

随机推荐

  1. 【Zulip】邮件系统配置

    通过docker-compose(docker-zulip)部署Zulip实例时需要配置邮件系统 SETTING_ZULIP_ADMINISTRATOR: '...@qq.com' SETTING_E ...

  2. 直播CDN调度技术关键挑战与架构设计

    作者:胡济麟 1.背景介绍 1.1 直播业务特点 互联网视频直播是一种消息媒介形态,提供时产时消的内容,经过多年,已经发展出秀场.游戏.电商.体育等多种业务形态.主要特点是:内容实时产生实时消费,对时 ...

  3. mindxdl--common--web_cert_utils.go

    // Copyright (c) 2021. Huawei Technologies Co., Ltd. All rights reserved.// Package common this file ...

  4. 【Devexpres】spreadsheetControl自动列宽

    Worksheet worksheet = this.spreadsheetControl1.ActiveWorksheet; worksheet.Import(datatable, true, 0, ...

  5. 【每日一题】【双端降序队列Deque】2021年12月28日-239. 滑动窗口最大值

    给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 来源:力扣(L ...

  6. python重要内置模块

    目录 包的概念 包的具体使用 编程思想的转变 常用内置模块之collections模块 (收集) 常用内置模块之time模块 (时间) 常用内置模块之random模块 (随机) os模块 sys模块 ...

  7. 一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中自定义控件制作和调用、TCP协议下文件的收发 、以及可执行文件的打包

    一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中ui的使用和TCP协议下文件的收发.以及可执行文件的打包 写在前面,Qt Designer是一个非常操蛋的页面编辑器,它非常的...怎么说呢 ...

  8. http转成https工具类

    工具类代码如下: 点击查看代码 package com.astronaut.auction.modules.oss.utils; import org.apache.commons.collectio ...

  9. USB转TTL串口 (CH340 G)

    为什么USB要转TTL串口[1]? 单片机串口基本采用TTL电平. 家用电脑很少有串口,但是有USB接口 USB的电平与TTL电平不兼容. 所以需要将USB电平转化为TTL电平. USB是什么? 接口 ...

  10. vue3项目,记录我是如何用1h实现产品预估1天工作量的界面需求

    最近在编写前端界面,硬是一人一周时间加班加点写完了一个项目的前端界面(一级菜单有12个页面+一个控制台大屏,二三级界面有N个),之前预估前端界面的编写需要一个月,我是自己把自己卷死了(没有办法,项目经 ...