电子商城后台管理系统
电子商城后台管理平台-Flask 项目开发
文章目录
前言
- 项目需求
百战电子商城后台管理平台包含账号管理、商品管理、订单管理、数据统计等业务功能
- 项目技术
百战电子商城后台管理平台采用前后端分离的开发模式
所谓的前后端分离,就是使用vue写前端页面,flask写后端数据
技术栈
前端的技术
Vue 前端框架
Element-UI UI 框架
Axios 发送请求
Echarts 绘制图表后端的技术
Python 主流语言
Flask Web 框架
MySQL 存储主要数据
Redis 存储缓存数据思路
项目需要什么功能,模块,静态文件。需要多少文件夹。
配置 Flask 项目结构
app 项目目录
app/init.py 模块初始化
app/model 模型类
app/blue_print 蓝图
app/static 静态文件夹
app/utils 工具文件夹
log 日志目录
manager.py 管理项目
config.py 配置项目文件相关的库:SQLAlchemy,Flask,flask_migrate(数据库同步),flask_script(自定义命令,命令管理),werkzeug.security密码加密
网课内容
关于功能的创建,比如注册,是先在后端写好接口,再使用postman测试接口。测试结束之后,再写前端页面,和前端axios请求。
由于我不太习惯使用postman,我是先写前端,后端先写个接口,后端不实现功能,后端获取数据之后,再拿着数据去操作。
数据库参数
- mysql参数
就是把mysql+pymysql://root:root@127.0.0.1:3306/shop_env 拆开。方便后期修改
- MYSQL_USERNAME=root
- MYSQL_PASSWORD=root
- MYSQL_HOST=localhost
- MYSQL_PORT=3306
- MYSQL_DB=shop_env
- MYSQL_DRIVER=pymysql
加密的盐SECRET_KEY,可以设置成固定的,也可以使用随机数
- 随机数:os.urandom(16)
SQLALCHEMY_TRACK_MODIFICATIONS 要设置成true 这是一个数据库相关的参数
使用navicat去创建数据库
用户的密码不能明文存储,需要使用加密,加密的方法使用现成的库,问ai去。
- 我们只存储加密后的密码,哪怕数据库泄露也不会有特大影响,用户登录的时候,只需要再次进行加密,然后判断是不是一样的结果就完了。
- 这里使用的是werkzeug.security库,generte_password_hash 对密码加密,check_password_hash将传入的密码和数据库已有的加密密码对比,返回布尔值(第一个参数是加密好的,第二个是等待验证的)
用户的信息:id,name,pwd,nickname昵称,phone手机号,email邮箱,creattime创建时间,uodatatime用户最近登录时间
只有用户名不能相同,就是unique=True 用户名在数据库唯一
用户模块/user/
登录 /login/ 只支持post传递参数。
验证用户信息的时候,如果信息不完全对,就返回用户名或密码错误,让他不知道是账号错了还是密码错了,他不知道账户是否存在,还是密码错误。防止别人拿着用户账号暴力破解。 暴力破解俗称“撞库”
验证逻辑:
- 判断用户名和密码格式是否正确,比如不能为空。验证失败返回错误信息
- if not all([name,pwd]) 使用all加数组,就可以一次性判断多个值是否不为空
- 去数据库找用户,没找到直接同上一步。
- 找密码是否匹配成功,失败同上一步。
- 都通过了就返回正常的信息
- 判断用户名和密码格式是否正确,比如不能为空。验证失败返回错误信息
使用postman调试接口
使用api接收数据,因为都是json数据,用不着传递html模板
注册 /user/ 因为是注册用户,所以判断的时候会麻烦点,验证用户名是否合法,手机号的正则判断等等
工具类message,就是我们在注册的时候,有很多错误状态,我们还要一个个去编辑错误信息。如果都写成json格式在代码里面,就很丑。我们想要提高代码的复用性,就把所有的返回信息都写在工具类里面,然后导入代码,代码再调用工具类的方法。用工具类的方法去返回指定信息。
比如{‘status’:10001,‘msg’:‘密码错误’} 改成to_msg(10001) tomsg设计成接收status,然后再自己去字典找对应的msg信息。再返回出去
后期一点点去加异常类型,token无效,token过期等等
token免密登录
因为存储session还要消耗服务器资源。索性不存储session了,直接写一个加密算法,把用户名和密钥(混淆/验证)进行加密,这个加密过程我们自己要知道。然后把加密好的token给用户储存在客户端浏览器。我们以后只需要根据用户的token能反加密一个正常的用户名就ok了
在用户注册/登录的时候,生成token给用户。后面用户在使用网站的时候,都需要携带token进行api请求
加密算法去python找现成的,密钥自己编或者随机生成,就是盐
token也可以设置有效期
前端
使用vue cli 安装手脚架
尽可能使用cnpm安装插件
不同vue组件如何联系
默认导出语法 export default 默认导出的成员
默认导入语法 import 接收名称 from ‘模块标识符’将本模块中的私有成员暴露出去,供其它模块使用 (注意:每个模块中,只允许使用唯一的一次 export default,否则会报错!
// 导入模块成员 import m1 from './model1.js'
箭头函数的使用
let sum = (num1, num2) => num1 + num2;
let sum = function(num1, num2) { return num1 + num2; };
在vue里面,把页面都写成组件,并且要使用less语言,也就是在vue里面的style 添加属性lang=‘less’ ,还有scoped属性,vue的设计只在当前页面有效
LESS 的语法使用
变量:
@primary-color: #4D926F; .header { color: @primary-color; }
嵌套:
.nav { ul { list-style: none; } li { display: inline-block; } }
混合(Mixins):
.rounded-corners (@radius: 5px) { border-radius: @radius; -webkit-border-radius: @radius; } .box { .rounded-corners; // 使用混合 }
运算:
@base-padding: 10px; .container { padding: @base-padding * 2; // 20px }
引入文件:
@import "variables.less";
继承:
.message { border: 1px solid #ccc; color: #333; } .error-message { .message; // 继承 border-color: red; }
LESS 的特点
变量:支持使用变量来重复使用颜色、字体等样式,提高代码的可维护性。
嵌套:允许在选择器中嵌套样式,逻辑结构更清晰。
混合(Mixins):可以创建可复用的样式,支持参数化,使样式定义更灵活。
运算:支持数学运算,便于动态计算样式值。
导入:可以通过
@import
导入其他 LESS 文件,方便模块化管理样式。继承:通过
.className
的方式拥有其它类的样式,避免代码重复。LESS 是利于提高开发效率的工具,特别适合大型项目中的样式管理。
- token可以保存在cookie里面,也可以保存在sessionstroage里面。推荐是cookie
- 后期所有页面都可以查看token,判断有没有登录。没有登录就使用 to-from-next 干到 login 页面去
- 有token就是登录了,没有token就跳转登录页面
在页面调整的时候,没必要发送数据验证,只需要在发送api 的时候验证即可,也就是axios 拦截器
ui
直接去element ui里面找对应的组件,复制代码就完了,一点点修改要不要哪些东西
element-ui自带一堆图标,随便使用
在前端登录的时候,我们要进行基本的表单验证,比如用户名是否合法,密码是不是空值
不懂的地方去看官方文档或者问ai。
登录页面
使用element-ui里面的from表单,然后两个输入框,两个按钮
- 输入框:用户名,密码
- 按钮:登录,重置
主页页面
在element提供了几种页面布局方式
选的是,有一个头部,和左边aside,以及右边main
头部显示标题,aside显示相关的功能选项
头部
显示logo + 标题(某某商城后台系统)+退出按钮
退出按钮,就是删掉token。并且跳转到登录界面
左边aside 菜单
需要从后端取出来菜单选项,不是写死的。后端把对应的菜单选项放在列表里面,前端去渲染列表
菜单栏
账户信息
权限管理
- 二级目录
- 用户管理
- 角色管理
商品管理
订单管理
数据统计
菜单栏设置
有二级菜单
只保持一个子菜单展示(有参数,可以直接设置
设置动态class,更改菜单图标。提前把所有图标引入,然后通过设置的字典,比如1对应用户图标,2对应设置图标。一一对应上去。
角色管理,就是普通用户,管理员这种角色
角色管理的增删查改,用户管理的增删查改都要实现
main主体
在进入主页页面的时候,右边这一大块地方,要么默认打开一个菜单栏,要么给一个welcome欢迎页面,就是欢迎用户使用某系统
后端
获取用户信息
获取用户列表,要进行分页处理。还要有查询参数,页数,每一页用户数量。
后端需要返回一共多少页。当前是第一页,就是页码。给前端多少用户数据。
获取用户信息的时候,使用列表生成式,生成json格式的列表,再返回给前端
修改用户信息,使用put请求
删除用户,设计成只需要id,就能删除,这样前端在删除用户的时候,点击按钮,就能直接删除用户
因为有很多菜单栏,我们想要保存用户上次选择的菜单选项,可以使用存储token的方式,再增加一个变量来保存用户最后一次点击的菜单选项。在加载页面的时候,就读取这个变量,并付给对应的页面序号。
main页面设置
- 面包屑
就是我们在前端进入不同的页面时,那个路径,在element-ui里面有介绍。
比如:首页/个人信息/详情 这种
搜索框,搜索指定用户
添加用户
table列表
分页器
用户列表展示内容:昵称,名字,密码,邮箱,手机号。
- 还有操作,对用户信息的编辑,或者移除用户
在切换页数,切换页面数据条数,或者跳转页面的时候,都需要请求服务器返回数据
新增用户 ,设计成按钮,点击之后,出现dialog对话框
对用户的操作有三种:编辑用户所有信息,重置用户密码,删除用户
编辑用户信息的时候,需要获取当前行的用户信息,或者获取当前行的用户id,再去服务器请求数据,把请求到的数据回填到对话框里面,避免每次都填写各种信息
重置密码:要么是用户重置自己的密码,要么是管理员重置密码。所以不用验证,只需要一个id即可
用户-角色-权限
- 常见情况:一个用户,一个角色,多个权限
- 不同角色的权限,可以是交叉的,可以是独立的
- 多对多:n个用户,使用一个角色,这一个角色有很多权限
- 多对多对多:n个用户,可以使用n个角色,一个权限被多个角色使用。多对多对多
比如,一个人既是程序员,又是老师,还可以是学生。
每个角色有不同的权限,所以权限还要去重
这个时候就需要再创建一个表了,用来储存不同角色的权限 (含有外键)
所以,用户的基本信息里面,还要显示一个角色属性。
角色存储在数据库的时候,使用01234来区分,但是在前端要使用文字描述,普通用户,管理员,超级管理员等等。还要处理一下,要么后端处理,要么前端处理。反正把数字变成字符串就完了
用户在创建的时候,可以选择成为的角色,因此,我们在后端还要回传一下数据库有哪些角色。再显示在前端
对应权限的增删查改依次实现
添加权限的时候,要加载所有的权限,并且是复选框的设计,毕权限很多个,要是一个个添加太慢了
添加权限的时候,一个角色可能已经有了一些权限,我们需要回显在页面上
关于权限列表,既要有修改角色信息和角色描述的修改按钮,还要有一个删除按钮,以及分配权限按钮,就是给角色分配权限按钮
商品分类
使用员工上司表,就是一个商品数据,有三个属性。一个是名称,一个是自己的id,一个上级id
和导航栏一样,是从数据库动态获取商品url的。
我写的系统,把导航栏写死了。他这个是动态加载的。用户和管理员公用一个页面。
商品信息
名称,价格,库存,介绍,大图片(储存图片地址),略缩图,商品审核状态,有没有折扣,折扣商品个数,权重(商品排名,隐藏分),一级分类,二级分类,三级分类,商品下架
在商品信息页面,还要有更详细的商品介绍,就是网购的时候,下面的图片,文字介绍。可以使用富文本,把数据编辑成字符串数据储存。在服务器使用循环遍历保存。
图片保存到项目里面
商品图片等等,直接放在项目的图片目录下面保存
图片名称可以使用时间戳+哈希算法命名
elementui里面有一个上传文件的upload
订单
商品信息,支付状态,收发货地址,订单编号,用户名,支付金额,物流运输状态
物流状态是类似权限关系表一样,只保留订单id。前端在查询的时候,遍历数据库特定id即可获取物流状态。意味着所有的订单物流信息,都存储在一个表里面。
物流状态通过一个按钮触发对话框。对话框使用elementui里面的时间线ui组件,展示物流信息。
数据展示
使用echarts
直接在vue里面安装依赖。
安装官方教程,导入js文件,给它一个div容器就完了,服务器返回数据。前端把数据放在列表里面,会自动渲染ui的。
网站计划目录结构
Admin 管理员主页
Dashboard (仪表盘) 总览关键指标与统计信息,如用户数、订单数、销售额等。
User Management (用户管理)
User List (用户列表)展示所有用户信息(如用户名、注册日期、状态等)。支持增、删、查、改功能。支持搜索和筛选功能。
User Details (用户详情)显示单个用户的详细信息(如个人资料、订单历史、角色信息等)。
Product Management (商品管理)
Product List (商品列表)展示所有商品的信息(如商品名称、价格、库存状态等)。支持增、删、查、改功能。
Add Product (添加商品)添加新商品的界面。包括商品信息填写、图片上传等功能。
Product Categories (商品分类管理)管理商品分类(如创建、修改、删除分类)。
Product Reviews (商品评价管理)查看和管理顾客对商品的评价及反馈。支持回复评价功能。
Order Management (订单管理)
Order List (订单列表)展示所有订单的概览(如订单号、顾客、订单状态等)。支持增、删、查、改功能。
Order Details (订单详情)查看单个订单的详细信息(如商品、数量、价格、顾客信息等)。
Order Status (订单状态管理)修改和管理订单状态(如待发货、已完成、已取消等)。
Inventory Management (库存管理)
Stock Levels (库存水平)查看所有商品的库存状态。提供库存预警功能。
Stock Alerts (库存警报)设置低库存警报,并在库存低于阈值时通知管理员。
Product Transfers (商品转移)管理商品在不同仓库或地点之间的转移。
Sales Reports (销售报告)
Daily Sales (日销售)生成每日销售报告,查看收入和解决问题。
Monthly Sales (月销售)生成每月销售报告,分析销售趋势和业绩。
Custom Reports (自定义报告)根据需求生成特定时间段或商品类别的报告。
Settings (设置)
System Settings (系统设置)配置系统参数(如网站名称、联系信息、时间格式等)。
Profile (个人信息)
View Profile (查看资料)查看管理员的个人资料及权限。
Edit Profile (编辑资料)更新管理员的个人信息(如联系方式、头像等)。
Change Password (修改密码)更新当前密码,确保账户安全。
User 用户主页
Profile (个人信息)
View Profile (查看资料):展示用户的个人基本信息,如用户名、手机号、邮箱、创建时间、最近登录时间等。
Edit Profile (编辑资料):用户可以对自己的信息进行修改(如更改手机号、邮箱等),并保存更改。
Change Password (修改密码):提供一个表单,让用户可以输入当前密码和新密码,用于修改账户密码。
Orders (订单管理)
Order History (订单历史):列出用户的历史订单,包括订单号、购买时间、状态等信息。
Order Details (订单详情):显示单个订单的详细信息,如商品列表、总金额、收货地址等。
Return/Cancel Order (订单退换/取消):用户可以选择已购买的订单进行退换或取消,并提供相关说明。
Wishlist (愿望清单)
View Wishlist (查看愿望清单):展示用户希望购买的商品列表。
Add Item to Wishlist (添加商品到愿望清单):用户可以选择商品并将其添加到愿望清单中。
Shopping (购物)
Browse Products (浏览商品):允许用户查看和搜索商品,以便发现新商品。
Cart (购物车):显示用户已加入购物车的商品,用户可以修改商品数量或删除商品。
Checkout (结账):用户进行订单结算的页面,输入送货地址、选择支付方式并确认订单。
Support (支持)
Contact Support (联系客服):提供联系客服的方式,例如通过在线聊天、电子邮件或电话联系。
FAQ (常见问题):提供常见问题的解答,帮助用户快速找到问题的解决方案。
我的设计
上面的都是听课记的笔记,就是一个思路。下面是我自己做网站的过程。
首页
我设计的网站,一进去是一个纯色背景的带有logo的页面。用户点击之后,进入login页面。
login页面
在这个页面,是左右结构,左边是logo,右边是from表单。
当前这个页面的主体也是from表单
- 前端的axios发送用户名和密码
postfrom(){
axios.post('http://127.0.0.1:5000/login/', {
name:this.ruleForm.name,
pwd:this.ruleForm.pass
})
.then(response => {
console.log(response.data);
})
.catch(err => {
console.error('Error:', err);
});
}
- 后端flask接收
@app.route('/login/',methods=['post'])
def login():
data = request.get_json()
name = data.get('name')
pwd = data.get('pwd')
print(name,pwd)
return '123'
在后端接收数据的时候遇到了跨域的问题
使用cors解决跨域问题
from flask_cors import CORS
app = Flask(__name__)
CORS(app) # 允许所有域名的跨域请求
- 设计数据库user
这里使用SQLAlchemy,因为pymysql需要自己设计sql语句,看上去比较low。虽然不太会用,但是公司还是喜欢逼格高的东西。欸,慢慢学习吧。
registered注册页面
还是单独设计一个注册页面吧,就不跟登录页面抢空间了
我使用了一个进度条:
- 用户填写表单
- 提交表单
- 服务器验证
- 返回登录/直接进入个人主页
第4步暂时选择返回登录
算了,还是砍掉第1步吧,因为是在一个注册页面,同时显示三个子页面。如果等第一个填写表单的组件回传填写进度,代码难度又高了点。为了不为难自己,还是砍掉吧。
- 用户要不要在创建的时候就选择角色,比如普通用户和管理员?
如果用户量很少,还是管理员统一管理比较好。那就不给用户选择的空间了。
home主页
也就是网站的主要页面了。上课的老师是使用一个主页,针对不同角色打开不同菜单栏。问了下ai,说是分开比较好。管理员类的角色,主要负责管理。用户主打一个购物体验。
用户主页home
用户主页主打一个购物,尽可能少一些导航栏。
这里使用了固定的导航栏,没有采用从服务器动态获取导航栏。因为用户和管理员的页面是不同的,本来就不同,没必要再动态获取页面结构的参数了。
使用了if判断获取用户点击的导航栏是哪个。然后去执行对应的方法。突然发现,我们需要在登录的时候,把用户名储存在浏览器。因为我们要基于用户名去服务器获取对应的数据。用户的名字,电话,邮箱等信息。
考虑了好久,要不要存储cookie在浏览器里面。只是实现了一个免登录,算了,我的小破站,没必要整个免登录了。而且现在的浏览器默认填写用户名密码。我们只需要点击一个登录,就能进入主页。
没有什么信息验证环节。索性就不实现免登录效果了。
已经成功在登录的时候,把用户名保存到cookie里面了,但是我想要实现一个功能,当用户在主页折起所有菜单的时候,main部分应该显示空,而不是最近一次鼠标点击的那一个菜单栏。(没有实现,想要在el-menu上面使用鼠标悬浮事件,一直没有成功,明天再试试,睡觉去,现在是2:28,不要问我是早上还是下午)
vue里面不支持jinja语法啊。还好有可以替代的方法。
- 突然意识到,这个用户主页很多功能都需要使用api了,要么在服务器里面一个个创建api,要么使用蓝图
刚刚想使用蓝图。又觉得管理员主页可能也会复用这些api。还是不用蓝图了。
- 我的数据库是依据用户的手机号为唯一元素。如果我用用户名作为查询条件,可能获取的不是用户真实的信息。
所以,在用户登录的时候,还要把手机号存储在cookie里面。使用手机号作为用户的唯一标识。以手机号去跟服务器交互。
- 突然忘记了测试用户页面的账户密码
然后尝试了好几次,差点心态崩了。我要返回登录页面设计一个“忘记密码”功能。
由于数据库是加密存储密码,所以,反而防了自己一手。
通过用户名和手机号,邮箱,去后端验证数据库是否存在该用户,如果存在就直接重置密码为123456.舒服多了
感觉写这个网站,就像木雕一样。对于网站的大体可以很简单的设计出来,剩下的就是慢慢雕琢细节。更人性化。
管理员主页manage
把用户主页的查看资料和修改密码迁移过来了。
但是目前右上角的头像不能正常显示了。哦没有把检查输入框格式的函数validateOldPass之类的拷过来
- 我在设计管理员添加用户功能,我在想作为管理员,应该可以省去信息验证,支持批量添加用户,那该如何批量添加呢
在切换列表页的时候,要调用方法去数据库请求新数据
在切换每一页数据个数的时候,也要重新请求数据
新增用户的时候,也要重新请求数据。
莫名其妙的很多bug,都是自己埋的雷。
使用sql语句的like,可以模糊查询用户。因为使用了模糊查询,要把前端页数置为1。因为查询数量不符合页数。
查询页数置1了,还要修改用户的数量。之前为了偷懒,设计了get请求方式,因为没想到用户数量会变。
现在才发现,应该根据查询条件,即查询用户的名称关键字,去后端查询。得到的用户数量是不同的。所以又把获取用户数量的方法,前后端都改了一下,改成post请求,并且携带查询参数。
之前一直想的是,由于翻页的时候,总人数不变,所以把获取总人数和获取分页数据的请求分开了。
我设计的是,点击用户列表这一栏的时候,同时调用获取总人数和用户列表两个方法。点击搜索的时候,也要同时调用两个方法。点击换页的时候,只调用获取用户列表方法。切换每一页的用户展示数量的时候也要调用获取用户列表方法。
- 让ai给了份数据,手动注册用户
用户名 | 手机号 | 邮箱 | 密码 |
---|---|---|---|
王晓丽 | 13812345678 | wangxiaoli@example.com | pass123 |
李明 | 13987654321 | liming@example.com | mypassword |
张伟 | 13765432109 | zhangwei@example.com | securePass1 |
刘婷 | 13612345678 | liuting@example.com | abc123def |
陈刚 | 13598765432 | chengang@example.com | pwd@2023 |
杨洋 | 13467891234 | yangyang@example.com | helloWorld |
赵静 | 13345678901 | zhaojing@example.com | 123456789 |
周杰伦 | 13234567890 | zhoujielun@example.com | password1 |
徐静蕾 | 13123456789 | xujinglei@example.com | letmein123 |
何璐 | 13098765432 | helu@example.com | welcome123 |
用户名 | 手机号 | 邮箱 | 密码 |
---|---|---|---|
孙丽丽 | 13834567890 | sunlili@example.com | sunshine2023 |
周星 | 13912345678 | zhouxing@example.com | comedyKing101 |
韩梅梅 | 13798765432 | hanmeimei@example.com | mySecretPass |
吕布 | 13623456789 | lubu@example.com | warrior2023 |
朱莉 | 13567891234 | zhu@example.com | lovelyP@ss |
李华 | 13456789012 | lihua@example.com | password1234 |
郝蕾 | 13323456789 | haolei@example.com | easyPass! |
余文乐 | 13212345678 | yuwenle@example.com | coolDude99 |
施华洛 | 13134567890 | shihualuo@example.com | diamond@home |
赖声川 | 13067891234 | laishengchuan@example.com | creativeMind123 |
用户名 | 手机号 | 邮箱 | 密码 |
---|---|---|---|
甄嬛啊 | 13876543210 | zhenhuan@example.com | qwerty123 |
马云啊 | 13923456789 | mayun@example.com | alibaba@2023 |
陆雪琪 | 13789012345 | luxueqi@example.com | snowflake2023 |
陈冠啊 | 13645678901 | chenguangxi@example.com | popstar123 |
徐峥啊 | 13567890123 | xuzheng@example.com | actor2023 |
由于批量创建的用户,都还没登录过,所以登录时间那一栏都是空的
考虑到是管理员添加用户,就没有对用户进行资质验证。其实应该在服务器进行一个验证的。哪些用户被添加,哪些用户添加失败。
再去后端修改一下。
现在要实现的是表格里面的用户操作。对用户的查看,编辑,删除。
用户的查看,编辑,删除
- 查看用户,设想的是点击查看之后,获取选中行的用户的id,或手机号,去数据库拿到所有数据。后期还要增加商品。查看用户订单历史。目前还没这么多功能。
先查看用户的基本信息得了。
还想着偷懒直接把表格数据拿过去展示。算了单独写接口。用户详情里面可以搜索单独的用户,展示用户资料。也可以是从用户列表点击查看跳转过去的。
查看用户信息,是拿用户名,调用获取用户列表方法?万一有同名用户就会出错,只能是拿手机号或者id。欸,不能复用了。
由于是管理员界面,直接通过id查询得了。那也不行啊。就不能在用户详情页面单独查询用户了。emmm,就是不能使用用户名去查询了,考虑手机号或者id。
还是使用手机号吧,数据库文件里面有一个通过手机号,获取用户邮箱、角色及其他信息的方法。复用这个函数。增加一些功能罢了。
- 出现了一个bug,我说呢,怎么之前设计的方法这么好使
之前为了加载这个页面,需要调用两个方法,即前面说的用户数量和用户列表。由于搜索的时候,应该也调用这两个方法。我偷懒调用了加载页面方法。就是点击菜单栏的时候,自动调用的方法。然后成了死循环。导致我在输入框输入文本的时候,会0延迟出现搜索结果,甚至不需要点击搜索按钮。我说昨晚测试的时候,还高兴了一下,就是莫名其妙的电脑狂啸。今早上一看控制台,好家伙,死循环,不断刷新用户列表。
- 现在回到一个问题,之前设计的编辑用户资料,我觉得用户的手机号就是身份证,不能随便改,设置的只能修改用户名和邮箱。
这个功能也移植了管理员的菜单栏。
现在又觉得,貌似可以发送六条数据进入服务器验证,前三条用来找用户,后三条修改用户的值。就可以修改手机号了。
之前设计的是发送三条数据,手机号,用户名,邮箱。以手机号为准,查找用户,并修改用户名和邮箱。
先不调整了,后期无聊的时候再改。现在先实现网站整体结构。
- 开始设计删除用户,设计一个对话框获取选中用户的名称和手机号。
拿着手机号去删除用户。
- 编辑用户功能,想了想,改成权限管理比较合适。这里写死了只能选择用户和管理员。
用户名就不修改了,感觉意义不大
二级路由
之前学过二级路由,没觉得有啥用处
现在感觉到了,在创建“注册”页面的时候,ai建议我的页面,可以使用div+v-if的模式,进行展开和收起。然后我就把主页的所有页面都放在一个vue里面,导致我在创建变量的时候,需要考虑起名方式,变量不能冲突。还是分开一些组件吧。
好消息:解决页面触发跳转问题
router.push(route).catch(err => {
if (err.name !== 'NavigationDuplicated') {
// 处理其他类型的错误
console.error(err);
}
});
之前一直有一个困扰我多年的问题,就是在当前页面,如果你还想进入,哪怕是不小心进入,也会触发一个报错。就是vue不希望你多次跳转当前页面。
网上找了很多方法,都不行,原来是需要在跳转页面的时候,捕获错误信息NavigationDuplicated。
为了不影响其他的报错,所以使用了if筛选报错类型。
真是可喜可贺啊!
继续搞组件的分离。由于管理员的菜单栏功能有19种,后续可能有多有少。个人倾向于减少,能摸鱼多爽。
被这个页面跳转恶心了半天了。
商品分类
按照老师的方法,去数据库创建商品分类表。
后端调用方法,如果前端给的是空参,那么只获取一级分类。如果是有参就是二级分类,对,我只做了二级分类。
前端调用的时候,默认是给空参。然后渲染在页面上,当用户点击一级分类的时候,再加载对应的二级分类,渲染到页面上。
- 添加商品分类
规则,可以选择商品分类的等级,一级分类,就是类似大纲,比较模糊,比如电子设备。二级分类是细致化的,如手机。
当选择一级分类的时候,可以使用输入框输入新的一级分类。
选择二级分类的时候,必须选择父级分类是哪一个,才能使用输入框。否则禁用输入框。
在用户没有选择商品分类等级的时候,不可以选择二级分类选择器,也不可以使用输入框。
使用按钮调用对话框的时候实现。现在对话框实现了,要去实现具体的方法。懒蛋了。明天说。
具体方法都实现了,就想着,跟课上一样,给这个商品分类加个标签tag属性,更好看一点。
就发现了elementui提供的动态编辑标签方法。
目前我实现了一个功能,就是通过按钮,触发对话框,选择父级商品分类,添加子级分类。
要重新修改一下,对话框也不要了,按钮也不要了。使用new tag方法。自动获取父级id。
- 在elementui里面有一个tag组件
这是一个标签功能,就是给一段文本加个边框,显得像个标签。还支持右侧显示x,直接删除功能。对于用户体验来说,非常的吃香。反正直接点击标签的删除,或者点击增加标签。比点击按钮再到对话框一点点选择,这个过程更舒服。个人体验来说,也是非常实用。
还有就是调整样式的问题。由于使用的是elementui组件。人家的组件会自带样式,优先级还挺高。有的还特别难去修改样式。反正挺麻烦的,推荐是给他们加div容器,对容器直接使用style属性进行一些调整,或者解决相对定位绝对定位的问题。
逻辑不成问题,就是一点点样式还不成功比较烦人。
后边就是设计商品了
添加商品
这回,是能看到成果的时刻了。总算是给商品系统,添加商品了。。。
回头看去,才发现,对于毕设来说,或者从实用角度来说,这个商品管理系统,貌似不需要给普通用户设计。都是管理员。面向的群体,也是类似仓库管理方面的人群。基本不会给用户去使用。
总结一下就是,都是管理员,给管理员不同的权限罢了。
比如,基层管理员,可以使用添加商品功能,负责商品入库。
稍微高级点的管理员,可以查看商品库存,管理基础管理员,负责库存管理。
再高级的管理员,就是分配权限,什么都能看到那种,超级管理员了。
大概就这个意思。生活中,有两级就够了。普通管理员和超级管理员。超级管理员也就是多一个管理普通管理员这一个功能,就足够了。
增加代码的灵活性,也是推荐,能使用数据库的,就使用数据库。能在前端动态加载的就让前端动态加载。
- 吃的亏,之前觉得,导航栏基本固定了,没什么改动的余地。就按照之前的网站目录结构创建了一堆组件,再配置路由,挂载到manage组件里面。设计的过程中,又发现一些组件没什么用,什么仓库管理。商品数量预警。销售统计。在网站设计的时候,觉得都有用,目前来看,没啥大用。写也没必要,不写吧,就不写了。
- 如果当初,按照老师的方式,学到什么功能,就添加什么功能。把这个功能写在数据库里面,前端根据数据库和管理员的权限去加载功能。比如商品分类管理。权限是1,所有管理员都能使用。返回给前端,让前端可以显示。如果是管理员管理功能,权限是2.只有超级管理员可以使用,那么普通管理员将无法看到这个功能。都加载不到,获取不到。
- 确实是比较香。先不改了,凑合用吧。原理都知道了。睡觉睡觉,狗命要紧。(凌晨1:04,算是睡得早的)
商品展示设计
在搜索商品的时候,没必要展示商品的全部属性。
在搜索页面,展示商品的图片,商品名称,商品价格,商品已售数量,
CREATE TABLE products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL, -- 商品名称
category_id INT NOT NULL, -- 分类 ID
price FLOAT NOT NULL, -- 商品价格
stock INT DEFAULT 0, -- 库存数量
FOREIGN KEY (category_id) REFERENCES product_categories(id) -- 外键约束
);
CREATE TABLE product_details (
id INT AUTO_INCREMENT PRIMARY KEY,
product_id INT NOT NULL, -- 关联商品 ID
description TEXT NOT NULL, -- 商品详细描述
additional_info TEXT, -- 额外信息
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, -- 创建时间
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- 更新时间
FOREIGN KEY (product_id) REFERENCES products(id) -- 外键约束
);
遗漏了商品图片,还要修改。。。
订单
商品下单数量,商品总价格,支付状态。
总感觉差点什么,好像要有商家的信息。我们设计的这个网站给用户看的时候,不需要展示商家信息,但是设计物流运输信息,就同时需要卖家信息和买家信息。地址,发货时间。
就要增加几个表,物流运输表,用户地址表(要么就修改已经成熟的用户表),订单表。懒蛋了。
就算大功告成了。主要的用户管理,商品管理完善了,就剩个订单了。
算了,直接把订单模块移除了。
嘶~,还是做个低配版的订购模块吧。在商品列表点击下单后,选择商品数量,直接支付成功。生成订单,也是以时间戳为订单编号。
订单表,有一个id主键自增,下单用户名,下单数量,商品id,商品名,支付金额,订单编号-时间戳,下单时间。
本来不想太麻烦,ai还是出手了把我的用户名换成了用户id,商品名也换成了商品id。。。行吧,偷个懒都不行。
由于下单的时候使用了之前构建的一个异步方法,没有插入await关键字,导致订单一直无法生成。
擦,这种小错误,真让人头大。逻辑没问题,最后还是看编译器有个推荐语法,提示我插入关键字,要是没有这个语法提示,估计我要重构代码了。
订单列表
最后一个板块了。。。不对,还有一个数据面板,展示数据库的所有数据,等下再说。
只需要获取订单表里面的全部数据即可。没有任何操作,只有展示数据。
交给ai一分钟就结束了,稍微配置一下文件就ok了。
数据面板
尽可能获取所有可以展示的数据。
展示了4个数据,用户数量,商品数量,订单数量,每月订单数量。
完结
有很多细节无法一一体现。还有很多功能想要展示。等明天,舍友睡醒了。方便我咔咔按鼠标,再一点点展示这个商城系统的全部功能。
告一段落了。
这个商城讲了140节课,平均每节课10分钟,粗略计算,只能更多。差不多20多个小时的时长。
我的个人设计,再算上听课时间差不多一周的时间就完成了。实际上经过了五一假期,又提前回家,一共是两周的时间才完成。
在写这个项目之前无从下手,感觉要考虑的东西太多了。
确实是,比如前端页面设计。尤其是使用了elementui组件,他自带很多属性,我没有老师那么熟悉属性的用法。很多地方都是使用元素的内联style让优先级强制超过自带的样式。如果不考虑这个局部的样式调整,vue搭配elementui组件,可以快速的构建前端页面。
确实是有很大的好处。总结也是利大于弊。
再一个就是后端flask的设计。在写项目之前,或者听课的过程中,看到老师一丝不苟的使用了尽可能多的知识点,什么蓝图,路由配置啥的。
作为一个小白来说,一个文件能解决的事,就尽量不分开写。因为我感觉,把一个完整的文件拆开,再让他们互相通信,属实麻烦。尤其是flask自带的模板页面。它确实是可以传递html。但是它的本职工作是进行数据处理,而非页面渲染。在听课的过程中多次强调了解即可,还真是。
这种前后端分离的项目确实很方便。flask只负责数据处理和提高api接口。vue只负责页面渲染和使用api接口。
有一个特别想说的话,虽然文件分离很烦,确实是更有逻辑。由于flask后端负责的任务单一,结构不复杂,flask项目可以尽可能不分离。比如所有的数据库模型和数据库方法,就可以在一个文件里面,没必要模型一个文件,方法一个文件。老师教的是模型一个文件,每一个模型的方法再单独一个文件。确实是在大公司里面有必要,因为项目足够庞大,但是对于个人,或者小型企业来说,如此复杂的项目结构,只会增加项目的复杂度。我个人看来,对于小型项目来说,分离文件操作是弊大于利。
前端的话,有个好处,页面可以复用,比后端更加方便。前端vue框架里面,是一切皆组件。意味着vue项目始终只有一个页面,不用担心页面跳转消耗的时间。比flask提供的页面跳转要快很多。这是一个优点,就是页面跳转速度非常快,没有跳转损耗。要是慢只能是服务器响应的数据慢,不可能是页面加载慢。
其次前端vue里面,可以直接嵌套页面,也就是路由接口router-view。本项目里面唯一一个组件的参数传递,就是用户列表到用户详情。传递了一个用户的id。现在想想有更好的解决方法,使用对话框来展示用户信息,就没必要切换组件了。
所以基本上组件之间不会互相通信。减去了组件通讯的麻烦。
哦,对,我想说的是vue里面,可以稍微拆分一下项目。比如用户列表和商品列表啥的可以拆开,或者说商品列表和添加商品这两个功能,可以拆开。
我前面说过一次,就是我担心项目结构过于复杂,不敢拆分文件,导致我的好多功能写在一个文件里面,之前是把用户列表,编辑资料,重置密码三个功能放在一个文件里面,导致我在构造方法的时候,经常遇到命名冲突的问题,以及变量命名冲突的问题。比如,用户自己的个人信息在一个表单里面,在用户列表里面,所有的用户信息在一个列表里面,我们操作用户的时候需要获取被操作用户的信息,又要创建一个被操作用户表单,操作用户的时候,有删除,查看,修改用户。我们不能直接把新的数据写在原来的表单里面,万一数据库错误或者前端数据库错误。数据就污染了,所以还要创建表单。
以及使用elementui的时候,他自带很多属性需要绑定很多值,比如选择器需要绑定v-model,还有输入框绑定prop等等。反正需要很多变量,方法。很容易引发命名问题。
所以尽可能去拆分vue文件,尽可能保留flask文件。
我不可能把整个项目的所有文件依次传入这个博客。顶多传到我的github。我会保留这个项目到网盘,压缩成压缩包。可以找我要一下,互相交流。
明天录项目的使用视频。