2
.gitbook.yaml
Normal file
2
.gitbook.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
structure:
|
||||
summary: doc/README.md
|
||||
31
CHANGELOG.md
31
CHANGELOG.md
@@ -1,6 +1,25 @@
|
||||
## 更新日志
|
||||
# 更新日志
|
||||
|
||||
### V 0.5.0
|
||||
## V 0.7.0
|
||||
|
||||
*2018-06-30*,数据库再次简化
|
||||
|
||||
* `管理后台`支持商品上架和商品编辑
|
||||
* `项目`数据库再次简化、小商城和管理后台代码进行相应调整
|
||||
|
||||
|
||||
## V 0.6.0
|
||||
|
||||
*2018-06-30*,项目支持商品上架和统计功能
|
||||
|
||||
* `小商场`因wx.getUserInfo接口调整,微信登录调整
|
||||
* `小商场`支持手机号码验证
|
||||
* `管理后台`支持简单的统计
|
||||
* `管理后台`支持商品上架
|
||||
* `管理后台`基于官方tinymce-vue实现富文本编辑
|
||||
* `项目`支持docker部署
|
||||
|
||||
## V 0.5.0
|
||||
|
||||
*2018-05-11*,项目支持微信支付和修复小程序的一些BUG
|
||||
|
||||
@@ -18,7 +37,7 @@
|
||||
* `项目`文档整理部署方案和上线方案
|
||||
* `项目`文档支持更新日志、贡献指南和常见问题
|
||||
|
||||
### V 0.4.0
|
||||
## V 0.4.0
|
||||
|
||||
*2018-04-21*,项目结构调整,增加了两个模块
|
||||
|
||||
@@ -33,7 +52,7 @@
|
||||
* `基础系统`新增litemall-all模块作为包裹模块,支持三个后台服务和静态文件
|
||||
打包成一个war项目包
|
||||
|
||||
### V 0.3.0
|
||||
## V 0.3.0
|
||||
|
||||
*2018-04-07*,业务模块从物理删除调整成逻辑删除
|
||||
|
||||
@@ -46,7 +65,7 @@
|
||||
* `基础系统`数据库中除regions几个表,其他所有表都添加`add_time`和`deleted`字段
|
||||
* `基础系统`litemall-db模块不支持数据物理删除,删除则设置`deleted`,而查询则过滤`deleted`
|
||||
|
||||
### V 0.2.0
|
||||
## V 0.2.0
|
||||
|
||||
*2018-04-02*,修复一些小商场出现的问题。
|
||||
|
||||
@@ -59,6 +78,6 @@
|
||||
* `管理后台`禁止管理员修改超级管理员信息
|
||||
* `基础系统`自动脚本util/lazy.sh和util/upload.sh
|
||||
|
||||
### V 0.1.0
|
||||
## V 0.1.0
|
||||
|
||||
*2018-03-24*, 项目架构基本完成。
|
||||
@@ -1,4 +1,4 @@
|
||||
## 贡献
|
||||
# 贡献指南
|
||||
|
||||
任何形式的贡献都欢迎,包括:
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
目前项目基本框架已经建立,但是还不完整,因此非常欢迎人一起讨论技术和业务。
|
||||
但是交流合作之前,请查看以下碎碎念。
|
||||
|
||||
### 项目理念
|
||||
## 项目理念
|
||||
|
||||
litemall的设计受众是小微型企业,而不是互联网企业,因此litemall的开发理念是一个小而美:
|
||||
|
||||
@@ -68,7 +68,7 @@ litemall的设计受众是小微型企业,而不是互联网企业,因此lit
|
||||
当然,如果开发者不认同这里的一些理念,也可以基于自己的技术选型来开发自己的版本。
|
||||
如果认为自己开发的好,可以在本项目提交链接地址,让其他开发者了解。
|
||||
|
||||
### 项目业务
|
||||
## 项目业务
|
||||
|
||||
本项目所设想的基本业务功能已经在文档中列举完成。
|
||||
|
||||
@@ -78,11 +78,11 @@ litemall的设计受众是小微型企业,而不是互联网企业,因此lit
|
||||
|
||||
当然更希望开发者直接提供代码,丰富完善目前的基础业务功能。
|
||||
|
||||
### 代码贡献
|
||||
## 代码贡献
|
||||
|
||||
* 代码规范目前没有严格要求,后续会补充。
|
||||
|
||||
### Issue规范
|
||||
## Issue规范
|
||||
|
||||
* 在提交issue之前,请搜索是否存在相关问题。
|
||||
* 提交的Issue请尽可能给出详细信息
|
||||
|
||||
100
README.md
100
README.md
@@ -1,20 +1,18 @@
|
||||
litemall
|
||||
=====
|
||||
# litemall
|
||||
|
||||
又一个小商场系统。
|
||||
|
||||
项目代码
|
||||
====
|
||||
litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
|
||||
|
||||
## 项目代码
|
||||
|
||||
* [码云](https://gitee.com/linlinjava/litemall)
|
||||
* [GitHub](https://github.com/linlinjava/litemall)
|
||||
|
||||
项目架构
|
||||
====
|
||||
## 项目架构
|
||||

|
||||
|
||||
技术栈
|
||||
===
|
||||
## 技术栈
|
||||
|
||||
> 1. Spring Boot
|
||||
> 2. Vue
|
||||
@@ -22,8 +20,7 @@ litemall
|
||||
|
||||

|
||||
|
||||
效果
|
||||
==
|
||||
## 效果
|
||||
|
||||
### 小商城效果
|
||||
|
||||
@@ -33,53 +30,28 @@ litemall
|
||||
* 专题列表、专题详情
|
||||
* 分类列表、分类详情
|
||||
* 品牌列表、品牌详情
|
||||
* 新品首发
|
||||
* 人气推荐
|
||||
* 商品搜索
|
||||
* 新品首发、人气推荐
|
||||
* 搜索
|
||||
* 商品详情
|
||||
* 商品评价列表、商品评价
|
||||
* 购物车
|
||||
* 下单
|
||||
* 我的主页
|
||||
* 个人
|
||||
* 订单列表、订单详情
|
||||
* 地址列表、地址添加、地址删除
|
||||
* 我的收藏
|
||||
* 我的足迹
|
||||
|
||||
* 收藏、足迹
|
||||
|
||||
### 管理平台效果
|
||||
|
||||

|
||||
|
||||
* 会员管理
|
||||
* 会员管理
|
||||
* 收货地址管理
|
||||
* 会员收藏
|
||||
* 会员足迹
|
||||
* 搜索历史
|
||||
* 购物车
|
||||
* 商城管理
|
||||
* 区域配置
|
||||
* 品牌制造商
|
||||
* 订单管理
|
||||
* 商品类目
|
||||
* 通用问题
|
||||
* 关键词
|
||||
* 商品管理
|
||||
* 商品管理
|
||||
* 商品参数
|
||||
* 商品规格
|
||||
* 货品管理
|
||||
* 用户评论
|
||||
* 推广管理
|
||||
* 广告列表
|
||||
* 专题管理
|
||||
* 系统管理
|
||||
* 管理员
|
||||
* 对象存储
|
||||
|
||||
云演示
|
||||
==
|
||||
## 云演示
|
||||
|
||||
### 小商城演示访问
|
||||
|
||||
@@ -89,6 +61,7 @@ litemall
|
||||
2. 项目配置,启用“不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书”
|
||||
3. 点击“编译”,即可在微信开发工具预览效果;
|
||||
4. 也可以点击“预览”,然后手机扫描登录。
|
||||
注意,手机需要打开调试功能。
|
||||
|
||||

|
||||
|
||||
@@ -97,35 +70,30 @@ litemall
|
||||
1. 浏览器打开,输入以下网址[http://122.152.206.172:8080/#/login](http://122.152.206.172:8080/#/login)
|
||||
2. 管理员名称`admin123`,管理员密码`admin123`
|
||||
|
||||
文档
|
||||
==
|
||||
## 文档
|
||||
|
||||
1. [系统架构](doc/1.md)
|
||||
2. [基础平台](doc/2.md)
|
||||
3. [小商场](doc/3.md)
|
||||
4. [管理后台](doc/4.md)
|
||||
5. [商场](doc/5.md)
|
||||
6. [下一步计划](doc/6.md)
|
||||
7. [FAQ](doc/7.md)
|
||||
[在线文档](https://linlinjava.gitbook.io/litemall/)
|
||||
|
||||
文档内容采用 [署名-禁止演绎 4.0 国际协议许可](https://creativecommons.org/licenses/by-nd/4.0/deed.zh)
|
||||
文档采用 [署名-禁止演绎 4.0 国际协议许可](https://creativecommons.org/licenses/by-nd/4.0/deed.zh)
|
||||
|
||||
开发计划
|
||||
====
|
||||
## 开发计划
|
||||
|
||||
目前项目开发中,存在诸多不足,以下是目前规划的开发计划。
|
||||
|
||||
V 1.0.0 完成以下目标:
|
||||
1. 除了部分功能(如支付和优惠券等),小商城的优化和改进基本结束;
|
||||
|
||||
1. 除了部分功能(如优惠券等),小商城的优化和改进基本结束;
|
||||
2. 管理后台基本实现所有表的CRUD操作;
|
||||
3. 后台服务能够对参数进行检验。
|
||||
|
||||
V 2.0.0 完成以下目标:
|
||||
|
||||
1. 小商城能够完成基本的业务功能;
|
||||
2. 管理后台实现较好的业务操作和交互效果,而不是简单的CRUD;
|
||||
3. 管理后台实现统计功能、日志功能
|
||||
|
||||
V 3.0.0 完成以下目标:
|
||||
|
||||
1. 管理后台一些辅助功能
|
||||
2. 后台服务加强安全功能、配置功能
|
||||
3. 项目代码重构和清理
|
||||
@@ -134,6 +102,7 @@ V 3.0.0 完成以下目标:
|
||||
项目结束,已经是一个真正可工作的项目,此时进入维护阶段。
|
||||
|
||||
如果真的坚持到维护阶段,那么存在三种可能性:
|
||||
|
||||
1. 或者开发 V 4.0.0,实现web商场子系统;
|
||||
2. 或者重新开发一个新的独立项目,引入企业级功能,如缓存、权限、对象存储云服务等;
|
||||
3. 或者结束,不再开发,仅仅维护。
|
||||
@@ -141,37 +110,30 @@ V 3.0.0 完成以下目标:
|
||||
警告:
|
||||
> ** 以上仅仅是个人规划的开发计划,实际可能出现任何情况,例如能力有限而放弃开发。**
|
||||
|
||||
开发进度更新
|
||||
======
|
||||
## 开发进度
|
||||
|
||||
查看[更新日志](CHANGELOG.md)
|
||||
|
||||
目前V0.5.0
|
||||
目前V0.6.0
|
||||
|
||||
警告
|
||||
==
|
||||
## 警告
|
||||
|
||||
> 1. 本项目仅用于学习练习
|
||||
> 2. 数据库数据来自nideshop
|
||||
> 3. 项目代码目前还不完善,仍处在开发中
|
||||
> 4. 项目开源(MIT),但不承担任何使用后果
|
||||
|
||||
致谢
|
||||
==
|
||||
## 致谢
|
||||
|
||||
本项目基于或参考以下项目:
|
||||
> 1. [nideshop-mini-program](https://github.com/tumobi/nideshop-mini-program)
|
||||
> 如果后端希望采用nodejs,开发者可以访问nideshop项目
|
||||
> 2. [platform](https://gitee.com/fuyang_lipengjun/platform)
|
||||
> 如果后端希望采用非spring boot版的普通spring版或者更多功能,
|
||||
> 开发者可以访问platform项目
|
||||
> 3. [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
> 2. [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
> 一个基于Vue和Element的后台集成方案
|
||||
|
||||
本项目所依赖的其他开源项目见相关章节
|
||||
|
||||
问题
|
||||
==
|
||||
## 问题
|
||||
|
||||
开发者有问题或者好的建议可以用Issues反馈交流,请给出详细信息,本人会尽可能解决。
|
||||
* 如果问题是共性问题(如代码bug或文档不全),本人会及时解决。
|
||||
@@ -183,8 +145,7 @@ V 3.0.0 完成以下目标:
|
||||
* 请查看相关技术的官方文档,例如微信小程序的官方文档;
|
||||
* 请提问前尽可能做一些DEBUG或者思考分析,然后提问时给出详细的错误相关信息以及个人对问题的理解。
|
||||
|
||||
贡献
|
||||
==
|
||||
## 贡献
|
||||
|
||||
任何形式的贡献都欢迎,查看[贡献指南](CONTRIBUTE.md)
|
||||
|
||||
@@ -195,7 +156,6 @@ V 3.0.0 完成以下目标:
|
||||
> * 在开发交流群中应讨论开发、业务和合作问题。
|
||||
> * 交流结果如果是共识性的则在文档中记录,如果是开放性的则会在Issue中记录。
|
||||
|
||||
相关项目
|
||||
====
|
||||
## 相关项目
|
||||
|
||||
[HubertYoung](https://github.com/HubertYoung)正在开发Android端[Litemall-Android](https://github.com/HubertYoung/Litemall-Android)
|
||||
3
deploy/.gitignore
vendored
3
deploy/.gitignore
vendored
@@ -2,5 +2,6 @@
|
||||
/litemall-os-api/litemall-os-api.jar
|
||||
/litemall-wx-api/litemall-wx-api.jar
|
||||
/litemall-admin/dist.tar
|
||||
/litemall-db/litemall.sql
|
||||
/litemall-db/litemall_schema.sql
|
||||
/litemall-db/litemall_table.sql
|
||||
/litemall-db/litemall_data.sql
|
||||
|
||||
@@ -20,7 +20,8 @@ fi
|
||||
|
||||
cd /home/ubuntu/deploy/litemall-db
|
||||
cat litemall_schema.sql > db.sql
|
||||
cat litemall.sql >> db.sql
|
||||
cat litemall_table.sql >> db.sql
|
||||
cat litemall_data.sql >> db.sql
|
||||
mysql -h localhost -u $ROOT -p$PASSWORD < db.sql
|
||||
rm db.sql
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ tar -zcvf ./deploy/litemall-admin/dist.tar -C ./litemall-admin/dist .
|
||||
|
||||
# 复制数据库
|
||||
cp -f ./litemall-db/sql/litemall_schema.sql ./deploy/litemall-db/litemall_schema.sql
|
||||
cp -f ./litemall-db/sql/litemall.sql ./deploy/litemall-db/litemall.sql
|
||||
cp -f ./litemall-db/sql/litemall_table.sql ./deploy/litemall-db/litemall_table.sql
|
||||
cp -f ./litemall-db/sql/litemall_data.sql ./deploy/litemall-db/litemall_data.sql
|
||||
|
||||
# 上传云主机
|
||||
scp -i $ID_RSA -r ./deploy $REMOTE:/home/ubuntu/
|
||||
|
||||
219
doc/1.md
219
doc/1.md
@@ -9,27 +9,46 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
|
||||
项目的架构是三个系统和六个模块:
|
||||
|
||||
* 基础系统(core),由数据库、litemall-cre模块、litemall-db模块、litemall-os-api模块和litemall-all模块组成;
|
||||
* 小商场系统(wxmall),由litemall-wx-api模块和litemall-wx模块组成;
|
||||
* 后台管理系统(admin),由litemall-admin-api模块和litemall-admin模块组成。
|
||||
* 简单商城系统(mall),这里仅列出,目前没有开发计划。
|
||||
* 基础系统子系统(core)
|
||||
|
||||
由数据库、litemall-cre模块、litemall-db模块、litemall-os-api模块和litemall-all模块组成;
|
||||
|
||||
* 小商场子系统(wxmall)
|
||||
|
||||
由litemall-wx-api模块和litemall-wx模块组成;
|
||||
|
||||
* 后台管理子系统(admin)
|
||||
|
||||
由litemall-admin-api模块和litemall-admin模块组成。
|
||||
|
||||
* 简单商城系统(mall)
|
||||
|
||||
这里仅列出,目前没有开发计划。
|
||||
|
||||
而六个模块的开发设计到三种技术栈:
|
||||
|
||||
* Spring Boot技术栈,采用IDEA开发工具,开发litemall-core、litemall-db、litemall-all、
|
||||
* Spring Boot技术栈
|
||||
|
||||
采用IDEA开发工具,开发litemall-core、litemall-db、litemall-all、
|
||||
litemall-os-api、litemall-admin-api和litemall-wx-api共六个个模块;
|
||||
* miniprogram(微信小程序)技术栈,采用微信小程序开发工具,开发litemall-wx模块;
|
||||
* Vue技术栈,采用VSC开发工具,开发litemall-admin模块。
|
||||
|
||||
* miniprogram(微信小程序)技术栈
|
||||
|
||||
采用微信小程序开发工具,开发litemall-wx模块;
|
||||
|
||||
* Vue技术栈
|
||||
|
||||
采用VSC开发工具,开发litemall-admin模块。
|
||||
|
||||
## 1.2 系统功能
|
||||
|
||||
从业务功能上,目前由五个业务模块(参考nideshop-mini-program和platform)组成:
|
||||
从业务功能上,目前由五个业务模块组成:
|
||||
|
||||
* 会员业务模块
|
||||
* 商场业务模块
|
||||
* 商品业务模块
|
||||
* 推广业务模块
|
||||
* 系统业务模块(仅管理平台)
|
||||
* 系统业务模块
|
||||
|
||||
### 1.2.1 小程序端功能
|
||||
|
||||
@@ -55,21 +74,16 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
* 地址添加
|
||||
* 我的收藏
|
||||
* 我的足迹
|
||||
* 支付页面(待定)
|
||||
* 优惠券选择(待定)
|
||||
* 我的优惠券(待定)
|
||||
* 支付页面
|
||||
|
||||
### 1.2.2 管理平台功能
|
||||
|
||||
* 会员管理
|
||||
* 会员管理
|
||||
* 收货地址管理
|
||||
* 收货地址
|
||||
* 会员收藏
|
||||
* 会员足迹
|
||||
* 搜索历史
|
||||
* 购物车
|
||||
* 会员等级(待定)
|
||||
* 会员优惠劵(待定)
|
||||
* 商城管理
|
||||
* 区域配置
|
||||
* 品牌制造商
|
||||
@@ -79,17 +93,13 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
* 关键词
|
||||
* 渠道管理(待定)
|
||||
* 商品管理
|
||||
* 商品管理
|
||||
* 商品参数
|
||||
* 商品规格
|
||||
* 货品管理
|
||||
* 商品列表
|
||||
* 商品上架
|
||||
* 商品编辑
|
||||
* 用户评论
|
||||
* 团购设置(待定)
|
||||
* 商品满减搭配(待定)
|
||||
* 推广管理
|
||||
* 广告列表
|
||||
* 广告管理
|
||||
* 专题管理
|
||||
* 优惠劵管理(待定)
|
||||
* 系统管理
|
||||
* 管理员
|
||||
* 对象存储
|
||||
@@ -171,7 +181,9 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
|
||||
最后,其实dep和prod不存在先后关系。例如,如果开发者已经存在域名和生产环境,可以直接
|
||||
跳过dep阶段,而直接部署在线上环境中。因此有些时候,这里部署和上线是一个阶段。
|
||||
|
||||
当然,这里仍然建议先dep后prod,是因为对于第一次开发而言,先dep阶段可以避免对域名、https证书等非业务相关工作的干扰。
|
||||
|
||||
此外,有些业务功能(例如微信支付)必须是域名访问,那么开发和部署阶段可以先采用模拟或跳过的形式,
|
||||
先不开发和测试这样业务功能,等其他功能开发完毕和部署测试成功以后,再来开发这些线上环境才能
|
||||
运行的功能,此时会有一个好的基础。
|
||||
@@ -211,19 +223,13 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
### 1.4.0 数据库
|
||||
|
||||
按照开发环境前,需要先在本地配置好数据库:
|
||||
1. 本项目目前采用MySQL,请上网下载安装MySQL 5.7.x
|
||||
|
||||
注意:
|
||||
> 1. MySQL必须安装5.7.x, 如果是5.6或者最新的8.0都会存在错误。
|
||||
> 目前原因还没有找到(可能是采用JSON引起),希望开发者注意或者有好的解决方案。
|
||||
> 2. 如果采用IDE工具导入数据,建议采用MySQL Workbench。如果采用navicat可能有时导入失败。
|
||||
> 这里失败的原因应该是sql文件是MySQL Workbench导出的,因此可能存在不兼容的格式。
|
||||
1. 本项目目前采用MySQL
|
||||
|
||||
注意:建议采用命令行或者MySQL Workbench。如果采用navicat可能导入失败。
|
||||
|
||||
2. 数据库文件存放在litemall-db/sql文件夹中,其中litemall_schema.sql创建数据库和用户权限,
|
||||
而litemall.sql则是具体的表和数据。开发者可以采用命令或者软件导入数据。
|
||||
|
||||
注意:
|
||||
> 不要运行nideshop.sql文件,这只是所参考nideshop项目的原始数据库,仅用于对比。
|
||||
litemall_table.sql则创建表,litemall_data.sql则是测试数据。
|
||||
|
||||
### 1.4.1 Spring Boot开发环境
|
||||
|
||||
@@ -339,11 +345,9 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
> 原因是这里的appid是本人申请的,而开发者不是本人app的开发者或体验者,
|
||||
> 因此微信登录导致后台服务向微信服务器交互时会失败。
|
||||
> 2. 有的开发者可能认为把litemall-wx模块的appid设置成开发者自己的appid就可以,
|
||||
> 但是实际上,由于小商场的云主机后台服务的appid仍然是本人appid,
|
||||
> 因此微信登录时仍然会失败。
|
||||
> 但是由于小商场的云主机后台服务的appid仍然是本人appid,因此微信登录时仍然会失败。
|
||||
> 3. 开发者可以在litemall-wx和litemall-wx-api中设置自己的appid,以及部署自己的后台服务,
|
||||
> 相关内容请阅读章节3。
|
||||
> 或者,开发者可以采用账号登录的方式登录后台服务,然后体验商品购买下单的方式。
|
||||
> 相关内容请阅读章节3。或者,开发者可以采用账号登录方式登录,然后体验商品购买下单的方式。
|
||||
> 4. 由于没有设置商户支付信息,因此开发者在付款时会失败。相关内容阅读章节3。
|
||||
|
||||
### 1.4.3 Vue开发环境
|
||||
@@ -356,6 +360,7 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
```
|
||||
cnpm install
|
||||
```
|
||||
|
||||
5. 编译并运行
|
||||
|
||||
```
|
||||
@@ -363,6 +368,7 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
```
|
||||
然后,打开浏览器,输入`http://localhost:9527`。
|
||||
如果出现管理后台登录页面,则表明管理后台的前端运行正常;
|
||||
|
||||
6. 请确定litemall-admin-api模块已经运行,然后点击`登录`,如果能够成功登录,则表明管理后台的前端和后端对接成功,运行正常。
|
||||
|
||||
## 1.5 部署方案
|
||||
@@ -379,11 +385,6 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
* litemall-wx模块部署在微信开发者工具中,此外数据API地址指向litemall-wx-api所在服务qi地址
|
||||
* litemall-admin编译出的静态文件放在web服务器或者tomcat服务器,此外服务器地址设置指向3中litemall-admin-api所在地址
|
||||
|
||||
注意
|
||||
> * 这里litemall-os-api、litemall-admin-api和litemall-wx-api也可以选择编译成jar模式的可执行文件(因为内嵌tomcat服务器),然后直接运行。
|
||||
> * litemall-wx部署时可以放在微信开发者工具中测试,但是上线时必须设置https开头的合法域名,因此litemall-wx-api所在的服务器需要配置合适的域名和SSL证书,
|
||||
> 具体参见官方文档和本项目的1.6节。
|
||||
|
||||
最后,**如果项目部署,则根据开发者的部署环境在以下文件中或代码中修改相应的配置。**
|
||||
|
||||
1. MySQL数据库设置合适的用户名和密码等信息,同时在litemall-os-api、litemall-wx-api和litemall-admin-api模块
|
||||
@@ -414,8 +415,10 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
|
||||
以下简单列举几种方案。
|
||||
|
||||
### 1.5.3 基于ubuntu腾讯云的单机云部署方案
|
||||
单机云部署方案,面向的是服务器数据和应用部署在云主机单机中用于演示的场景。
|
||||
### 1.5.3 单机云部署方案
|
||||
|
||||
本节介绍基于腾讯云的单机云部署方案,面向的是服务器数据和应用部署在云主机单机中用于演示的场景。
|
||||
其他云应该也是可行的。
|
||||
|
||||
主要流程是:创建云主机,安装ubuntu操作系统,按照JDK和MySQL应用运行环境,部署三个Spring Boot微服务后台应用,
|
||||
以及部署管理后台静态文件到tomcat。
|
||||
@@ -449,6 +452,7 @@ litemall是一个简单的商场系统,基于现有的开源项目,重新实
|
||||
#### 1.5.3.2 JDK8
|
||||
|
||||
https://www.digitalocean.com/community/tutorials/how-to-install-java-with-apt-get-on-ubuntu-16-04
|
||||
|
||||
http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html
|
||||
|
||||
```bash
|
||||
@@ -464,7 +468,6 @@ sudo apt-get install oracle-java8-set-default
|
||||
#### 1.5.3.3 MySQL
|
||||
|
||||
https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04
|
||||
https://www.linuxidc.com/Linux/2017-01/139502.htm
|
||||
|
||||
```
|
||||
sudo apt-get update
|
||||
@@ -504,31 +507,34 @@ sudo apt-get install mysql-client
|
||||
|
||||
* 命令行导入
|
||||
|
||||
1. 采用FileZilla把本项目的litemall.sql上传到云主机
|
||||
2. 使用PuTTY登录云主机
|
||||
3. 进入MySQL,输入上节所设置的MySQL的root密码
|
||||
4. 创建数据库、 创建用户并分配访问权限
|
||||
5. 导入数据
|
||||
6. 退出
|
||||
1. 采用FileZilla把本项目的数据库文件上传到云主机
|
||||
2. 使用PuTTY登录云主机
|
||||
3. 进入MySQL,输入上节所设置的MySQL的root密码
|
||||
4. 创建数据库、 创建用户并分配访问权限
|
||||
5. 导入数据
|
||||
6. 退出
|
||||
|
||||
* MySQL Workbench导入
|
||||
|
||||
1. 先确认已经在1.4.3节中设置了root可以远程访问;
|
||||
2. 创建一个新的连接,设置`Hostname` 、`Username` 和`Password`,
|
||||
然后点击`Test Connection`测试是否能够连接到云主机;
|
||||
如果测试成功,则进入;
|
||||

|
||||
3. 开发者自行学习文档,完成`创建数据库`、`创建用户`和`分配权限`三个操作;
|
||||
4. 利用Workbench的`Server`菜单下的`Data Import`完成数据导入。
|
||||
1. 先确认已经在1.4.3节中设置了root可以远程访问;
|
||||
2. 创建一个新的连接,设置`Hostname` 、`Username` 和`Password`,
|
||||
然后点击`Test Connection`测试是否能够连接到云主机;
|
||||
如果测试成功,则进入;
|
||||

|
||||
3. 开发者自行学习文档,完成`创建数据库`、`创建用户`和`分配权限`三个操作;
|
||||
4. 利用Workbench的`Server`菜单下的`Data Import`完成数据导入。
|
||||
|
||||
* 命令脚本
|
||||
```bash
|
||||
cd deploy
|
||||
mysql -h localhost -u root -p123456
|
||||
source ./litemall-db/litemall_schema.sql
|
||||
source ./litemall-db/litemall.sql
|
||||
```
|
||||
其中123456是开发者所设置的MySQL的管理员密码。
|
||||
|
||||
```bash
|
||||
cd deploy
|
||||
mysql -h localhost -u root -p123456
|
||||
source ./litemall-db/litemall_schema.sql
|
||||
source ./litemall-db/litemall_table.sql
|
||||
source ./litemall-db/litemall_data.sql
|
||||
```
|
||||
|
||||
其中123456是开发者所设置的MySQL的管理员密码。
|
||||
|
||||
#### 1.5.3.5 Tomcat/Nginx
|
||||
|
||||
@@ -537,15 +543,15 @@ source ./litemall-db/litemall.sql
|
||||
因此这里需要安装tomcat或者nginx(或者其他服务器)。
|
||||
|
||||
这里可能有点绕:
|
||||
|
||||
1. 开发方案,无需tomcat/nginx,直接用VSC即可;
|
||||
2. 部署方案,采用tomcat,这里是因为80端口可能需要云主机备案;
|
||||
2. 部署方案,采用tomcat,这里是因为80端口可能需要云主机备案因此采用tomcat使用8080端口;
|
||||
3. 上线方案. 采用nginx,通过反向代理访问后台服务。
|
||||
|
||||
因此目前这里采用tomcat部署静态文件,通过8080端口访问管理后台。
|
||||
当然,这里没有严格限制,开发者也可以直接配置好nginx,在部署方案就使用nginx来
|
||||
部署静态文件服务,通过80web端口访问管理后台。
|
||||
部署静态文件服务,通过web端口80访问管理后台。
|
||||
|
||||
|
||||
* Tomcat部署静态文件
|
||||
|
||||
1. 安装tomcat
|
||||
@@ -581,10 +587,10 @@ source ./litemall-db/litemall.sql
|
||||
|
||||
1. 安装nginx
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install nginx
|
||||
```
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install nginx
|
||||
```
|
||||
|
||||
2. 配置nginx指向`delpoy/litemall-admin/dist`目录
|
||||
|
||||
@@ -597,36 +603,32 @@ source ./litemall-db/litemall.sql
|
||||
|
||||
#### 1.5.3.6 项目打包
|
||||
|
||||
这里项目打包括两种:
|
||||
|
||||
1. Spring Boot打包
|
||||
|
||||
通常项目打包方案存在两种:
|
||||
采用如下命令进行项目打包
|
||||
|
||||
* 一是打包war格式,因此云主机需要专门安装tomcat
|
||||
* 二是打包可执行jar格式,此时内部包含嵌入式tomcat
|
||||
```
|
||||
cd litemall
|
||||
mvn clean
|
||||
mvn package
|
||||
```
|
||||
|
||||
这里仅采用第二种方案,简化tomcat的安装配置过程。
|
||||
|
||||
采用如下命令进行项目打包
|
||||
|
||||
```
|
||||
cd litemall
|
||||
mvn clean
|
||||
mvn package
|
||||
```
|
||||
此时,在litemall-os-api项目的target文件夹中看到litemall-os-xxx.jar;
|
||||
在litemall-wx-api项目的target文件夹中看到litemall-wx-xxx.jar;
|
||||
在litemall-admin-api项目的target文件夹中看到litemall-admin-xxx.jar。
|
||||
此时,在litemall-os-api项目的target文件夹中看到litemall-os-xxx.jar;
|
||||
在litemall-wx-api项目的target文件夹中看到litemall-wx-xxx.jar;
|
||||
在litemall-admin-api项目的target文件夹中看到litemall-admin-xxx.jar。
|
||||
|
||||
2. Vue项目打包
|
||||
|
||||
采用如下命令进行项目打包
|
||||
采用如下命令进行项目打包
|
||||
|
||||
````bash
|
||||
cd litemall/litemall-admin
|
||||
cnpm run build:dep
|
||||
````
|
||||
````bash
|
||||
cd litemall/litemall-admin
|
||||
cnpm run build:dep
|
||||
````
|
||||
|
||||
此时,litemall-admin模块的dist文件夹中就是最终部署时的代码,可以先压缩,上传到云主机,再解压缩。
|
||||
此时,litemall-admin模块的dist文件夹中就是最终部署时的代码,可以先压缩,上传到云主机,再解压缩。
|
||||
|
||||
#### 1.5.3.7 项目部署运行
|
||||
|
||||
@@ -648,7 +650,8 @@ https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#dep
|
||||
cd deploy
|
||||
mysql -h localhost -u root -p123456
|
||||
source ./litemall-db/litemall_schema.sql
|
||||
source ./litemall-db/litemall.sql
|
||||
source ./litemall-db/litemall_table.sql
|
||||
source ./litemall-db/litemall_data.sql
|
||||
```
|
||||
注意,123456是开发者所设置的MySQL管理员密码
|
||||
警告:
|
||||
@@ -705,6 +708,7 @@ cd litemall
|
||||
### 1.5.4 集群式云部署方案
|
||||
|
||||
由于本项目是面向微小型企业的小商城系统,因此预期的分布式部署方案是
|
||||
|
||||
1. 专门的云数据库部署数据
|
||||
2. 专门的云存储方案
|
||||
3. 专门的CDN分发管理后台的静态文件
|
||||
@@ -718,19 +722,21 @@ cd litemall
|
||||
至少每个功能模块应该是独立服务系统。此外,需要引入单点登录系统、集群、缓存
|
||||
和消息队列等多种技术。因此如果开发者需要这种形式的分布式方案,请参考其他项目。
|
||||
|
||||
### 1.5.5 单主机单服务war部署方案
|
||||
### 1.5.5 war部署方案
|
||||
|
||||
这里介绍另外一种单主机单服务的方案,即四个服务打包成一个war格式的项目部署包。
|
||||
这里介绍另外一种单主机单服务的war部署方案,即四个服务打包成一个war格式的项目部署包。
|
||||
|
||||

|
||||
|
||||
和1.5.3节相比,采用这样方案的原因是:
|
||||
|
||||
1. 安装方便,是传统的web项目安装方式,在tomcat里面部署一个war项目包,即可完成安装;
|
||||
2. 内存消耗少。在1.5.3节中四个独立的java环境消耗的内存大概1.2G多,而这里部署以后
|
||||
只需要一个java环境,因此消耗内存只有1.5.3节方案的四分之一,适合1G云主机部署。
|
||||
3. 只存在一个域名和端口,没有多个服务之间依赖关系。
|
||||
|
||||
具体的打包部署方案是;
|
||||
|
||||
1. litemall-admin首先需要先编译得到静态文件;
|
||||
2. 采用`mvn package`命令,litemall-all模块自动生成war格式的安装包,里面
|
||||
包含了三个后台服务和静态文件;
|
||||
@@ -746,6 +752,7 @@ cd litemall
|
||||
## 1.6 上线方案
|
||||
|
||||
在1.5节部署方案中,我们介绍了多种部署的方案,但是实际上这些方案都不能立即用于正式环境:
|
||||
|
||||
1. 正式环境需要域名和HTTPS证书
|
||||
2. 小商场的小程序端对服务器域名存在接入要求。
|
||||
|
||||
@@ -917,7 +924,7 @@ http://www.example.com
|
||||
> 本人对nginx也不了解,仅仅依靠网络知识配置了简单的效果。
|
||||
> 更多配置方法和功能,请开发者自行学习。
|
||||
|
||||
### 1.6.3 小商场的小程序端上线
|
||||
### 1.6.3 小程序端上线
|
||||
|
||||
这里参考小程序官方文档,上线自己的小商城。
|
||||
|
||||
@@ -965,7 +972,7 @@ http://www.example.com
|
||||
|
||||
### 1.6.5 上线脚本
|
||||
|
||||
本项目的deploy文件夹是用于
|
||||
本项目目前没有上线脚本,不过可以参考1.5.3节中的部署脚本。
|
||||
|
||||
### 1.6.6 优化
|
||||
|
||||
@@ -976,10 +983,18 @@ http://www.example.com
|
||||
如果部署方案中采用tomcat而8080端口访问后台,而这里配置nginx后,
|
||||
可以直接采用80端口访问,因此tomcat可以卸载。
|
||||
|
||||
#### 1.6.6.2 静态文件托管CDN
|
||||
#### 1.6.6.2 管理后台前端文件启动优化
|
||||
|
||||
在上节中,建议采用卸载tomcat,采用nginx托管管理后台的静态文件。
|
||||
这里可以进一步地,把静态文件托管到CDN,当然这里是需要收费。
|
||||
litemall-admin编译得到的前端文件在第一次加载时相当耗时,这里需要一些措施来优化启动速度
|
||||
|
||||
* 静态文件托管CDN
|
||||
|
||||
在上节中,建议采用卸载tomcat,采用nginx托管管理后台的静态文件。
|
||||
这里可以进一步地,把静态文件托管到CDN,当然这里是需要收费。
|
||||
|
||||
* gzip压缩
|
||||
|
||||
* 动态加载
|
||||
|
||||
#### 1.6.6.3 后台服务内部访问
|
||||
|
||||
|
||||
168
doc/2.md
168
doc/2.md
@@ -1,13 +1,20 @@
|
||||
# 2 litemall基础平台
|
||||
# 2 litemall基础系统
|
||||
|
||||
目前litemall基础系统主要由litemall数据库、litemall-core模块、litemall-db模块、
|
||||
litemall-os-api模块和litemall-all模块组成。
|
||||
目前litemall基础系统由以下部分组成:
|
||||
|
||||
* litemall数据库
|
||||
* litemall-core模块
|
||||
* litemall-db模块、
|
||||
* litemall-os-api模块
|
||||
* litemall-all模块组成
|
||||
|
||||
实际上,litemall**真正的基础系统**是litemall-core模块和litemall-db模块。
|
||||
|
||||
实际上,属于litemall**真正的基础系统**是litemall-core模块和litemall-db模块。
|
||||
litemall-os-api模块只是为了减少开发中对第三方图片存储服务依赖而实现的简单图像存储服务,
|
||||
建议开发者最终部署时切换到第三方图片存储服务。litemall-all模块只是一个包裹模块,
|
||||
没有任何代码,其作用是融合三个spring boot模块和litemall-adminm模块静态文件到
|
||||
一个单独spring boot应用中,并最终打包成war格式的项目安装包。
|
||||
建议开发者最终部署时切换到第三方图片存储服务。
|
||||
|
||||
litemall-all模块则只是一个包裹模块,几乎没有任何代码。该模块的作用是融合三个spring boot模块
|
||||
和litemall-admin模块静态文件到一个单独spring boot应用中,并最终打包成war格式的项目安装包。
|
||||
|
||||
目前存在的问题:
|
||||
|
||||
@@ -15,19 +22,43 @@ litemall-os-api模块只是为了减少开发中对第三方图片存储服务
|
||||
* `改善` litemall-db的一些CRUD操作可以基于开源库重构
|
||||
* `功能`可以参考一些云存储服务的API加强一些功能
|
||||
|
||||
## 2.1 litemall.sql
|
||||
## 2.1 litemall数据库
|
||||
|
||||
litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumobi/nideshop/blob/master/nideshop.sql)数据库,然后在实际开发过程中进行了调整和修改:
|
||||
litemall数据库基于nideshop中的[nideshop.sql](https://github.com/tumobi/nideshop/blob/master/nideshop.sql)数据库,然后在实际开发过程中进行了调整和修改:
|
||||
|
||||
* 删除了一些目前不必要的表;
|
||||
* 删除了表中一些目前不必要的字段;
|
||||
* 行政区域数据litemall_region没有采用原nideshop中的数据,而是采用了[Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China);
|
||||
* 表中的某些字段采用JSON;
|
||||
* 表中的某些字段采用JSON存储;
|
||||
* 表中的日期或时间字段采用DATE、DATETIME;
|
||||
* 字段的数据类型粗粒度化,例如避免MEDIUMINT,而是INT;
|
||||
* 表的数据做了清理、调整和补充(假数据)。
|
||||
|
||||
具体不同可以比较litemall-db模块下sql文件夹中nideshop.sql和litemall.sql。
|
||||
litemall数据库由三个sql文件组成,在litemall-db文件夹下面的sql文件夹中:
|
||||
|
||||
1. litemall_schema.sql
|
||||
|
||||
作用是创建空数据库、创建用户、设置访问权限。
|
||||
|
||||
开发者开发测试阶段可以使用,但是部署生产阶段一定要注意修改这里的默认用户名和密码。
|
||||
|
||||
注意,这里的sql文件不一定需要运行,开发者可以自己手动或命令行或IDE进行对应的操作即可。
|
||||
|
||||
2. litemall_table.sql
|
||||
|
||||
作用是创建数据库表,但是没有创建任何数据。
|
||||
|
||||
因此,开发者可以在部署生产阶段直接使用。
|
||||
|
||||
3. litemall_data.sql
|
||||
|
||||
作用是创建测试数据。
|
||||
|
||||
这里的测试数据来自开源项目[nideshop-mini-program](https://github.com/tumobi/nideshop-mini-program)
|
||||
|
||||
开发者开发测试阶段可以使用,但是部署开发阶段应该使用自己的数据。
|
||||
|
||||
综上,这里litemall真正必须运行的sql文件是litemall_table.sql,其他两个sql文件开发者自行决定如何是否使用。
|
||||
|
||||
以下讨论一些关键性设计
|
||||
|
||||
@@ -36,7 +67,7 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
|
||||
### 2.1.1 商品和货品设计
|
||||
|
||||
这里商品存在商品,商品属性,商品规格,货品四种表
|
||||
这里商品存在商品表(litemall_goods),商品属性表(litemall_goods_attribute),商品规格表(litemall_goods_specification),商品货品表(litemall_product)四种表
|
||||
|
||||
商品表是一种商品的基本信息,主要包括商品介绍,商品图片,商品所属类目,商品品牌商等;
|
||||
|
||||
@@ -53,9 +84,10 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
* 多个规格和单一规格值,可以简化成第一种情况,或者采用第四种情况,通常实际情况下不常见;
|
||||
* 多个规格和多个规格值,通常是两种规格或者三种规格较为常见,而且对应的价格不完全相同。
|
||||
|
||||
货品则是最终面向开发者购买的商品标识,存在多个规格值、数量和价格。
|
||||
商品货品则是最终实现商品库存管理、购买业务的实体对象,存在多个规格值、数量和价格。
|
||||
例如,同样的衣服品牌,可能因为不能尺寸和颜色而存在最终的货品,这里每个货品的价格可以一样,也可以不一样。
|
||||
|
||||
因此这里一个商品表项,存在(至少0个)多个商品属性表项目,存在(至少一个)多个商品规格表项,
|
||||
总结一下,一个普通商品,实际上在数据库中,存在一个商品表项,存在(至少0个)多个商品属性表项目,存在(至少一个)多个商品规格表项,
|
||||
存在(至少一个)多个货品表项。
|
||||
|
||||
举例如下:
|
||||
@@ -64,7 +96,7 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
* 存在两个商品参数,
|
||||
* 属性名称“面向人群”,属性值“男士”
|
||||
* 属性名称“面料”,属性值“100%棉”
|
||||
* 存在两种规格共八个商品规格项,
|
||||
* 存在两种规格(分别五个规格值和三个规格值)共八个商品规格项,
|
||||
* 规格名称“尺寸”,规则值“S”
|
||||
* 规格名称“尺寸”,规则值“M”
|
||||
* 规格名称“尺寸”,规则值“L”
|
||||
@@ -102,8 +134,7 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
* 商品规格可以存在规格图片,效果是规格名称前放置规格图片
|
||||
* 货品也可以存在货品图片,效果是所有规格选定以后对应的货品有货,则在货品价格前放置货品图片
|
||||
* 如果商品是两种规格,分别是M个和N个规格值,那么通常应该是`M*N`个货品,但是有些货品可能天然不存在。
|
||||
那么,此时数据库如何来设计,是允许少于`M*N`个项,还是必须等于`M*N`个,而不存在货品的数量设置为0?
|
||||
*
|
||||
目前这里要求所有货品信息都应该存在,如果实际中货品不存在,也要设置商品数量为0.
|
||||
|
||||
注意:
|
||||
|
||||
@@ -112,7 +143,9 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
|
||||
### 2.1.2 用户和微信用户设计
|
||||
|
||||
目前准备支持用户普通账号登录和微信登录两种方式,两种登录方式仅仅采用一个litemall-user表可能不是很合适。此外,如果进一步支持其他多种第三方登录,那么这里需要重新设计。
|
||||
目前准备支持用户普通账号登录和微信登录两种方式,两种登录方式仅仅采用一个litemall-user表可能不是很合适。
|
||||
|
||||
外,如果进一步支持其他多种第三方登录,那么这里需要重新设计。
|
||||
|
||||
### 2.1.3 行政区域设计
|
||||
|
||||
@@ -199,16 +232,16 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
注意:
|
||||
> 1. 目前退款相关功能未完成。
|
||||
> 2. 在上图中可以看到`101`到`101`的状态变化,这里只是小商场用户的操作,不会影响订单状态码。
|
||||
> * 用户点击付款时,后台服务会生成预支付会话id,但是不会影响订单状态。
|
||||
> * 而用户支付过程中,放弃支付,例如没有
|
||||
> 如果用户点击付款时,后台服务会生成预支付会话id,但是不会影响订单状态。
|
||||
> 如果而用户支付过程中,放弃支付,则也不会影响订单状态。
|
||||
|
||||
#### 2.1.4.2 状态变化所对应的流程
|
||||
|
||||
* -> 101
|
||||
* 初始 -> 101
|
||||
|
||||
小商场用户在小商场点击`下单`按钮,此时小商城后台服务会生产商户订单。
|
||||
|
||||
所对应的后台服务方法是litemall-wx-api模块的`WxOrderController.submit`
|
||||
所对应的后台服务方法是litemall-wx-api模块的`WxOrderController.submit`方法。
|
||||
|
||||
* 101 -> 101
|
||||
|
||||
@@ -332,6 +365,7 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
用户可以`确认收货`
|
||||
|
||||
* 401
|
||||
|
||||
用户可以`退货`、`删除`、`去评价`、`再次购买`
|
||||
|
||||
* 402
|
||||
@@ -373,8 +407,7 @@ litemall.sql数据库基于nideshop中的[nideshop.sql](https://github.com/tumob
|
||||
|
||||
## 2.2 litemall-db
|
||||
|
||||
litemall-db模块是一个普通的Spring Boot应用,基于mybatis技术提供开发者
|
||||
访问数据库的功能。
|
||||
litemall-db模块是一个普通的Spring Boot应用,基于mybatis框架实现数据库访问操作,对外提供业务数据访问服务。
|
||||
|
||||
此外,litemall-db最终是作为一个类库被其他模块所依赖使用,因此并不对外
|
||||
直接服务,没有使用Spring MVC技术。
|
||||
@@ -392,13 +425,26 @@ litemall-db模块是一个普通的Spring Boot应用,基于mybatis技术提供
|
||||
|
||||
这里litemall-db模块可以分成以下几种代码:
|
||||
|
||||
* mybatis generator自动化代码
|
||||
* mybatis数据库访问代码
|
||||
* generator生成代码
|
||||
* 非generator手动代码
|
||||
* 业务代码
|
||||
* 安全代码
|
||||
* JSON支持代码
|
||||
* 配置代码
|
||||
|
||||
### 2.2.1 自动化代码
|
||||
### 2.2.1 mybatis数据库访问代码
|
||||
|
||||
mybatis数据库访问代码是指dao接口代码、dao数据库XML文件和domain代码:
|
||||
* dao接口代码,声明了数据库访问接口
|
||||
* dao数据库XML文件,实现了数据库访问操作
|
||||
* domain代码,则是保存数据库返回数据。
|
||||
|
||||
此外,这里的数据库访问代码又进一步分成
|
||||
* generator生成代码,即基于mybatis generator相关插件自动生成上述三种代码或文件;
|
||||
* 非generator手动代码,则是需要开发者自己编写上述三种代码。
|
||||
|
||||
#### 2.2.1.1 generator生成代码
|
||||
|
||||

|
||||
|
||||
@@ -407,7 +453,7 @@ litemall-db模块是一个普通的Spring Boot应用,基于mybatis技术提供
|
||||
1. 读取`mybatis-generator`文件夹下的`generatorConfig.xml`文件
|
||||
2. 根据`jdbcConnection`访问数据库
|
||||
3. 根据`table`, 自动生成三种代码:
|
||||
* src文件夹`org.linlinjava.litemall.db.domain` 包内的Java代码
|
||||
* src文件夹`org.linlinjava.litemall.db.dao` 包内的Java代码
|
||||
* src文件夹`org.linlinjava.litemall.db.domain` 包内的Java代码
|
||||
* resources文件夹`org.linlinjava.litemall.db.domain.dao` 内的XML文件
|
||||
|
||||
@@ -460,9 +506,38 @@ litemall-db模块是一个普通的Spring Boot应用,基于mybatis技术提供
|
||||
关于mybatis generator的用法,可以参考:
|
||||
https://blog.csdn.net/isea533/article/details/42102297
|
||||
|
||||
#### 2.2.1.2 非generator手动代码
|
||||
|
||||
虽然generator可以自动生产代码,帮助开发者简化开发工作,但是在涉及到多表操作或特殊数据库操作时,
|
||||
仍然需要开发者自己手动编写mybatis框架代码。
|
||||
|
||||
具体如何基于mybatis框架编写代码,请开发者自己查找资料。
|
||||
|
||||
这里,以统计功能举例说明:
|
||||
|
||||
1. dao代码
|
||||
|
||||
在src文件夹`org.linlinjava.litemall.db.domain` 包内的StatMapper.java代码定义了数据库访问的接口
|
||||
|
||||
2. domain代码
|
||||
|
||||
如果希望数据库操作返回数据模型,可以在src文件夹`org.linlinjava.litemall.db.domain` 包内创建相应代码。
|
||||
而这里统计功能是采用简化的`List<Map>`保存数据,没有定义domain代码。
|
||||
|
||||
3. XML文件
|
||||
|
||||
在resources文件夹`org.linlinjava.litemall.db.domain.dao` 内的StatMapper.xml文件则是实现真正的数据库访问操作。
|
||||
|
||||
|
||||
### 2.2.2 业务代码
|
||||
|
||||
基于2.2.1的代码,业务代码处理一些具体业务相关的操作,对其他模块提供具体的服务。
|
||||
虽然2.2.1节所述代码已经能够提供数据库访问操作,但是这里仍然会抽象出业务访问层代码,即基于2.2.1所述代码和实际业务需求
|
||||
实现一些具体业务相关的操作,对其他模块提供便捷业务数据服务。
|
||||
|
||||
需要指出的是,这里的业务代码往往是单表相关的业务代码,而涉及到多表操作的java代码通常是在其他高层模块中实现。
|
||||
这里的业务分层并不是绝对的。例如,开发者可以取消这里的业务代码,而在其他模块中直接调用2.2.1所述代码。
|
||||
|
||||
通常业务层代码在src文件夹`org.linlinjava.litemall.db.service` 包中。
|
||||
|
||||
### 2.2.3 安全代码
|
||||
|
||||
@@ -562,12 +637,16 @@ https://blog.csdn.net/isea533/article/details/42102297
|
||||
|
||||
开发者可以自行修改代码进行真正的物理删除。
|
||||
|
||||
### 2.2.8 乐观锁
|
||||
### 2.2.8 并发访问
|
||||
|
||||
由于服务是多线程并发的,因此这带来了多线程同时操作数据库中同一数据的问题。
|
||||
由于数据极少删除或者是逻辑删除,因此操作数据,可以简化成更新数据。
|
||||
也就是说,需要解决多线程更新数据库同一数据的并发问题。
|
||||
|
||||
* https://blog.csdn.net/qq315737546/article/details/76850173
|
||||
* http://baijiahao.baidu.com/s?id=1571172971189129
|
||||
* https://blog.csdn.net/speedme/article/details/48525119
|
||||
|
||||
例如,下单操作中,用户A购买商品G的数量是1个,而用户B同一时间也购买商品G的
|
||||
数量也是1个,那么如果没有很好地并发控制,有可能商品G的数量仅仅是减1,而不是
|
||||
设想的2。
|
||||
@@ -583,14 +662,6 @@ https://blog.csdn.net/isea533/article/details/42102297
|
||||
* 如果相同,说明数据没有改变则可以更新,数据更新同时version调整一个新值;
|
||||
* 如果不相同,则说明数据改变了则更新失败,不能修改数据。
|
||||
|
||||
当然,这里好像也存在一个漏洞,3中所比较的数据库当前version字段的值有可能修改过
|
||||
但是恰巧没有变。例如version加1再减1,那么查询时该值并没有变化。当然,如果version
|
||||
是单调自增,则应该不存在这个问题。
|
||||
|
||||
具体技术细节如下:
|
||||
|
||||
1.
|
||||
|
||||
当然,由于采用乐观锁,这里也会带来另外一个问题:
|
||||
数据库有可能更新失败,那么如何处理更新失败的情况?
|
||||
|
||||
@@ -605,7 +676,25 @@ https://blog.csdn.net/isea533/article/details/42102297
|
||||
|
||||
开发者需要注意这个问题,可能需要采用其他技术来解决或避免。
|
||||
|
||||
### 2.2.9 mybatis增强框架
|
||||
### 2.2.9 事务管理
|
||||
|
||||
litemall-db模块中不涉及到事务管理,而是在其他后台服务模块中涉及。
|
||||
但是其他后台服务模块因为依赖litemall-db模块,因此这里列出。
|
||||
|
||||
事务管理的问题出现在多个表的修改操作中。
|
||||
|
||||
例如用户A修改表1,再修改表2,而如果修改表2的时候出现错误推出,
|
||||
此时如果没有引入事务管理,那么这里会存在表1数据已跟新,表2数据
|
||||
未更新的问题。
|
||||
|
||||
解决的方案是采用spring自带的事务管理机制。
|
||||
当事务管理中的任何SQL操作出现错误而抛出异常时,则回滚之前的操作。
|
||||
|
||||
注意:
|
||||
> 并发访问是多个用户同时操作单个表时可能出现的问题;
|
||||
> 而事务管理是单个用户操作多个表时可能出现的问题。
|
||||
|
||||
### 2.2.10 mybatis增强框架
|
||||
|
||||
通过mybatis-generator已经自动生成了很多代码,而且具有一定的功能,
|
||||
但是开发者仍然需要基于生成的代码写一些固定的CRUD代码。
|
||||
@@ -757,5 +846,4 @@ bcypt代码本质上是spring里面的代码。
|
||||
注意,这里只是简单的复制。因此开发者需要保证litemall-all打包前,litemall-admin
|
||||
模块内dist目录下静态文件已经生成。
|
||||
|
||||
最终打包以后则是一个war格式的项目包,包含了三个后台服务和静态文件。
|
||||
|
||||
最终打包以后则是一个war格式的项目包,包含了三个后台服务和静态文件。
|
||||
68
doc/3.md
68
doc/3.md
@@ -94,6 +94,8 @@ wx.app-secret=开发者申请的app-secret
|
||||
|
||||
## 3.1 litemall-wx-api
|
||||
|
||||
本节介绍小商场的后台服务模块。
|
||||
|
||||
### 3.1.1 授权服务
|
||||
|
||||
#### 3.1.1.1 账号登录
|
||||
@@ -266,7 +268,7 @@ wx.app-secret=开发者申请的app-secret
|
||||
|
||||
### 3.1.16 安全
|
||||
|
||||
#### 3.1.161 Token
|
||||
#### 3.1.16.1 Token
|
||||
|
||||
用户登录成功以后,后端会返回`token`,之后用户的请求都会携带token。
|
||||
|
||||
@@ -389,30 +391,36 @@ var WxApiRoot = 'http://localhost:8082/wx/';
|
||||
|
||||
### 3.2.2 页面
|
||||
|
||||
#### 3.2.2.1 首页
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
#### 3.2.2.
|
||||
|
||||
* 首页
|
||||
* 专题页
|
||||
* 专题详情页
|
||||
* 专题评论页
|
||||
* 专题评论添加页
|
||||
* 品牌页
|
||||
* 品牌详情页
|
||||
* 人气推荐页
|
||||
* 新品首发页
|
||||
* 分类页
|
||||
* 分类详情页
|
||||
* 查找页
|
||||
* 商品详情页
|
||||
* 商品评论页
|
||||
* 购物车页
|
||||
* 下单页
|
||||
* 下单地址页
|
||||
* 下单地址添加页
|
||||
* 支付结果页
|
||||
* 个人页
|
||||
* 订单列表页
|
||||
* 订单详情页
|
||||
* 优惠券页
|
||||
* 收藏页
|
||||
* 足迹页
|
||||
* 收货地址页
|
||||
* 收货地址添加页
|
||||
* 登录页
|
||||
* 注册页
|
||||
* 找回密码页
|
||||
|
||||
### 3.2.3 登录设计
|
||||
|
||||
@@ -489,16 +497,6 @@ var WxApiRoot = 'http://localhost:8082/wx/';
|
||||
});
|
||||
```
|
||||
|
||||
#### 3.2.2.4 登录拒绝授权
|
||||
|
||||
还存在一个问题,当用户登录时,会出现"微信授权"的对话框。
|
||||
如果用户选择”拒绝“,那么之后用户的登录操作总是失败的。
|
||||
|
||||
目前的做法是,用户拒绝授权后,如果再次登录,则:
|
||||
1. 弹出对话框,请求用户授权
|
||||
2. 如果用户仍然拒绝,则返回
|
||||
3. 如果用户接受授权,则弹出系统权限配置页面,等待用户给与授权。
|
||||
|
||||
### 3.2.4 立即购买和放入购物车
|
||||
|
||||
### 3.2.5 storage使用
|
||||
|
||||
53
doc/4.md
53
doc/4.md
@@ -1,7 +1,5 @@
|
||||
# 4 litemall管理后台
|
||||
|
||||
这里的后台管理业务参考了[platform](https://gitee.com/fuyang_lipengjun/platform).
|
||||
|
||||
项目技术架构:
|
||||
|
||||
* 后台管理前端,即litemall-admin模块
|
||||
@@ -46,16 +44,61 @@
|
||||
|
||||
## 4.1 litemall-admin-api
|
||||
|
||||
### 4.1.1
|
||||
本节介绍管理后台的后台服务模块。
|
||||
|
||||
### 4.1.1 授权服务
|
||||
|
||||
|
||||
|
||||
### 4.1.2 安全配置
|
||||
|
||||
### 4.1.3 CROS配置
|
||||
### 4.1.16 安全
|
||||
|
||||
#### 4.1.16.1 Token
|
||||
|
||||
用户登录成功以后,后端会返回`token`,之后用户的请求都会携带token。
|
||||
|
||||
目前token的失效和跟新机制没有涉及。
|
||||
|
||||
#### 4.1.16.2 CROS
|
||||
|
||||
如果litemall-admin-api不配置CROS,则Spring Boot会失败。
|
||||
|
||||
#### 4.1.16.3 账号密码加盐
|
||||
|
||||
如果是微信登录,那么无需账号和密码。
|
||||
|
||||
而如果用户采用了账号和密码的形式登录,那么后端需要把用户密码加盐。
|
||||
|
||||
#### 4.1.16.4 限制登录
|
||||
|
||||
如果采用账号密码登录,那么登录失败一定次数,应该限制登录。
|
||||
|
||||
进一步地,如果项目启用了短信功能,应该短信提醒用户,防止他人登录。
|
||||
|
||||
目前这里没有实现,仅列出。
|
||||
|
||||
### 4.1.17 定时任务
|
||||
|
||||
### 4.1.18 并发控制
|
||||
|
||||
参考`2.2.8 乐观锁`
|
||||
|
||||
当乐观锁更新失败时采用多次尝试方案。
|
||||
|
||||
### 4.1.19 事务管理
|
||||
|
||||
### 4.1.20 开发技巧
|
||||
|
||||
当小商城后台服务开发中因为测试或者debug可能需要经常性重启应用,此时
|
||||
一旦重启,将导致小商场的小程序段的token失效,因此要求用户再次登录。
|
||||
这里,介绍一个小技巧:
|
||||
开发时,
|
||||
|
||||
|
||||
## 4.2 litemall-admin
|
||||
|
||||
本节介绍管理后台的前端模块。
|
||||
|
||||
litemall-admin模块的代码基于[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
|
||||
|
||||
### 4.2.1
|
||||
|
||||
60
doc/7.md
60
doc/7.md
@@ -2,7 +2,7 @@
|
||||
|
||||
## 7.1 小商城
|
||||
|
||||
### 7.1.1 为什么小程序微信登录失败
|
||||
### 7.1.1 小程序微信登录失败
|
||||
|
||||
原因:
|
||||
|
||||
@@ -13,11 +13,25 @@
|
||||
1. 如果只是体验商品购买流程,开发者可以采用账号注册登录方式。
|
||||
2. 开发者在litemall-wx和litemall-wx-api模块的appid等信息设置成自己申请的信息。
|
||||
|
||||
#### 7.1.2 为什么开发者工具运行正常,但是手机真机测试不正常?
|
||||
#### 7.1.1.1 appid已经修改,微信登陆仍然失败
|
||||
|
||||
现象:
|
||||
|
||||
手机真机扫描加载小商场以后,只有页面结构,没有数据和图片。
|
||||
微信开发者工具修改了开发者自己申请的appid,后台也更新了相应信息,但是微信登录仍然报错。
|
||||
|
||||
原因:
|
||||
|
||||
这里可能是缓存问题,虽然修改了appid,但是微信开发者工具未及时跟新。
|
||||
|
||||
解决方案:
|
||||
|
||||
微信开发者工具中修改appid以后,请关闭litemall-wx项目或者微信开发者工具,重新启动导入litemall-wx。
|
||||
|
||||
### 7.1.2 手机真机测试不正常
|
||||
|
||||
现象:
|
||||
|
||||
微信开发者工具打开正常,但是手机真机扫描加载小商场以后,只有页面结构,没有数据和图片。
|
||||
|
||||
原因:
|
||||
|
||||
@@ -31,7 +45,11 @@
|
||||
* 小商场的后台服务未启动
|
||||
2. 手机小商场的**调试功能**开启
|
||||
|
||||
#### 7.1.3 为什么本人手机测试正常,而第三者手机测试不正常?
|
||||
### 7.1.3 第三方手机测试不正常
|
||||
|
||||
现象:
|
||||
|
||||
本人手机测试正常,而第三者手机测试不正常。
|
||||
|
||||
解决方案:
|
||||
|
||||
@@ -39,7 +57,11 @@
|
||||
2. 第三者手机小商场的**调试功能**开启
|
||||
3. 在微信小程序平台设置第三者的微信账号是**体验者**
|
||||
|
||||
#### 7.1.4 小商场为什么不能支付,或者为什么点击支付总是报错?
|
||||
### 7.1.4 微信支付失败
|
||||
|
||||
现象:
|
||||
|
||||
小商场不能支付,或者点击支付总是报错
|
||||
|
||||
原因:
|
||||
|
||||
@@ -54,9 +76,9 @@ wx.notify-url=
|
||||
|
||||
解决方案:
|
||||
|
||||
参考`3.0 小商场环境`,设置好相应支付配置信息
|
||||
参考`3.0 小商场环境`,设置相应支付配置信息
|
||||
|
||||
#### 7.1.5 为什么小商城支付成功,但是返回以后商品订单?
|
||||
### 7.1.5 支付成功,但商品仍未付款
|
||||
|
||||
现象:
|
||||
|
||||
@@ -79,4 +101,26 @@ wx.notify-url=
|
||||
|
||||
## 7.2 管理后台
|
||||
|
||||
## 7.3 基础平台
|
||||
### 7.2.1 Invalid bound statement
|
||||
|
||||
现象:
|
||||
|
||||
有时(特别是采用mybatis generator重新生成代码)后台服务报错
|
||||
|
||||
```
|
||||
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): org.linlinjava.litemall.db.dao.XXXX
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
应该是自动生成的新的XML文件没有及时跟新到编译文件夹target中,造成了target中mybatis的Java代码和XML文件不对应。
|
||||
|
||||
解决方案:
|
||||
|
||||
采用maven命令或者插件先清理项目再重新编译打包,例如
|
||||
```bash
|
||||
mvn clean
|
||||
mvn package
|
||||
```
|
||||
|
||||
## 7.3 基础系统
|
||||
12
doc/README.md
Normal file
12
doc/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Table of Contents
|
||||
|
||||
* [介绍](../README.md)
|
||||
* [更新日志](../CHANGELOG.md)
|
||||
* [贡献指南](../CONTRIBUTE.md)
|
||||
* [1. 系统架构](./1.md)
|
||||
* [2. 基础系统](./2.md)
|
||||
* [3. 小商场](./3.md)
|
||||
* [4. 管理后台](./4.md)
|
||||
* [5. 商场](./5.md)
|
||||
* [6. 下一步计划](./6.md)
|
||||
* [7. FAQ](./7.md)
|
||||
@@ -25,6 +25,22 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.linlinjava.litemall.admin.dao;
|
||||
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoods;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoodsAttribute;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoodsSpecification;
|
||||
import org.linlinjava.litemall.db.domain.LitemallProduct;
|
||||
|
||||
public class GoodsAllinone {
|
||||
LitemallGoods goods;
|
||||
LitemallGoodsSpecification[] specifications;
|
||||
LitemallGoodsAttribute[] attributes;
|
||||
// 这里采用 Product 再转换到 LitemallProduct
|
||||
LitemallProduct[] products;
|
||||
|
||||
public LitemallGoods getGoods() {
|
||||
return goods;
|
||||
}
|
||||
|
||||
public LitemallProduct[] getProducts() {
|
||||
return products;
|
||||
}
|
||||
|
||||
public void setProducts(LitemallProduct[] products) {
|
||||
this.products = products;
|
||||
}
|
||||
|
||||
public void setGoods(LitemallGoods goods) {
|
||||
this.goods = goods;
|
||||
}
|
||||
|
||||
public LitemallGoodsSpecification[] getSpecifications() {
|
||||
return specifications;
|
||||
}
|
||||
|
||||
public void setSpecifications(LitemallGoodsSpecification[] specifications) {
|
||||
this.specifications = specifications;
|
||||
}
|
||||
|
||||
public LitemallGoodsAttribute[] getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(LitemallGoodsAttribute[] attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.linlinjava.litemall.admin.dao;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class Product {
|
||||
String[] specifications;
|
||||
BigDecimal price;
|
||||
Integer number;
|
||||
String url;
|
||||
|
||||
public String[] getSpecifications() {
|
||||
return specifications;
|
||||
}
|
||||
|
||||
public void setSpecifications(String[] specifications) {
|
||||
this.specifications = specifications;
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(BigDecimal price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public Integer getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(Integer number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.linlinjava.litemall.admin.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CatVo {
|
||||
private Integer value = null;
|
||||
private String label = null;
|
||||
private List children = null;
|
||||
|
||||
public Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Integer value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public List getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(List children) {
|
||||
this.children = children;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.linlinjava.litemall.admin.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class StatVo {
|
||||
private String[] columns = new String[0];
|
||||
private List<Map> rows = new ArrayList<>();
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public void setColumns(String[] columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public List<Map> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setRows(List<Map> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
public void add(Map ... r) {
|
||||
rows.addAll(Arrays.asList(r));
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +46,7 @@ public class AdminAdController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
ad.setAddTime(LocalDateTime.now());
|
||||
adService.add(ad);
|
||||
return ResponseUtil.ok(ad);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -53,7 +54,7 @@ public class AdminAddressController {
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<LitemallAddress> addressList = addressService.querySelective(userId, name, page, limit, sort, order);
|
||||
@@ -75,7 +76,7 @@ public class AdminAddressController {
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
String mobile = address.getMobile();
|
||||
@@ -83,6 +84,7 @@ public class AdminAddressController {
|
||||
return ResponseUtil.fail(403, "手机号格式不正确");
|
||||
}
|
||||
|
||||
address.setAddTime(LocalDateTime.now());
|
||||
addressService.add(address);
|
||||
|
||||
Map<String, Object> addressVo = toVo(address);
|
||||
@@ -92,7 +94,7 @@ public class AdminAddressController {
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer addressId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
LitemallAddress address = addressService.findById(addressId);
|
||||
@@ -103,7 +105,7 @@ public class AdminAddressController {
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
addressService.updateById(address);
|
||||
Map<String, Object> addressVo = toVo(address);
|
||||
@@ -113,7 +115,7 @@ public class AdminAddressController {
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
addressService.delete(address.getId());
|
||||
return ResponseUtil.ok();
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.db.service.LitemallAdminService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -72,6 +73,7 @@ public class AdminAdminController {
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
String encodedPassword = encoder.encode(rawPassword);
|
||||
admin.setPassword(encodedPassword);
|
||||
admin.setAddTime(LocalDateTime.now());
|
||||
|
||||
adminService.add(admin);
|
||||
return ResponseUtil.ok(admin);
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +46,7 @@ public class AdminBrandController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
brand.setAddTime(LocalDateTime.now());
|
||||
brandService.add(brand);
|
||||
return ResponseUtil.ok(brand);
|
||||
}
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.db.domain.LitemallCart;
|
||||
import org.linlinjava.litemall.db.service.LitemallCartService;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsService;
|
||||
import org.linlinjava.litemall.db.service.LitemallProductService;
|
||||
import org.linlinjava.litemall.db.service.LitemallUserService;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/cart")
|
||||
public class AdminCartController {
|
||||
private final Log logger = LogFactory.getLog(AdminCartController.class);
|
||||
|
||||
@Autowired
|
||||
private LitemallCartService cartService;
|
||||
@Autowired
|
||||
private LitemallUserService userService;
|
||||
@Autowired
|
||||
private LitemallGoodsService goodsService;
|
||||
@Autowired
|
||||
private LitemallProductService productService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Object list(@LoginAdmin Integer adminId,
|
||||
Integer userId, Integer goodsId,
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
List<LitemallCart> cartList = cartService.querySelective(userId, goodsId, page, limit, sort, order);
|
||||
int total = cartService.countSelective(userId, goodsId, page, limit, sort, order);
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("total", total);
|
||||
data.put("items", cartList);
|
||||
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* 目前的逻辑不支持管理员创建
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallCart cart){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
|
||||
return ResponseUtil.fail501();
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
|
||||
LitemallCart cart = cartService.findById(id);
|
||||
return ResponseUtil.ok(cart);
|
||||
}
|
||||
|
||||
/*
|
||||
* 目前的逻辑不支持管理员创建
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallCart cart){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
return ResponseUtil.fail501();
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallCart cart){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
cartService.deleteById(cart.getId());
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,15 @@ package org.linlinjava.litemall.admin.web;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.admin.util.CatVo;
|
||||
import org.linlinjava.litemall.db.domain.LitemallCategory;
|
||||
import org.linlinjava.litemall.db.service.LitemallCategoryService;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +48,7 @@ public class AdminCategoryController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
category.setAddTime(LocalDateTime.now());
|
||||
categoryService.add(category);
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
@@ -89,11 +93,13 @@ public class AdminCategoryController {
|
||||
|
||||
// 所有一级分类目录
|
||||
List<LitemallCategory> l1CatList = categoryService.queryL1();
|
||||
HashMap<Integer, String> data = new HashMap<>(l1CatList.size());
|
||||
List<Map<String, Object>> data = new ArrayList<>(l1CatList.size());
|
||||
for(LitemallCategory category : l1CatList){
|
||||
data.put(category.getId(), category.getName());
|
||||
Map<String, Object> d = new HashMap<>(2);
|
||||
d.put("value", category.getId());
|
||||
d.put("label", category.getName());
|
||||
data.add(d);
|
||||
}
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +46,7 @@ public class AdminCommentController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
comment.setAddTime(LocalDateTime.now());
|
||||
commentService.add(comment);
|
||||
return ResponseUtil.ok(comment);
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoodsAttribute;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsAttributeService;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/goods-attribute")
|
||||
public class AdminGoodsAttributeController {
|
||||
private final Log logger = LogFactory.getLog(AdminGoodsAttributeController.class);
|
||||
|
||||
@Autowired
|
||||
private LitemallGoodsAttributeService goodsAttributeService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Object list(@LoginAdmin Integer adminId,
|
||||
Integer goodsId,
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<LitemallGoodsAttribute> goodsAttributeList = goodsAttributeService.querySelective(goodsId, page, limit, sort, order);
|
||||
int total = goodsAttributeService.countSelective(goodsId, page, limit, sort, order);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("total", total);
|
||||
data.put("items", goodsAttributeList);
|
||||
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsAttribute goodsAttribute){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsAttributeService.add(goodsAttribute);
|
||||
return ResponseUtil.ok(goodsAttribute);
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if(id == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallGoodsAttribute goodsAttribute = goodsAttributeService.findById(id);
|
||||
return ResponseUtil.ok(goodsAttribute);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsAttribute goodsAttribute){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsAttributeService.updateById(goodsAttribute);
|
||||
return ResponseUtil.ok(goodsAttribute);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsAttribute goodsAttribute){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsAttributeService.deleteById(goodsAttribute.getId());
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +1,46 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import io.swagger.models.auth.In;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoods;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsService;
|
||||
import org.linlinjava.litemall.admin.dao.GoodsAllinone;
|
||||
import org.linlinjava.litemall.admin.dao.Product;
|
||||
import org.linlinjava.litemall.admin.util.CatVo;
|
||||
import org.linlinjava.litemall.db.domain.*;
|
||||
import org.linlinjava.litemall.db.service.*;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/goods")
|
||||
public class AdminGoodsController {
|
||||
private final Log logger = LogFactory.getLog(AdminGoodsController.class);
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager txManager;
|
||||
|
||||
@Autowired
|
||||
private LitemallGoodsService goodsService;
|
||||
@Autowired
|
||||
private LitemallGoodsSpecificationService specificationService;
|
||||
@Autowired
|
||||
private LitemallGoodsAttributeService attributeService;
|
||||
@Autowired
|
||||
private LitemallProductService productService;
|
||||
@Autowired
|
||||
private LitemallCategoryService categoryService;
|
||||
@Autowired
|
||||
private LitemallBrandService brandService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Object list(@LoginAdmin Integer adminId,
|
||||
@@ -40,36 +61,71 @@ public class AdminGoodsController {
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallGoods goods){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsService.add(goods);
|
||||
return ResponseUtil.ok(goods);
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if(id == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallGoods goods = goodsService.findById(id);
|
||||
return ResponseUtil.ok(goods);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* 目前商品修改的逻辑是
|
||||
* 1. 更新litemall_goods表
|
||||
* 2. 逻辑删除litemall_goods_specification、litemall_goods_attribute、litemall_product
|
||||
* 3. 添加litemall_goods_specification、litemall_goods_attribute、litemall_product
|
||||
*
|
||||
* 这里商品三个表的数据采用删除再跟新的策略是因为
|
||||
* 商品编辑页面,管理员可以添加删除商品规格、添加删除商品属性,因此这里仅仅更新表是不可能的,
|
||||
* 因此这里只能删除所有旧的数据,然后添加新的数据
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallGoods goods){
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody GoodsAllinone goodsAllinone){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsService.updateById(goods);
|
||||
return ResponseUtil.ok(goods);
|
||||
|
||||
LitemallGoods goods = goodsAllinone.getGoods();
|
||||
LitemallGoodsAttribute[] attributes = goodsAllinone.getAttributes();
|
||||
LitemallGoodsSpecification[] specifications = goodsAllinone.getSpecifications();
|
||||
LitemallProduct[] products = goodsAllinone.getProducts();
|
||||
|
||||
// 开启事务管理
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
TransactionStatus status = txManager.getTransaction(def);
|
||||
try {
|
||||
|
||||
// 商品基本信息表litemall_goods
|
||||
goodsService.updateById(goods);
|
||||
|
||||
Integer gid = goods.getId();
|
||||
specificationService.deleteByGid(gid);
|
||||
attributeService.deleteByGid(gid);
|
||||
productService.deleteByGid(gid);
|
||||
|
||||
// 商品规格表litemall_goods_specification
|
||||
Map<String, Integer> specIds = new HashMap<>();
|
||||
for(LitemallGoodsSpecification specification : specifications){
|
||||
specification.setGoodsId(goods.getId());
|
||||
specification.setAddTime(LocalDateTime.now());
|
||||
specificationService.add(specification);
|
||||
specIds.put(specification.getValue(), specification.getId());
|
||||
}
|
||||
|
||||
// 商品参数表litemall_goods_attribute
|
||||
for(LitemallGoodsAttribute attribute : attributes){
|
||||
attribute.setGoodsId(goods.getId());
|
||||
attribute.setAddTime(LocalDateTime.now());
|
||||
attributeService.add(attribute);
|
||||
}
|
||||
|
||||
// 商品货品表litemall_product
|
||||
for(LitemallProduct product : products){
|
||||
product.setGoodsId(goods.getId());
|
||||
product.setAddTime(LocalDateTime.now());
|
||||
productService.add(product);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
txManager.rollback(status);
|
||||
logger.error("系统内部错误", ex);
|
||||
}
|
||||
txManager.commit(status);
|
||||
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
@@ -77,8 +133,162 @@ public class AdminGoodsController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsService.deleteById(goods.getId());
|
||||
|
||||
// 开启事务管理
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
TransactionStatus status = txManager.getTransaction(def);
|
||||
try {
|
||||
|
||||
Integer gid = goods.getId();
|
||||
goodsService.deleteById(gid);
|
||||
specificationService.deleteByGid(gid);
|
||||
attributeService.deleteByGid(gid);
|
||||
productService.deleteByGid(gid);
|
||||
} catch (Exception ex) {
|
||||
txManager.rollback(status);
|
||||
logger.error("系统内部错误", ex);
|
||||
}
|
||||
txManager.commit(status);
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody GoodsAllinone goodsAllinone){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
LitemallGoods goods = goodsAllinone.getGoods();
|
||||
LitemallGoodsAttribute[] attributes = goodsAllinone.getAttributes();
|
||||
LitemallGoodsSpecification[] specifications = goodsAllinone.getSpecifications();
|
||||
LitemallProduct[] products = goodsAllinone.getProducts();
|
||||
|
||||
String name = goods.getName();
|
||||
if(goodsService.checkExistByName(name)){
|
||||
return ResponseUtil.fail(403, "商品名已经存在");
|
||||
}
|
||||
|
||||
// 开启事务管理
|
||||
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
|
||||
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
TransactionStatus status = txManager.getTransaction(def);
|
||||
try {
|
||||
|
||||
// 商品基本信息表litemall_goods
|
||||
goods.setAddTime(LocalDateTime.now());
|
||||
goodsService.add(goods);
|
||||
|
||||
// 商品规格表litemall_goods_specification
|
||||
Map<String, Integer> specIds = new HashMap<>();
|
||||
for(LitemallGoodsSpecification specification : specifications){
|
||||
specification.setGoodsId(goods.getId());
|
||||
specification.setAddTime(LocalDateTime.now());
|
||||
specificationService.add(specification);
|
||||
specIds.put(specification.getValue(), specification.getId());
|
||||
}
|
||||
|
||||
// 商品参数表litemall_goods_attribute
|
||||
for(LitemallGoodsAttribute attribute : attributes){
|
||||
attribute.setGoodsId(goods.getId());
|
||||
attribute.setAddTime(LocalDateTime.now());
|
||||
attributeService.add(attribute);
|
||||
}
|
||||
|
||||
// 商品货品表litemall_product
|
||||
for(LitemallProduct product : products){
|
||||
product.setGoodsId(goods.getId());
|
||||
product.setAddTime(LocalDateTime.now());
|
||||
productService.add(product);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
txManager.rollback(status);
|
||||
logger.error("系统内部错误", ex);
|
||||
}
|
||||
txManager.commit(status);
|
||||
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/catAndBrand")
|
||||
public Object list2(@LoginAdmin Integer adminId) {
|
||||
if (adminId == null) {
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
// http://element-cn.eleme.io/#/zh-CN/component/cascader
|
||||
// 管理员设置“所属分类”
|
||||
List<LitemallCategory> l1CatList = categoryService.queryL1();
|
||||
List<CatVo> categoryList = new ArrayList<>(l1CatList.size());
|
||||
|
||||
for(LitemallCategory l1 : l1CatList){
|
||||
CatVo l1CatVo = new CatVo();
|
||||
l1CatVo.setValue(l1.getId());
|
||||
l1CatVo.setLabel(l1.getName());
|
||||
|
||||
List<LitemallCategory> l2CatList = categoryService.queryByPid(l1.getId());
|
||||
List<CatVo> children = new ArrayList<>(l2CatList.size());
|
||||
for(LitemallCategory l2 : l2CatList) {
|
||||
CatVo l2CatVo = new CatVo();
|
||||
l2CatVo.setValue(l2.getId());
|
||||
l2CatVo.setLabel(l2.getName());
|
||||
children.add(l2CatVo);
|
||||
}
|
||||
l1CatVo.setChildren(children);
|
||||
|
||||
categoryList.add(l1CatVo);
|
||||
}
|
||||
|
||||
// http://element-cn.eleme.io/#/zh-CN/component/select
|
||||
// 管理员设置“所属品牌商”
|
||||
List<LitemallBrand> list = brandService.all();
|
||||
List<Map<String, Object>> brandList = new ArrayList<>(l1CatList.size());
|
||||
for(LitemallBrand brand : list){
|
||||
Map<String, Object> b = new HashMap<>(2);
|
||||
b.put("value", brand.getId());
|
||||
b.put("label", brand.getName());
|
||||
brandList.add(b);
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("categoryList" ,categoryList);
|
||||
data.put("brandList", brandList);
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
@GetMapping("/detail")
|
||||
public Object detail(@LoginAdmin Integer adminId, Integer id) {
|
||||
if (adminId == null) {
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallGoods goods = goodsService.findById(id);
|
||||
List<LitemallProduct> products = productService.queryByGid(id);
|
||||
List<LitemallGoodsSpecification> specifications = specificationService.queryByGid(id);
|
||||
List<LitemallGoodsAttribute> attributes = attributeService.queryByGid(id);
|
||||
|
||||
Integer categoryId = goods.getCategoryId();
|
||||
LitemallCategory category = categoryService.findById(categoryId);
|
||||
Integer[] categoryIds = new Integer[]{};
|
||||
if (category != null) {
|
||||
Integer parentCategoryId = category.getPid();
|
||||
categoryIds = new Integer[] {parentCategoryId, categoryId};
|
||||
}
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("goods" ,goods);
|
||||
data.put("specifications", specifications);
|
||||
data.put("products", products);
|
||||
data.put("attributes", attributes);
|
||||
data.put("categoryIds", categoryIds);
|
||||
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoodsSpecification;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsSpecificationService;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/goods-specification")
|
||||
public class AdminGoodsSpecificationController {
|
||||
private final Log logger = LogFactory.getLog(AdminGoodsSpecificationController.class);
|
||||
|
||||
@Autowired
|
||||
private LitemallGoodsSpecificationService goodsSpecificationService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Object list(@LoginAdmin Integer adminId,
|
||||
Integer goodsId,
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<LitemallGoodsSpecification> goodsSpecificationList = goodsSpecificationService.querySelective(goodsId, page, limit, sort, order);
|
||||
int total = goodsSpecificationService.countSelective(goodsId, page, limit, sort, order);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("total", total);
|
||||
data.put("items", goodsSpecificationList);
|
||||
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsSpecification goodsSpecification){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsSpecificationService.add(goodsSpecification);
|
||||
return ResponseUtil.ok(goodsSpecification);
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if(id == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallGoodsSpecification goodsSpecification = goodsSpecificationService.findById(id);
|
||||
return ResponseUtil.ok(goodsSpecification);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsSpecification goodsSpecification){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsSpecificationService.updateById(goodsSpecification);
|
||||
return ResponseUtil.ok(goodsSpecification);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallGoodsSpecification goodsSpecification){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
goodsSpecificationService.deleteById(goodsSpecification.getId());
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/volist")
|
||||
public Object volist(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if(id == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
Object goodsSpecificationVoList = goodsSpecificationService.getSpecificationVoList(id);
|
||||
return ResponseUtil.ok(goodsSpecificationVoList);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -43,9 +43,9 @@ public class AdminHistoryController {
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallSearchHistory history){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
return ResponseUtil.fail501();
|
||||
return ResponseUtil.unsupport();
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -41,12 +42,13 @@ public class AdminIssueController {
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallIssue issue){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
issueService.add(brand);
|
||||
return ResponseUtil.ok(brand);
|
||||
issue.setAddTime(LocalDateTime.now());
|
||||
issueService.add(issue);
|
||||
return ResponseUtil.ok(issue);
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
@@ -59,25 +61,25 @@ public class AdminIssueController {
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallIssue brand = issueService.findById(id);
|
||||
return ResponseUtil.ok(brand);
|
||||
LitemallIssue issue = issueService.findById(id);
|
||||
return ResponseUtil.ok(issue);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallIssue issue){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
issueService.updateById(brand);
|
||||
return ResponseUtil.ok(brand);
|
||||
issueService.updateById(issue);
|
||||
return ResponseUtil.ok(issue);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallIssue issue){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
issueService.deleteById(brand.getId());
|
||||
issueService.deleteById(issue.getId());
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +46,7 @@ public class AdminKeywordController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
keywords.setAddTime(LocalDateTime.now());
|
||||
keywordService.add(keywords);
|
||||
return ResponseUtil.ok(keywords);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -48,7 +49,7 @@ public class AdminOrderController {
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
List<LitemallOrder> orderList = orderService.querySelective(userId, orderSn, page, limit, sort, order);
|
||||
int total = orderService.countSelective(userId, orderSn, page, limit, sort, order);
|
||||
@@ -60,73 +61,6 @@ public class AdminOrderController {
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* 目前的逻辑不支持管理员创建
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallOrder order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
return ResponseUtil.unsupport();
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
}
|
||||
|
||||
LitemallOrder order = orderService.findById(id);
|
||||
return ResponseUtil.ok(order);
|
||||
}
|
||||
|
||||
/*
|
||||
* 目前仅仅支持管理员设置发货相关的信息
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallOrder order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
Integer orderId = order.getId();
|
||||
if(orderId == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallOrder litemallOrder = orderService.findById(orderId);
|
||||
if(litemallOrder == null){
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
if(OrderUtil.isPayStatus(litemallOrder) || OrderUtil.isShipStatus(litemallOrder)){
|
||||
LitemallOrder newOrder = new LitemallOrder();
|
||||
newOrder.setId(orderId);
|
||||
newOrder.setShipChannel(order.getShipChannel());
|
||||
newOrder.setShipSn(order.getOrderSn());
|
||||
newOrder.setShipStartTime(order.getShipStartTime());
|
||||
newOrder.setShipEndTime(order.getShipEndTime());
|
||||
newOrder.setOrderStatus(OrderUtil.STATUS_SHIP);
|
||||
orderService.update(newOrder);
|
||||
}
|
||||
else {
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
litemallOrder = orderService.findById(orderId);
|
||||
return ResponseUtil.ok(litemallOrder);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallOrder order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
return ResponseUtil.unsupport();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 订单退款确认
|
||||
* 1. 检测当前订单是否能够退款确认
|
||||
@@ -139,12 +73,13 @@ public class AdminOrderController {
|
||||
* 成功则 { errno: 0, errmsg: '成功' }
|
||||
* 失败则 { errno: XXX, errmsg: XXX }
|
||||
*/
|
||||
@PostMapping("refundConfirm")
|
||||
public Object refundConfirm(@LoginAdmin Integer adminId, @RequestBody String body) {
|
||||
@PostMapping("refund")
|
||||
public Object refund(@LoginAdmin Integer adminId, @RequestBody String body) {
|
||||
if (adminId == null) {
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
Integer orderId = JacksonUtil.parseInteger(body, "orderId");
|
||||
Integer refundMoney = JacksonUtil.parseInteger(body, "refundMoney");
|
||||
if (orderId == null) {
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
@@ -153,13 +88,14 @@ public class AdminOrderController {
|
||||
if (order == null) {
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
if (!order.getUserId().equals(adminId)) {
|
||||
|
||||
if(order.getActualPrice().compareTo(new BigDecimal(refundMoney)) != 0){
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
OrderHandleOption handleOption = OrderUtil.build(order);
|
||||
if (!handleOption.isRefund()) {
|
||||
return ResponseUtil.fail(403, "订单不能取消");
|
||||
// 如果订单不是退款状态,则不能退款
|
||||
if (!order.getOrderStatus().equals(OrderUtil.STATUS_REFUND)) {
|
||||
return ResponseUtil.fail(403, "订单不能确认收货");
|
||||
}
|
||||
|
||||
// 开启事务管理
|
||||
@@ -176,8 +112,8 @@ public class AdminOrderController {
|
||||
for (LitemallOrderGoods orderGoods : orderGoodsList) {
|
||||
Integer productId = orderGoods.getProductId();
|
||||
LitemallProduct product = productService.findById(productId);
|
||||
Integer number = product.getGoodsNumber() + orderGoods.getNumber();
|
||||
product.setGoodsNumber(number);
|
||||
Integer number = product.getNumber() + orderGoods.getNumber();
|
||||
product.setNumber(number);
|
||||
productService.updateById(product);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@@ -217,9 +153,6 @@ public class AdminOrderController {
|
||||
if (order == null) {
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
if (!order.getUserId().equals(adminId)) {
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
// 如果订单不是已付款状态,则不能发货
|
||||
if (!order.getOrderStatus().equals(OrderUtil.STATUS_PAY)) {
|
||||
@@ -229,7 +162,7 @@ public class AdminOrderController {
|
||||
order.setOrderStatus(OrderUtil.STATUS_SHIP);
|
||||
order.setShipSn(shipSn);
|
||||
order.setShipChannel(shipChannel);
|
||||
order.setShipStartTime(LocalDateTime.now());
|
||||
order.setShipTime(LocalDateTime.now());
|
||||
orderService.update(order);
|
||||
|
||||
return ResponseUtil.ok();
|
||||
@@ -274,8 +207,8 @@ public class AdminOrderController {
|
||||
for (LitemallOrderGoods orderGoods : orderGoodsList) {
|
||||
Integer productId = orderGoods.getProductId();
|
||||
LitemallProduct product = productService.findById(productId);
|
||||
Integer number = product.getGoodsNumber() + orderGoods.getNumber();
|
||||
product.setGoodsNumber(number);
|
||||
Integer number = product.getNumber() + orderGoods.getNumber();
|
||||
product.setNumber(number);
|
||||
productService.updateById(product);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
@@ -298,7 +231,7 @@ public class AdminOrderController {
|
||||
* 早点清理未付款情况,这里八天再确认是可以的。
|
||||
*
|
||||
* TODO
|
||||
* 目前自动确认是基于管理后台管理员所设置的商品快递到达时间,见orderService.queryUnconfirm。
|
||||
* 目前自动确认是基于管理后台管理员所设置的商品快递时间,见orderService.queryUnconfirm。
|
||||
* 那么在实际业务上有可能存在商品寄出以后商品因为一些原因快递最终没有到达,
|
||||
* 也就是商品快递失败而shipEndTime一直是空的情况,因此这里业务可能需要扩展,以防止订单一直
|
||||
* 处于发货状态。
|
||||
@@ -309,9 +242,9 @@ public class AdminOrderController {
|
||||
|
||||
List<LitemallOrder> orderList = orderService.queryUnconfirm();
|
||||
for(LitemallOrder order : orderList){
|
||||
LocalDateTime shipEnd = order.getShipEndTime();
|
||||
LocalDateTime ship = order.getShipTime();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LocalDateTime expired = shipEnd.plusDays(7);
|
||||
LocalDateTime expired = ship.plusDays(7);
|
||||
if(expired.isAfter(now)){
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.db.domain.LitemallGoods;
|
||||
import org.linlinjava.litemall.db.domain.LitemallProduct;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsService;
|
||||
import org.linlinjava.litemall.db.service.LitemallGoodsSpecificationService;
|
||||
import org.linlinjava.litemall.db.service.LitemallProductService;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/product")
|
||||
public class AdminProductController {
|
||||
private final Log logger = LogFactory.getLog(AdminProductController.class);
|
||||
|
||||
@Autowired
|
||||
private LitemallProductService productService;
|
||||
@Autowired
|
||||
private LitemallGoodsService goodsService;
|
||||
@Autowired
|
||||
private LitemallGoodsSpecificationService goodsSpecificationService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Object list(@LoginAdmin Integer adminId,
|
||||
Integer goodsId,
|
||||
@RequestParam(value = "page", defaultValue = "1") Integer page,
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<LitemallProduct> productList = productService.querySelective(goodsId, page, limit, sort, order);
|
||||
int total = productService.countSelective(goodsId, page, limit, sort, order);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("total", total);
|
||||
data.put("items", productList);
|
||||
|
||||
return ResponseUtil.ok(data);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param adminId
|
||||
* @param litemallProduct
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallProduct litemallProduct){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
Integer goodsId = litemallProduct.getGoodsId();
|
||||
if(goodsId == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallGoods goods = goodsService.findById(goodsId);
|
||||
if(goods == null){
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
List<LitemallProduct> productList = productService.queryByGid(goodsId);
|
||||
if(productList.size() != 0){
|
||||
return ResponseUtil.badArgumentValue();
|
||||
}
|
||||
|
||||
Integer[] goodsSpecificationIds = goodsSpecificationService.queryIdsByGid(goodsId);
|
||||
if(goodsSpecificationIds.length == 0) {
|
||||
return ResponseUtil.serious();
|
||||
}
|
||||
|
||||
LitemallProduct product = new LitemallProduct();
|
||||
product.setGoodsId(goodsId);
|
||||
product.setGoodsNumber(0);
|
||||
product.setRetailPrice(new BigDecimal(0.00));
|
||||
product.setGoodsSpecificationIds(goodsSpecificationIds);
|
||||
productService.add(product);
|
||||
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/read")
|
||||
public Object read(@LoginAdmin Integer adminId, Integer id){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
if(id == null){
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
LitemallProduct product = productService.findById(id);
|
||||
return ResponseUtil.ok(product);
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallProduct product){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
productService.updateById(product);
|
||||
return ResponseUtil.ok(product);
|
||||
}
|
||||
|
||||
@PostMapping("/delete")
|
||||
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallProduct product){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
productService.deleteById(product.getId());
|
||||
return ResponseUtil.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package org.linlinjava.litemall.admin.web;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
|
||||
import org.linlinjava.litemall.admin.util.StatVo;
|
||||
import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.linlinjava.litemall.db.dao.StatMapper;
|
||||
import org.linlinjava.litemall.db.service.LitemallOrderService;
|
||||
import org.linlinjava.litemall.db.service.StatService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/stat")
|
||||
public class AdminStatController {
|
||||
private final Log logger = LogFactory.getLog(AdminStatController.class);
|
||||
|
||||
@Autowired
|
||||
private StatService statService;
|
||||
|
||||
@GetMapping("/user")
|
||||
public Object statUser(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statUser();
|
||||
String[] columns = new String[]{"day", "users"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
@GetMapping("/order")
|
||||
public Object statOrder(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statOrder();
|
||||
String[] columns = new String[]{"day", "orders", "customers", "amount", "pcr"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
@GetMapping("/goods")
|
||||
public Object statGoods(@LoginAdmin Integer adminId){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
|
||||
List<Map> rows = statService.statGoods();
|
||||
String[] columns = new String[]{"day", "orders", "products", "amount"};
|
||||
StatVo statVo = new StatVo();
|
||||
statVo.setColumns(columns);
|
||||
statVo.setRows(rows);
|
||||
|
||||
|
||||
return ResponseUtil.ok(statVo);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -45,6 +46,7 @@ public class AdminTopicController {
|
||||
if(adminId == null){
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
topic.setAddTime(LocalDateTime.now());
|
||||
topicService.add(topic);
|
||||
return ResponseUtil.ok(topic);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -29,7 +30,7 @@ public class AdminUserController {
|
||||
@RequestParam(value = "limit", defaultValue = "10") Integer limit,
|
||||
String sort, String order){
|
||||
if(adminId == null){
|
||||
return ResponseUtil.fail401();
|
||||
return ResponseUtil.unlogin();
|
||||
}
|
||||
List<LitemallUser> userList = userService.querySelective(username, mobile, page, limit, sort, order);
|
||||
int total = userService.countSeletive(username, mobile, page, limit, sort, order);
|
||||
@@ -43,7 +44,7 @@ public class AdminUserController {
|
||||
@GetMapping("/username")
|
||||
public Object username(String username){
|
||||
if(StringUtil.isEmpty(username)){
|
||||
return ResponseUtil.fail402();
|
||||
return ResponseUtil.badArgument();
|
||||
}
|
||||
|
||||
int total = userService.countSeletive(username, null, null, null, null, null);
|
||||
@@ -57,7 +58,7 @@ public class AdminUserController {
|
||||
@PostMapping("/create")
|
||||
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallUser user){
|
||||
logger.debug(user);
|
||||
|
||||
user.setAddTime(LocalDateTime.now());
|
||||
userService.add(user);
|
||||
return ResponseUtil.ok(user);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
|
||||
@@ -13,9 +13,10 @@
|
||||
"test": "npm run lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tinymce/tinymce-vue": "^1.0.8",
|
||||
"axios": "0.17.1",
|
||||
"clipboard": "1.7.1",
|
||||
"echarts": "3.8.5",
|
||||
"echarts": "^4.1.0",
|
||||
"element-ui": "2.0.8",
|
||||
"file-saver": "1.3.3",
|
||||
"font-awesome": "4.7.0",
|
||||
@@ -24,13 +25,13 @@
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"screenfull": "3.3.2",
|
||||
"v-charts": "^1.16.19",
|
||||
"vue": "2.5.10",
|
||||
"vue-count-to": "1.0.13",
|
||||
"vue-router": "3.0.1",
|
||||
"vue-splitpane": "1.0.2",
|
||||
"vuex": "3.0.1",
|
||||
"xlsx": "^0.11.16",
|
||||
"@tinymce/tinymce-vue": "1.0.8"
|
||||
"xlsx": "^0.11.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "7.2.3",
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listCart(query) {
|
||||
return request({
|
||||
url: '/cart/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createCart(data) {
|
||||
return request({
|
||||
url: '/cart/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readCart(data) {
|
||||
return request({
|
||||
url: '/cart/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateCart(data) {
|
||||
return request({
|
||||
url: '/cart/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteCart(data) {
|
||||
return request({
|
||||
url: '/cart/delete',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listGoodsAttribute(query) {
|
||||
return request({
|
||||
url: '/goods-attribute/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createGoodsAttribute(data) {
|
||||
return request({
|
||||
url: '/goods-attribute/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readGoodsAttribute(data) {
|
||||
return request({
|
||||
url: '/goods-attribute/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateGoodsAttribute(data) {
|
||||
return request({
|
||||
url: '/goods-attribute/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteGoodsAttribute(data) {
|
||||
return request({
|
||||
url: '/goods-attribute/delete',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listGoodsSpecification(query) {
|
||||
return request({
|
||||
url: '/goods-specification/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createGoodsSpecification(data) {
|
||||
return request({
|
||||
url: '/goods-specification/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readGoodsSpecification(data) {
|
||||
return request({
|
||||
url: '/goods-specification/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateGoodsSpecification(data) {
|
||||
return request({
|
||||
url: '/goods-specification/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteGoodsSpecification(data) {
|
||||
return request({
|
||||
url: '/goods-specification/delete',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function listGoodsSpecificationVo(query) {
|
||||
return request({
|
||||
url: '/goods-specification/volist',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -8,30 +8,6 @@ export function listGoods(query) {
|
||||
})
|
||||
}
|
||||
|
||||
export function createGoods(data) {
|
||||
return request({
|
||||
url: '/goods/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readGoods(data) {
|
||||
return request({
|
||||
url: '/goods/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateGoods(data) {
|
||||
return request({
|
||||
url: '/goods/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteGoods(data) {
|
||||
return request({
|
||||
url: '/goods/delete',
|
||||
@@ -39,3 +15,34 @@ export function deleteGoods(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function publishGoods(data) {
|
||||
return request({
|
||||
url: '/goods/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function detailGoods(id) {
|
||||
return request({
|
||||
url: '/goods/detail',
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
}
|
||||
|
||||
export function editGoods(data) {
|
||||
return request({
|
||||
url: '/goods/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function listCatAndBrand() {
|
||||
return request({
|
||||
url: '/goods/catAndBrand',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,33 +8,17 @@ export function listOrder(query) {
|
||||
})
|
||||
}
|
||||
|
||||
export function createOrder(data) {
|
||||
export function shipOrder(data) {
|
||||
return request({
|
||||
url: '/order/create',
|
||||
url: '/order/ship',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readOrder(data) {
|
||||
export function refundOrder(data) {
|
||||
return request({
|
||||
url: '/order/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateOrder(data) {
|
||||
return request({
|
||||
url: '/order/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteOrder(data) {
|
||||
return request({
|
||||
url: '/order/delete',
|
||||
url: '/order/refund',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listProduct(query) {
|
||||
return request({
|
||||
url: '/product/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function createProduct(data) {
|
||||
return request({
|
||||
url: '/product/create',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function readProduct(data) {
|
||||
return request({
|
||||
url: '/product/read',
|
||||
method: 'get',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateProduct(data) {
|
||||
return request({
|
||||
url: '/product/update',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteProduct(data) {
|
||||
return request({
|
||||
url: '/product/delete',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
25
litemall-admin/src/api/stat.js
Normal file
25
litemall-admin/src/api/stat.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function statUser(query) {
|
||||
return request({
|
||||
url: '/stat/user',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function statOrder(query) {
|
||||
return request({
|
||||
url: '/stat/order',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function statGoods(query) {
|
||||
return request({
|
||||
url: '/stat/goods',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
@@ -60,3 +60,6 @@ export function deleteStorage(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
const uploadPath = process.env.OS_API + '/storage/create'
|
||||
export { uploadPath }
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
const vueSticky = {}
|
||||
let listenAction
|
||||
vueSticky.install = Vue => {
|
||||
Vue.directive('sticky', {
|
||||
inserted(el, binding) {
|
||||
const params = binding.value || {}
|
||||
const stickyTop = params.stickyTop || 0
|
||||
const zIndex = params.zIndex || 1000
|
||||
const elStyle = el.style
|
||||
|
||||
elStyle.position = '-webkit-sticky'
|
||||
elStyle.position = 'sticky'
|
||||
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
|
||||
// if (~elStyle.position.indexOf('sticky')) {
|
||||
// elStyle.top = `${stickyTop}px`;
|
||||
// elStyle.zIndex = zIndex;
|
||||
// return
|
||||
// }
|
||||
const elHeight = el.getBoundingClientRect().height
|
||||
const elWidth = el.getBoundingClientRect().width
|
||||
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
|
||||
|
||||
const parentElm = el.parentNode || document.documentElement
|
||||
const placeholder = document.createElement('div')
|
||||
placeholder.style.display = 'none'
|
||||
placeholder.style.width = `${elWidth}px`
|
||||
placeholder.style.height = `${elHeight}px`
|
||||
parentElm.insertBefore(placeholder, el)
|
||||
|
||||
let active = false
|
||||
|
||||
const getScroll = (target, top) => {
|
||||
const prop = top ? 'pageYOffset' : 'pageXOffset'
|
||||
const method = top ? 'scrollTop' : 'scrollLeft'
|
||||
let ret = target[prop]
|
||||
if (typeof ret !== 'number') {
|
||||
ret = window.document.documentElement[method]
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
const sticky = () => {
|
||||
if (active) {
|
||||
return
|
||||
}
|
||||
if (!elStyle.height) {
|
||||
elStyle.height = `${el.offsetHeight}px`
|
||||
}
|
||||
|
||||
elStyle.position = 'fixed'
|
||||
elStyle.width = `${elWidth}px`
|
||||
placeholder.style.display = 'inline-block'
|
||||
active = true
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
if (!active) {
|
||||
return
|
||||
}
|
||||
|
||||
elStyle.position = ''
|
||||
placeholder.style.display = 'none'
|
||||
active = false
|
||||
}
|
||||
|
||||
const check = () => {
|
||||
const scrollTop = getScroll(window, true)
|
||||
const offsetTop = el.getBoundingClientRect().top
|
||||
if (offsetTop < stickyTop) {
|
||||
sticky()
|
||||
} else {
|
||||
if (scrollTop < elHeight + stickyTop) {
|
||||
reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
listenAction = () => {
|
||||
check()
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', listenAction)
|
||||
},
|
||||
|
||||
unbind() {
|
||||
window.removeEventListener('scroll', listenAction)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default vueSticky
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import waves from './waves'
|
||||
|
||||
const install = function(Vue) {
|
||||
Vue.directive('waves', waves)
|
||||
}
|
||||
|
||||
if (window.Vue) {
|
||||
window.waves = waves
|
||||
Vue.use(install); // eslint-disable-line
|
||||
}
|
||||
|
||||
waves.install = install
|
||||
export default waves
|
||||
@@ -1,26 +0,0 @@
|
||||
.waves-ripple {
|
||||
position: absolute;
|
||||
border-radius: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
background-clip: padding-box;
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-transform: scale(0);
|
||||
-ms-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.waves-ripple.z-active {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(2);
|
||||
-ms-transform: scale(2);
|
||||
transform: scale(2);
|
||||
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
||||
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
|
||||
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
|
||||
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import './waves.css'
|
||||
|
||||
export default{
|
||||
bind(el, binding) {
|
||||
el.addEventListener('click', e => {
|
||||
const customOpts = Object.assign({}, binding.value)
|
||||
const opts = Object.assign({
|
||||
ele: el, // 波纹作用元素
|
||||
type: 'hit', // hit点击位置扩散center中心点扩展
|
||||
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
|
||||
}, customOpts)
|
||||
const target = opts.ele
|
||||
if (target) {
|
||||
target.style.position = 'relative'
|
||||
target.style.overflow = 'hidden'
|
||||
const rect = target.getBoundingClientRect()
|
||||
let ripple = target.querySelector('.waves-ripple')
|
||||
if (!ripple) {
|
||||
ripple = document.createElement('span')
|
||||
ripple.className = 'waves-ripple'
|
||||
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
|
||||
target.appendChild(ripple)
|
||||
} else {
|
||||
ripple.className = 'waves-ripple'
|
||||
}
|
||||
switch (opts.type) {
|
||||
case 'center':
|
||||
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
|
||||
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
|
||||
break
|
||||
default:
|
||||
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
|
||||
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
|
||||
}
|
||||
ripple.style.backgroundColor = opts.color
|
||||
ripple.className = 'waves-ripple z-active'
|
||||
return false
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ function hasPermission(roles, permissionRoles) {
|
||||
return roles.some(role => permissionRoles.indexOf(role) >= 0)
|
||||
}
|
||||
|
||||
const whiteList = ['/login', '/authredirect']// no redirect whitelist
|
||||
const whiteList = ['/login']// no redirect whitelist
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start() // start progress bar
|
||||
@@ -33,7 +33,7 @@ router.beforeEach((to, from, next) => {
|
||||
})
|
||||
}).catch(() => {
|
||||
store.dispatch('FedLogOut').then(() => {
|
||||
Message.error('Verification failed, please login again')
|
||||
Message.error('验证失败,请输入正确的用户名和密码')
|
||||
next({ path: '/login' })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -29,7 +29,6 @@ import Layout from '../views/layout/Layout'
|
||||
**/
|
||||
export const constantRouterMap = [
|
||||
{ path: '/login', component: _import('login/index'), hidden: true },
|
||||
{ path: '/authredirect', component: _import('login/authredirect'), hidden: true },
|
||||
{ path: '/404', component: _import('error/404'), hidden: true },
|
||||
{ path: '/401', component: _import('error/401'), hidden: true },
|
||||
{
|
||||
@@ -66,8 +65,7 @@ export const asyncRouterMap = [
|
||||
{ path: 'address', component: _import('user/address'), name: 'address', meta: { title: '收货地址', noCache: true }},
|
||||
{ path: 'collect', component: _import('user/collect'), name: 'collect', meta: { title: '会员收藏', noCache: true }},
|
||||
{ path: 'footprint', component: _import('user/footprint'), name: 'footprint', meta: { title: '会员足迹', noCache: true }},
|
||||
{ path: 'history', component: _import('user/history'), name: 'history', meta: { title: '搜索历史', noCache: true }},
|
||||
{ path: 'cart', component: _import('user/cart'), name: 'cart', meta: { title: '购物车', noCache: true }}
|
||||
{ path: 'history', component: _import('user/history'), name: 'history', meta: { title: '搜索历史', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -100,13 +98,13 @@ export const asyncRouterMap = [
|
||||
icon: 'chart'
|
||||
},
|
||||
children: [
|
||||
{ path: 'goods', component: _import('goods/goods'), name: 'goods', meta: { title: '商品管理', noCache: true }},
|
||||
{ path: 'attribute', component: _import('goods/attribute'), name: 'attribute', meta: { title: '商品参数', noCache: true }},
|
||||
{ path: 'specification', component: _import('goods/specification'), name: 'specification', meta: { title: '商品规格', noCache: true }},
|
||||
{ path: 'product', component: _import('goods/product'), name: 'product', meta: { title: '货品管理', noCache: true }},
|
||||
{ path: 'comment', component: _import('goods/comment'), name: 'comment', meta: { title: '用户评论', noCache: true }}
|
||||
{ path: 'list', component: _import('goods/list'), name: 'goodsList', meta: { title: '商品列表', noCache: true }},
|
||||
{ path: 'create', component: _import('goods/create'), name: 'goodsCreate', meta: { title: '商品上架', noCache: true }},
|
||||
{ path: 'edit', component: _import('goods/edit'), name: 'goodsEdit', meta: { title: '商品编辑', noCache: true }, hidden: true },
|
||||
{ path: 'comment', component: _import('goods/comment'), name: 'goodsComment', meta: { title: '商品评论', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/promotion',
|
||||
component: Layout,
|
||||
@@ -121,6 +119,7 @@ export const asyncRouterMap = [
|
||||
{ path: 'topic', component: _import('promotion/topic'), name: 'topic', meta: { title: '专题管理', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/sys',
|
||||
component: Layout,
|
||||
@@ -136,5 +135,21 @@ export const asyncRouterMap = [
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/stat',
|
||||
component: Layout,
|
||||
redirect: 'noredirect',
|
||||
name: 'statManage',
|
||||
meta: {
|
||||
title: '统计',
|
||||
icon: 'chart'
|
||||
},
|
||||
children: [
|
||||
{ path: 'user', component: _import('stat/user'), name: 'statUser', meta: { title: '用户统计', noCache: true }},
|
||||
{ path: 'order', component: _import('stat/order'), name: 'statOrder', meta: { title: '订单统计', noCache: true }},
|
||||
{ path: 'goods', component: _import('stat/goods'), name: 'statGoods', meta: { title: '商品统计', noCache: true }}
|
||||
]
|
||||
},
|
||||
|
||||
{ path: '*', redirect: '/404', hidden: true }
|
||||
]
|
||||
|
||||
@@ -26,22 +26,32 @@ service.interceptors.request.use(config => {
|
||||
service.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data
|
||||
if (res.errno === 502) {
|
||||
MessageBox.alert('系统内部错误,请联系管理员维护', '错误', {
|
||||
|
||||
if (res.errno === 501) {
|
||||
MessageBox.alert('系统未登录,请重新登录', '未登录', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject('error')
|
||||
} else if (res.errno !== 0) {
|
||||
MessageBox.alert('超时自动退出系统,请重新登录', '已退出', {
|
||||
confirmButtonText: '重新登录',
|
||||
type: 'error'
|
||||
}).then(() => {
|
||||
store.dispatch('FedLogOut').then(() => {
|
||||
location.reload()
|
||||
})
|
||||
})
|
||||
return Promise.reject('error')
|
||||
} else if (res.errno === 502) {
|
||||
MessageBox.alert('系统内部错误,请联系管理员维护', '错误', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject('error')
|
||||
} else if (res.errno === 503) {
|
||||
MessageBox.alert('请求业务目前未支持', '警告', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error'
|
||||
})
|
||||
return Promise.reject('error')
|
||||
} else if (res.errno !== 0) {
|
||||
// 非5xx的错误属于业务错误,留给具体页面处理
|
||||
return Promise.reject(response)
|
||||
} else {
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
<el-table-column align="center" width="150px" label="商品参数ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品ID" prop="goodsId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品参数名称" prop="attribute">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="商品参数值" prop="value">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<!-- 添加或修改对话框 -->
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品ID" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品参数名" prop="attribute">
|
||||
<el-input v-model="dataForm.attribute"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品参数值" prop="value">
|
||||
<el-input v-model="dataForm.value"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">确定</el-button>
|
||||
<el-button v-else type="primary" @click="updateData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listGoodsAttribute, createGoodsAttribute, updateGoodsAttribute, deleteGoodsAttribute } from '@/api/goods-attribute'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'GoodsAttribute',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
goodsId: undefined,
|
||||
sort: '+id'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
attribute: undefined,
|
||||
value: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
update: '编辑',
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
goodsId: [{ required: true, message: '商品ID不能为空', trigger: 'blur' }],
|
||||
attribute: [{ required: true, message: '商品参数名称不能为空', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '商品参数值不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listGoodsAttribute(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm() {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
attribute: undefined,
|
||||
value: undefined
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
createGoodsAttribute(this.dataForm).then(response => {
|
||||
this.list.unshift(response.data.data)
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.dialogStatus = 'update'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateGoodsAttribute(this.dataForm).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.dataForm.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.dataForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteGoodsAttribute(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['商品参数ID', '商品ID', '商品参数名称', '商品参数值']
|
||||
const filterVal = ['id', 'goodsId', 'attribute', 'value']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品参数信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -7,33 +7,33 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.valueId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column align="center" width="150px" label="评论ID" prop="id" sortable>
|
||||
<el-table-column align="center" label="用户ID" prop="userId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="100px" label="用户ID" prop="userId">
|
||||
<el-table-column align="center" label="商品ID" prop="valueId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="100px" label="商品ID" prop="valueId">
|
||||
<el-table-column align="center" label="评论内容" prop="content">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="评论内容" prop="content">
|
||||
<el-table-column align="center" label="评论图片" prop="picUrls">
|
||||
<template slot-scope="scope">
|
||||
<img v-for="item in scope.row.picUrls" :key="item" :src="item" width="40"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="评论图片" prop="picUrls">
|
||||
<el-table-column align="center" label="时间" prop="addTime">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="时间" prop="addTime">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -98,13 +98,9 @@
|
||||
<script>
|
||||
import { listComment, createComment, updateComment, deleteComment } from '@/api/comment'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Comment',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
@@ -115,7 +111,8 @@ export default {
|
||||
limit: 20,
|
||||
userId: undefined,
|
||||
valueId: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
@@ -123,8 +120,7 @@ export default {
|
||||
valueId: undefined,
|
||||
content: undefined,
|
||||
hasPicture: false,
|
||||
picUrls: [],
|
||||
addTime: undefined
|
||||
picUrls: []
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
@@ -174,8 +170,7 @@ export default {
|
||||
userId: undefined,
|
||||
valueId: undefined,
|
||||
content: undefined,
|
||||
picUrls: [],
|
||||
addTime: undefined
|
||||
picUrls: []
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
|
||||
543
litemall-admin/src/views/goods/create.vue
Normal file
543
litemall-admin/src/views/goods/create.vue
Normal file
@@ -0,0 +1,543 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品介绍</h3>
|
||||
<el-form :rules="rules" ref="goods" :model="goods" label-width="150px">
|
||||
<el-form-item label="商品编号" prop="goodsSn">
|
||||
<el-input v-model="goods.goodsSn"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input v-model="goods.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="专柜价格" prop="counterPrice">
|
||||
<el-input v-model="goods.counterPrice" placeholder="0.00">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前价格" prop="retailPrice">
|
||||
<el-input v-model="goods.retailPrice" placeholder="0.00">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否新品" prop="isNew">
|
||||
<el-radio-group v-model="goods.isNew">
|
||||
<el-radio :label="true">新品</el-radio>
|
||||
<el-radio :label="false">非新品</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否热卖" prop="isHot">
|
||||
<el-radio-group v-model="goods.isHot">
|
||||
<el-radio :label="false">普通</el-radio>
|
||||
<el-radio :label="true">热卖</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否在售" prop="isOnSale">
|
||||
<el-radio-group v-model="goods.isOnSale">
|
||||
<el-radio :label="true">在售</el-radio>
|
||||
<el-radio :label="false">未售</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品图片">
|
||||
<el-upload class="avatar-uploader" :action="uploadPath" list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadPicUrl">
|
||||
<img v-if="goods.picUrl" :src="goods.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="宣传画廊">
|
||||
<el-upload :action="uploadPath" :limit="5" multiple accept=".jpg,.jpeg,.png,.gif" list-type="picture-card" :on-exceed="uploadOverrun" :on-success="handleGalleryUrl" :on-remove="handleRemove">
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品单位">
|
||||
<el-input v-model="goods.unit" placeholder="件 / 个 / 盒"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="关键字">
|
||||
<el-tag :key="tag" v-for="tag in keywords" closable type="primary" @close="handleClose(tag)">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
<el-input class="input-new-keyword" v-if="newKeywordVisible" v-model="newKeyword" ref="newKeywordInput" size="small" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm">
|
||||
</el-input>
|
||||
<el-button v-else class="button-new-keyword" size="small" type="primary" @click="showInput">+ 增加</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属分类">
|
||||
<el-cascader expand-trigger="hover" :options="categoryList" @change="handleCategoryChange"></el-cascader>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属品牌商">
|
||||
<el-select v-model="goods.brandId">
|
||||
<el-option v-for="item in brandList" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品简介">
|
||||
<el-input v-model="goods.brief"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品详细介绍">
|
||||
<editor :init="editorInit" v-model="goods.desc"></editor>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品规格</h3>
|
||||
<el-row type="flex" align="middle" :gutter="20" style="padding:20px 0;">
|
||||
<el-col :span="10" >
|
||||
<el-radio-group v-model="multipleSpec" @change="specChanged">
|
||||
<el-radio-button :label="false" >默认标准规格</el-radio-button>
|
||||
<el-radio-button :label="true">多规格支持</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-col>
|
||||
<el-col :span="10" v-if="multipleSpec">
|
||||
<el-button :plain="true" @click="handleSpecificationShow" type="primary">添加</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-table :data="specifications">
|
||||
<el-table-column property="specification" label="规格名" ></el-table-column>
|
||||
<el-table-column property="value" label="规格值" >
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="primary">
|
||||
{{scope.row.value}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="picUrl" label="规格图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.picUrl" width="40" v-if="scope.row.picUrl"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width" v-if="multipleSpec">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" size="mini" @click="handleSpecificationDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置规格" :visible.sync="specVisiable">
|
||||
<el-form :rules="rules" ref="specForm" :model="specForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="规格名" prop="specification">
|
||||
<el-input v-model="specForm.specification"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格值" prop="value">
|
||||
<el-input v-model="specForm.value"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格图片" prop="picUrl">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadSpecPicUrl">
|
||||
<img v-if="specForm.picUrl" :src="specForm.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="specVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSpecificationAdd">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品库存</h3>
|
||||
<el-table :data="products">
|
||||
<el-table-column property="value" label="货品规格" >
|
||||
<template slot-scope="scope">
|
||||
<el-tag :key="tag" v-for="tag in scope.row.specifications">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="price" width="100" label="货品售价">
|
||||
</el-table-column>
|
||||
<el-table-column property="number" width="100" label="货品数量">
|
||||
</el-table-column>
|
||||
<el-table-column property="url" width="100" label="货品图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.url" width="40" v-if="scope.row.url"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleProductShow(scope.row)">设置</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置货品" :visible.sync="productVisiable">
|
||||
<el-form ref="productForm" :model="productForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="货品规格列" prop="specifications">
|
||||
<el-tag :key="tag" v-for="tag in productForm.specifications">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品售价" prop="price">
|
||||
<el-input v-model="productForm.price"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品数量" prop="number">
|
||||
<el-input v-model="productForm.number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品图片" prop="url">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadProductUrl">
|
||||
<img v-if="productForm.url" :src="productForm.url" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="productVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleProductEdit">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品参数</h3>
|
||||
<el-button :plain="true" @click="handleAttributeShow" type="primary">添加</el-button>
|
||||
<el-table :data="attributes">
|
||||
<el-table-column property="attribute" label="商品参数名称">
|
||||
</el-table-column>
|
||||
<el-table-column property="value" label="商品参数值">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" size="mini" @click="handleAttributeDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置商品参数" :visible.sync="attributeVisiable">
|
||||
<el-form ref="attributeForm" :model="attributeForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品参数名称" prop="attribute">
|
||||
<el-input v-model="attributeForm.attribute"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品参数值" prop="value">
|
||||
<el-input v-model="attributeForm.value"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="attributeVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleAttributeAdd">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<div class="op-container">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button @click="handlePublish" type="primary">上架</el-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.el-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.input-new-keyword {
|
||||
width: 90px;
|
||||
margin-left: 10px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { publishGoods, listCatAndBrand } from '@/api/goods'
|
||||
import { createStorage, uploadPath } from '@/api/storage'
|
||||
import Editor from '@tinymce/tinymce-vue'
|
||||
import { MessageBox } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'GoodsCreate',
|
||||
components: { Editor },
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
newKeywordVisible: false,
|
||||
newKeyword: '',
|
||||
keywords: [],
|
||||
categoryList: [],
|
||||
brandList: [],
|
||||
goods: { picUrl: '', gallery: [] },
|
||||
specVisiable: false,
|
||||
specForm: { specification: '', value: '', picUrl: '' },
|
||||
multipleSpec: false,
|
||||
specifications: [{ specification: '规格', value: '标准', picUrl: '' }],
|
||||
productVisiable: false,
|
||||
productForm: { id: 0, specifications: [], price: 0.00, number: 0, url: '' },
|
||||
products: [{ id: 0, specifications: ['标准'], price: 0.00, number: 0, url: '' }],
|
||||
attributeVisiable: false,
|
||||
attributeForm: { attribute: '', value: '' },
|
||||
attributes: [],
|
||||
rules: {
|
||||
goodsSn: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
editorInit: {
|
||||
language: 'zh_CN',
|
||||
plugins: ['advlist anchor autolink autoresize autosave emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace tabfocus table template textcolor textpattern visualblocks visualchars wordcount'],
|
||||
toolbar: ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript ', 'hr bullist numlist link image charmap preview anchor pagebreak fullscreen media table emoticons forecolor backcolor'],
|
||||
images_upload_handler: function(blobInfo, success, failure) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', blobInfo.blob())
|
||||
createStorage(formData).then(res => {
|
||||
success(res.data.data.url)
|
||||
}).catch(() => {
|
||||
failure('上传失败,请重新上传')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init: function() {
|
||||
listCatAndBrand().then(response => {
|
||||
this.categoryList = response.data.data.categoryList
|
||||
this.brandList = response.data.data.brandList
|
||||
})
|
||||
},
|
||||
handleCategoryChange(value) {
|
||||
this.goods.categoryId = value[value.length - 1]
|
||||
},
|
||||
handleCancel: function() {
|
||||
this.$router.push({ path: '/goods/goods' })
|
||||
},
|
||||
handlePublish: function() {
|
||||
const finalGoods = {
|
||||
goods: this.goods,
|
||||
specifications: this.specifications,
|
||||
products: this.products,
|
||||
attributes: this.attributes
|
||||
}
|
||||
publishGoods(finalGoods).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
this.$router.push({ path: '/goods/list' })
|
||||
}).catch(response => {
|
||||
MessageBox.alert('业务错误:' + response.data.errmsg, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
handleClose(tag) {
|
||||
this.keywords.splice(this.keywords.indexOf(tag), 1)
|
||||
this.goods.keywords = this.keywords.toString()
|
||||
},
|
||||
showInput() {
|
||||
this.newKeywordVisible = true
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.newKeywordInput.$refs.input.focus()
|
||||
})
|
||||
},
|
||||
handleInputConfirm() {
|
||||
const newKeyword = this.newKeyword
|
||||
if (newKeyword) {
|
||||
this.keywords.push(newKeyword)
|
||||
this.goods.keywords = this.keywords.toString()
|
||||
}
|
||||
this.newKeywordVisible = false
|
||||
this.newKeyword = ''
|
||||
},
|
||||
uploadPicUrl: function(response) {
|
||||
this.goods.picUrl = response.data.url
|
||||
},
|
||||
uploadOverrun: function() {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: '上传文件个数超出限制!最多上传5张图片!'
|
||||
})
|
||||
},
|
||||
handleGalleryUrl(response, file, fileList) {
|
||||
if (response.errno === 0) {
|
||||
this.goods.gallery.push(response.data.url)
|
||||
}
|
||||
},
|
||||
handleRemove: function(file, fileList) {
|
||||
for (var i = 0; i < this.goods.gallery.length; i++) {
|
||||
// 这里存在两种情况
|
||||
// 1. 如果所删除图片是刚刚上传的图片,那么图片地址是file.response.data.url
|
||||
// 此时的file.url虽然存在,但是是本机地址,而不是远程地址。
|
||||
// 2. 如果所删除图片是后台返回的已有图片,那么图片地址是file.url
|
||||
var url
|
||||
if (file.response === undefined) {
|
||||
url = file.url
|
||||
} else {
|
||||
url = file.response.data.url
|
||||
}
|
||||
|
||||
if (this.goods.gallery[i] === url) {
|
||||
this.goods.gallery.splice(i, 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
specChanged: function(label) {
|
||||
if (label === false) {
|
||||
this.specifications = [{ specification: '规格', value: '标准', picUrl: '' }]
|
||||
this.products = [{ id: 0, specifications: ['标准'], price: 0.00, number: 0, url: '' }]
|
||||
} else {
|
||||
this.specifications = []
|
||||
this.products = []
|
||||
}
|
||||
},
|
||||
uploadSpecPicUrl: function(response) {
|
||||
this.specForm.picUrl = response.data.url
|
||||
},
|
||||
handleSpecificationShow() {
|
||||
this.specForm = {}
|
||||
this.specVisiable = true
|
||||
},
|
||||
handleSpecificationAdd() {
|
||||
var index = this.specifications.length - 1
|
||||
for (var i = 0; i < this.specifications.length; i++) {
|
||||
const v = this.specifications[i]
|
||||
if (v.specification === this.specForm.specification) {
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
this.specifications.splice(index + 1, 0, this.specForm)
|
||||
this.specVisiable = false
|
||||
|
||||
this.specToProduct()
|
||||
},
|
||||
handleSpecificationDelete(row) {
|
||||
const index = this.specifications.indexOf(row)
|
||||
this.specifications.splice(index, 1)
|
||||
this.specToProduct()
|
||||
},
|
||||
specToProduct() {
|
||||
if (this.specifications.length === 0) {
|
||||
return
|
||||
}
|
||||
// 根据specifications创建临时规格列表
|
||||
var specValues = []
|
||||
var spec = this.specifications[0].specification
|
||||
var values = []
|
||||
values.push(0)
|
||||
|
||||
for (var i = 1; i < this.specifications.length; i++) {
|
||||
const aspec = this.specifications[i].specification
|
||||
|
||||
if (aspec === spec) {
|
||||
values.push(i)
|
||||
} else {
|
||||
specValues.push(values)
|
||||
spec = aspec
|
||||
values = []
|
||||
values.push(i)
|
||||
}
|
||||
}
|
||||
specValues.push(values)
|
||||
|
||||
// 根据临时规格列表生产货品规格
|
||||
// 算法基于 https://blog.csdn.net/tyhj_sf/article/details/53893125
|
||||
var productsIndex = 0
|
||||
var products = []
|
||||
var combination = []
|
||||
var n = specValues.length
|
||||
for (var s = 0; s < n; s++) {
|
||||
combination[s] = 0
|
||||
}
|
||||
var index = 0
|
||||
var isContinue = false
|
||||
do {
|
||||
var specifications = []
|
||||
for (var x = 0; x < n; x++) {
|
||||
var z = specValues[x][combination[x]]
|
||||
specifications.push(this.specifications[z].value)
|
||||
}
|
||||
products[productsIndex] = { id: productsIndex, specifications: specifications, price: 0.00, number: 0, url: '' }
|
||||
productsIndex++
|
||||
|
||||
index++
|
||||
combination[n - 1] = index
|
||||
for (var j = n - 1; j >= 0; j--) {
|
||||
if (combination[j] >= specValues[j].length) {
|
||||
combination[j] = 0
|
||||
index = 0
|
||||
if (j - 1 >= 0) {
|
||||
combination[j - 1] = combination[j - 1] + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
isContinue = false
|
||||
for (var p = 0; p < n; p++) {
|
||||
if (combination[p] !== 0) {
|
||||
isContinue = true
|
||||
}
|
||||
}
|
||||
} while (isContinue)
|
||||
|
||||
this.products = products
|
||||
},
|
||||
handleProductShow(row) {
|
||||
this.productForm = Object.assign({}, row)
|
||||
this.productVisiable = true
|
||||
},
|
||||
uploadProductUrl: function(response) {
|
||||
this.productForm.url = response.data.url
|
||||
},
|
||||
handleProductEdit() {
|
||||
for (var i = 0; i < this.products.length; i++) {
|
||||
const v = this.products[i]
|
||||
if (v.id === this.productForm.id) {
|
||||
this.products.splice(i, 1, this.productForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.productVisiable = false
|
||||
},
|
||||
handleAttributeShow() {
|
||||
this.attributeForm = {}
|
||||
this.attributeVisiable = true
|
||||
},
|
||||
handleAttributeAdd() {
|
||||
this.attributes.unshift(this.attributeForm)
|
||||
this.attributeVisiable = false
|
||||
},
|
||||
handleAttributeDelete(row) {
|
||||
const index = this.attributes.indexOf(row)
|
||||
this.attributes.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
554
litemall-admin/src/views/goods/edit.vue
Normal file
554
litemall-admin/src/views/goods/edit.vue
Normal file
@@ -0,0 +1,554 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品介绍</h3>
|
||||
<el-form :rules="rules" ref="goods" :model="goods" label-width="150px">
|
||||
<el-form-item label="商品编号" prop="goodsSn">
|
||||
<el-input v-model="goods.goodsSn"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input v-model="goods.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="专柜价格" prop="counterPrice">
|
||||
<el-input v-model="goods.counterPrice" placeholder="0.00">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前价格" prop="retailPrice">
|
||||
<el-input v-model="goods.retailPrice" placeholder="0.00">
|
||||
<template slot="append">元</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否新品" prop="isNew">
|
||||
<el-radio-group v-model="goods.isNew">
|
||||
<el-radio :label="true">新品</el-radio>
|
||||
<el-radio :label="false">非新品</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否热卖" prop="isHot">
|
||||
<el-radio-group v-model="goods.isHot">
|
||||
<el-radio :label="false">普通</el-radio>
|
||||
<el-radio :label="true">热卖</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否在售" prop="isOnSale">
|
||||
<el-radio-group v-model="goods.isOnSale">
|
||||
<el-radio :label="true">在售</el-radio>
|
||||
<el-radio :label="false">未售</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品图片">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadPicUrl">
|
||||
<img v-if="goods.picUrl" :src="goods.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="宣传画廊">
|
||||
<el-upload :action='uploadPath' :limit='5' multiple accept=".jpg,.jpeg,.png,.gif" :file-list="galleryFileList" list-type="picture-card" :on-exceed='uploadOverrun' :on-success="handleGalleryUrl" :on-remove="handleRemove">
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品单位">
|
||||
<el-input v-model="goods.unit" placeholder="件 / 个 / 盒"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="关键字">
|
||||
<el-tag :key="tag" v-for="tag in keywords" closable type="primary" @close="handleClose(tag)">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
<el-input class="input-new-keyword" v-if="newKeywordVisible" v-model="newKeyword" ref="newKeywordInput" size="small" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm">
|
||||
</el-input>
|
||||
<el-button v-else class="button-new-keyword" size="small" type="primary" @click="showInput">+ 增加</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属分类">
|
||||
<el-cascader expand-trigger="hover" :options="categoryList" v-model="categoryIds" @change="handleCategoryChange"></el-cascader>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="所属品牌商">
|
||||
<el-select v-model="goods.brandId">
|
||||
<el-option v-for="item in brandList" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品简介">
|
||||
<el-input v-model="goods.brief"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品详细介绍">
|
||||
<editor :init="editorInit" v-model="goods.desc"></editor>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品规格</h3>
|
||||
<el-button :plain="true" @click="handleSpecificationShow" type="primary">添加</el-button>
|
||||
|
||||
<el-table :data="specifications">
|
||||
<el-table-column property="specification" label="规格名" ></el-table-column>
|
||||
<el-table-column property="value" label="规格值" >
|
||||
<template slot-scope="scope">
|
||||
<el-tag type="primary">
|
||||
{{scope.row.value}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="picUrl" label="规格图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.picUrl" width="40" v-if="scope.row.picUrl"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" size="mini" @click="handleSpecificationDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置规格" :visible.sync="specVisiable">
|
||||
<el-form :rules="rules" ref="specForm" :model="specForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="规格名" prop="specification">
|
||||
<el-input v-model="specForm.specification"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格值" prop="value">
|
||||
<el-input v-model="specForm.value"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="规格图片" prop="picUrl">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadSpecPicUrl">
|
||||
<img v-if="specForm.picUrl" :src="specForm.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="specVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSpecificationAdd">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品库存</h3>
|
||||
<el-table :data="products">
|
||||
<el-table-column property="value" label="货品规格" >
|
||||
<template slot-scope="scope">
|
||||
<el-tag :key="tag" v-for="tag in scope.row.specifications">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column property="price" width="100" label="货品售价">
|
||||
</el-table-column>
|
||||
<el-table-column property="number" width="100" label="货品数量">
|
||||
</el-table-column>
|
||||
<el-table-column property="url" width="100" label="货品图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.url" width="40" v-if="scope.row.url"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleProductShow(scope.row)">设置</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置货品" :visible.sync="productVisiable">
|
||||
<el-form ref="productForm" :model="productForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="货品规格列" prop="specifications">
|
||||
<el-tag :key="tag" v-for="tag in productForm.specifications">
|
||||
{{tag}}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品售价" prop="price">
|
||||
<el-input v-model="productForm.price"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品数量" prop="number">
|
||||
<el-input v-model="productForm.number"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品图片" prop="url">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadProductUrl">
|
||||
<img v-if="productForm.url" :src="productForm.url" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="productVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleProductEdit">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<el-card class="box-card">
|
||||
<h3>商品参数</h3>
|
||||
<el-button :plain="true" @click="handleAttributeShow" type="primary">添加</el-button>
|
||||
<el-table :data="attributes">
|
||||
<el-table-column property="attribute" label="商品参数名称">
|
||||
</el-table-column>
|
||||
<el-table-column property="value" label="商品参数值">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" label="操作" width="100" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="danger" size="mini" @click="handleAttributeDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog title="设置商品参数" :visible.sync="attributeVisiable">
|
||||
<el-form ref="attributeForm" :model="attributeForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品参数名称" prop="attribute">
|
||||
<el-input v-model="attributeForm.attribute"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品参数值" prop="value">
|
||||
<el-input v-model="attributeForm.value"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="attributeVisiable = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleAttributeAdd">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
|
||||
<div class="op-container">
|
||||
<el-button @click="handleCancel">取消</el-button>
|
||||
<el-button @click="handleEdit" type="primary">更新商品</el-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.el-card {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.input-new-keyword {
|
||||
width: 90px;
|
||||
margin-left: 10px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { detailGoods, editGoods, listCatAndBrand } from '@/api/goods'
|
||||
import { createStorage, uploadPath } from '@/api/storage'
|
||||
import Editor from '@tinymce/tinymce-vue'
|
||||
import { MessageBox } from 'element-ui'
|
||||
|
||||
export default {
|
||||
name: 'GoodsEdit',
|
||||
components: { Editor },
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
newKeywordVisible: false,
|
||||
newKeyword: '',
|
||||
keywords: [],
|
||||
galleryFileList: [],
|
||||
categoryList: [],
|
||||
brandList: [],
|
||||
categoryIds: [],
|
||||
goods: { gallery: [] },
|
||||
specVisiable: false,
|
||||
specForm: { specification: '', value: '', picUrl: '' },
|
||||
specifications: [{ specification: '规格', value: '标准', picUrl: '' }],
|
||||
productVisiable: false,
|
||||
productForm: { id: 0, specifications: [], price: 0.00, number: 0, url: '' },
|
||||
products: [{ id: 0, specifications: ['标准'], price: 0.00, number: 0, url: '' }],
|
||||
attributeVisiable: false,
|
||||
attributeForm: { attribute: '', value: '' },
|
||||
attributes: [],
|
||||
rules: {
|
||||
goodsSn: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
editorInit: {
|
||||
language: 'zh_CN',
|
||||
plugins: ['advlist anchor autolink autoresize autosave emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace tabfocus table template textcolor textpattern visualblocks visualchars wordcount'],
|
||||
toolbar: ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript ', 'hr bullist numlist link image charmap preview anchor pagebreak fullscreen media table emoticons forecolor backcolor'],
|
||||
images_upload_handler: function(blobInfo, success, failure) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', blobInfo.blob())
|
||||
createStorage(formData).then(res => {
|
||||
success(res.data.data.url)
|
||||
}).catch(() => {
|
||||
failure('上传失败,请重新上传')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init: function() {
|
||||
if (this.$route.query.id == null) {
|
||||
return
|
||||
}
|
||||
|
||||
const goodsId = this.$route.query.id
|
||||
detailGoods(goodsId).then(response => {
|
||||
this.goods = response.data.data.goods
|
||||
this.specifications = response.data.data.specifications
|
||||
this.products = response.data.data.products
|
||||
this.attributes = response.data.data.attributes
|
||||
this.categoryIds = response.data.data.categoryIds
|
||||
|
||||
this.galleryFileList = []
|
||||
for (var i = 0; i < this.goods.gallery.length; i++) {
|
||||
this.galleryFileList.push({
|
||||
url: this.goods.gallery[i]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
listCatAndBrand().then(response => {
|
||||
this.categoryList = response.data.data.categoryList
|
||||
this.brandList = response.data.data.brandList
|
||||
})
|
||||
},
|
||||
handleCategoryChange(value) {
|
||||
this.goods.categoryId = value[value.length - 1]
|
||||
},
|
||||
handleCancel: function() {
|
||||
this.$router.push({ path: '/goods/list' })
|
||||
},
|
||||
handleEdit: function() {
|
||||
const finalGoods = {
|
||||
goods: this.goods,
|
||||
specifications: this.specifications,
|
||||
products: this.products,
|
||||
attributes: this.attributes
|
||||
}
|
||||
editGoods(finalGoods).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
this.$router.push({ path: '/goods/list' })
|
||||
}).catch(response => {
|
||||
MessageBox.alert('业务错误:' + response.data.errmsg, '警告', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
handleClose(tag) {
|
||||
this.keywords.splice(this.keywords.indexOf(tag), 1)
|
||||
this.goods.keywords = this.keywords.toString()
|
||||
},
|
||||
showInput() {
|
||||
this.newKeywordVisible = true
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.newKeywordInput.$refs.input.focus()
|
||||
})
|
||||
},
|
||||
handleInputConfirm() {
|
||||
const newKeyword = this.newKeyword
|
||||
if (newKeyword) {
|
||||
this.keywords.push(newKeyword)
|
||||
this.goods.keywords = this.keywords.toString()
|
||||
}
|
||||
this.newKeywordVisible = false
|
||||
this.newKeyword = ''
|
||||
},
|
||||
uploadPicUrl: function(response) {
|
||||
this.goods.picUrl = response.data.url
|
||||
},
|
||||
uploadOverrun: function() {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: '上传文件个数超出限制!最多上传5张图片!'
|
||||
})
|
||||
},
|
||||
handleGalleryUrl(response, file, fileList) {
|
||||
if (response.errno === 0) {
|
||||
this.goods.gallery.push(response.data.url)
|
||||
}
|
||||
},
|
||||
handleRemove: function(file, fileList) {
|
||||
for (var i = 0; i < this.goods.gallery.length; i++) {
|
||||
// 这里存在两种情况
|
||||
// 1. 如果所删除图片是刚刚上传的图片,那么图片地址是file.response.data.url
|
||||
// 此时的file.url虽然存在,但是是本机地址,而不是远程地址。
|
||||
// 2. 如果所删除图片是后台返回的已有图片,那么图片地址是file.url
|
||||
var url
|
||||
if (file.response === undefined) {
|
||||
url = file.url
|
||||
} else {
|
||||
url = file.response.data.url
|
||||
}
|
||||
|
||||
if (this.goods.gallery[i] === url) {
|
||||
this.goods.gallery.splice(i, 1)
|
||||
}
|
||||
}
|
||||
},
|
||||
specChanged: function(label) {
|
||||
if (label === false) {
|
||||
this.specifications = [{ specification: '规格', value: '标准', picUrl: '' }]
|
||||
this.products = [{ id: 0, specifications: ['标准'], price: 0.00, number: 0, url: '' }]
|
||||
} else {
|
||||
this.specifications = []
|
||||
this.products = []
|
||||
}
|
||||
},
|
||||
uploadSpecPicUrl: function(response) {
|
||||
this.specForm.picUrl = response.data.url
|
||||
},
|
||||
handleSpecificationShow() {
|
||||
this.specForm = {}
|
||||
this.specVisiable = true
|
||||
},
|
||||
handleSpecificationAdd() {
|
||||
var index = this.specifications.length - 1
|
||||
for (var i = 0; i < this.specifications.length; i++) {
|
||||
const v = this.specifications[i]
|
||||
if (v.specification === this.specForm.specification) {
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
this.specifications.splice(index + 1, 0, this.specForm)
|
||||
this.specVisiable = false
|
||||
|
||||
this.specToProduct()
|
||||
},
|
||||
handleSpecificationDelete(row) {
|
||||
const index = this.specifications.indexOf(row)
|
||||
this.specifications.splice(index, 1)
|
||||
this.specToProduct()
|
||||
},
|
||||
specToProduct() {
|
||||
if (this.specifications.length === 0) {
|
||||
return
|
||||
}
|
||||
// 根据specifications创建临时规格列表
|
||||
var specValues = []
|
||||
var spec = this.specifications[0].specification
|
||||
var values = []
|
||||
values.push(0)
|
||||
|
||||
for (var i = 1; i < this.specifications.length; i++) {
|
||||
const aspec = this.specifications[i].specification
|
||||
|
||||
if (aspec === spec) {
|
||||
values.push(i)
|
||||
} else {
|
||||
specValues.push(values)
|
||||
spec = aspec
|
||||
values = []
|
||||
values.push(i)
|
||||
}
|
||||
}
|
||||
specValues.push(values)
|
||||
|
||||
// 根据临时规格列表生产货品规格
|
||||
// 算法基于 https://blog.csdn.net/tyhj_sf/article/details/53893125
|
||||
var productsIndex = 0
|
||||
var products = []
|
||||
var combination = []
|
||||
var n = specValues.length
|
||||
for (var s = 0; s < n; s++) {
|
||||
combination[s] = 0
|
||||
}
|
||||
var index = 0
|
||||
var isContinue = false
|
||||
do {
|
||||
var specifications = []
|
||||
for (var x = 0; x < n; x++) {
|
||||
var z = specValues[x][combination[x]]
|
||||
specifications.push(this.specifications[z].value)
|
||||
}
|
||||
products[productsIndex] = { id: productsIndex, specifications: specifications, price: 0.00, number: 0, url: '' }
|
||||
productsIndex++
|
||||
|
||||
index++
|
||||
combination[n - 1] = index
|
||||
for (var j = n - 1; j >= 0; j--) {
|
||||
if (combination[j] >= specValues[j].length) {
|
||||
combination[j] = 0
|
||||
index = 0
|
||||
if (j - 1 >= 0) {
|
||||
combination[j - 1] = combination[j - 1] + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
isContinue = false
|
||||
for (var p = 0; p < n; p++) {
|
||||
if (combination[p] !== 0) {
|
||||
isContinue = true
|
||||
}
|
||||
}
|
||||
} while (isContinue)
|
||||
|
||||
this.products = products
|
||||
},
|
||||
handleProductShow(row) {
|
||||
this.productForm = Object.assign({}, row)
|
||||
this.productVisiable = true
|
||||
},
|
||||
uploadProductUrl: function(response) {
|
||||
this.productForm.url = response.data.url
|
||||
},
|
||||
handleProductEdit() {
|
||||
for (var i = 0; i < this.products.length; i++) {
|
||||
const v = this.products[i]
|
||||
if (v.id === this.productForm.id) {
|
||||
this.products.splice(i, 1, this.productForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.productVisiable = false
|
||||
},
|
||||
handleAttributeShow() {
|
||||
this.attributeForm = {}
|
||||
this.attributeVisiable = true
|
||||
},
|
||||
handleAttributeAdd() {
|
||||
this.attributes.unshift(this.attributeForm)
|
||||
this.attributeVisiable = false
|
||||
},
|
||||
handleAttributeDelete(row) {
|
||||
const index = this.attributes.indexOf(row)
|
||||
this.attributes.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,404 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品编号" v-model="listQuery.goodsSn">
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="props">
|
||||
<el-form label-position="left" class="demo-table-expand">
|
||||
<el-form-item label="首页主图">
|
||||
<span>{{ props.row.listPicUrl }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="宣传画廊">
|
||||
<span>{{ props.row.gallery }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品介绍">
|
||||
<span>{{ props.row.goodsBrief }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品详细介绍">
|
||||
<span>{{ props.row.goodsDesc }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品主图">
|
||||
<span>{{ props.row.primaryPicUrl }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品单位">
|
||||
<span>{{ props.row.goodsUnit }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字">
|
||||
<span>{{ props.row.keyword }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目ID">
|
||||
<span>{{ props.row.categoryId }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="品牌商ID">
|
||||
<span>{{ props.row.brandId }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="100px" label="商品ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品编号" prop="goodsSn">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="专柜价格" prop="counterPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="当前价格" prop="retailPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否新品" prop="isNew">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isNew ? 'success' : 'error' ">{{scope.row.isNew ? '新品' : '非新品'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否热品" prop="isHot">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isHot ? 'success' : 'error' ">{{scope.row.isHot ? '热品' : '非热品'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否在售" prop="isOnSale">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isOnSale ? 'success' : 'error' ">{{scope.row.isOnSale ? '在售' : '未售'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<el-tooltip placement="top" content="返回顶部">
|
||||
<back-to-top :visibilityHeight="100" ></back-to-top>
|
||||
</el-tooltip>
|
||||
|
||||
<!-- 添加或修改对话框 -->
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品编号" prop="goodsSn">
|
||||
<el-input v-model="dataForm.goodsSn"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品名称" prop="name">
|
||||
<el-input v-model="dataForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="专柜价格" prop="counterPrice">
|
||||
<el-input v-model="dataForm.counterPrice"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="当前价格" prop="retailPrice">
|
||||
<el-input v-model="dataForm.retailPrice"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否新品" prop="isNew">
|
||||
<el-select v-model="dataForm.isNew" placeholder="请选择">
|
||||
<el-option label="新品" :value="true">
|
||||
</el-option>
|
||||
<el-option label="新品" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否热品" prop="isHot">
|
||||
<el-select v-model="dataForm.isHot" placeholder="请选择">
|
||||
<el-option label="热品" :value="true">
|
||||
</el-option>
|
||||
<el-option label="非热品" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否在售" prop="isOnSale">
|
||||
<el-select v-model="dataForm.isOnSale" placeholder="请选择">
|
||||
<el-option label="在售" :value="true">
|
||||
</el-option>
|
||||
<el-option label="未售" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="首页主图">
|
||||
<el-input v-model="dataForm.listPicUrl"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="宣传画廊">
|
||||
<el-input v-model="dataForm.gallery"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品介绍">
|
||||
<el-input v-model="dataForm.goodsBrief"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item style="width: 700px;" label="商品详细介绍">
|
||||
<editor :init="editorInit" v-model="dataForm.goodsDesc"></editor>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品主图">
|
||||
<el-input v-model="dataForm.primaryPicUrl"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="商品单位">
|
||||
<el-input v-model="dataForm.goodsUnit"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="关键字">
|
||||
<el-input v-model="dataForm.keyword"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="类目ID">
|
||||
<el-input v-model="dataForm.categoryId"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="品牌商ID">
|
||||
<el-input v-model="dataForm.brandId"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">确定</el-button>
|
||||
<el-button v-else type="primary" @click="updateData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.el-dialog {
|
||||
width: 800px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listGoods, createGoods, updateGoods, deleteGoods } from '@/api/goods'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import BackToTop from '@/components/BackToTop'
|
||||
import Editor from '@tinymce/tinymce-vue'
|
||||
|
||||
export default {
|
||||
name: 'Goods',
|
||||
components: { BackToTop, Editor },
|
||||
directives: { waves },
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
goodsSn: undefined,
|
||||
name: undefined,
|
||||
sort: '+id'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
goodsSn: undefined,
|
||||
name: undefined,
|
||||
counterPrice: undefined,
|
||||
retailPrice: undefined,
|
||||
isHot: false,
|
||||
isNew: true,
|
||||
isOnSale: true,
|
||||
listPicUrl: undefined,
|
||||
primaryPicUrl: undefined,
|
||||
goodsBrief: undefined,
|
||||
goodsDesc: '',
|
||||
keywords: undefined,
|
||||
gallery: undefined,
|
||||
categoryId: undefined,
|
||||
brandId: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
update: '编辑',
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
goodsSn: [{ required: true, message: '商品编号不能为空', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false,
|
||||
editorInit: {
|
||||
language: 'zh_CN',
|
||||
plugins: ['advlist anchor autolink autoresize autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools importcss insertdatetime legacyoutput link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace tabfocus table template textcolor textpattern visualblocks visualchars wordcount'],
|
||||
toolbar: ['bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript ', 'hr bullist numlist link image charmap preview anchor pagebreak fullscreen media table emoticons forecolor backcolor'],
|
||||
images_upload_handler: function(blobInfo, success, failure) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', blobInfo.blob())
|
||||
createStorage(formData).then(res => {
|
||||
success(res.data.data.url)
|
||||
}).catch(() => {
|
||||
failure('上传失败,请重新上传')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listGoods(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm() {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
goodsSn: undefined,
|
||||
name: undefined,
|
||||
counterPrice: undefined,
|
||||
retailPrice: undefined,
|
||||
isHot: false,
|
||||
isNew: true,
|
||||
isOnSale: true,
|
||||
listPicUrl: undefined,
|
||||
primaryPicUrl: undefined,
|
||||
goodsBrief: undefined,
|
||||
goodsDesc: '',
|
||||
keywords: undefined,
|
||||
gallery: undefined,
|
||||
categoryId: undefined,
|
||||
brandId: undefined
|
||||
}
|
||||
},
|
||||
filterLevel(value, row) {
|
||||
return row.level === value
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
createGoods(this.dataForm).then(response => {
|
||||
this.list.unshift(response.data.data)
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.dialogStatus = 'update'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateGoods(this.dataForm).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.dataForm.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.dataForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteGoods(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['商品ID', '商品编号', '名称', '专柜价格', '当前价格', '是否新品', '是否热品', '是否在售', '首页主图', '宣传画廊', '商品介绍', '详细介绍', '商品主图', '商品单位', '关键字', '类目ID', '品牌商ID']
|
||||
const filterVal = ['id', 'goodsSn', 'name', 'counterPrice', 'retailPrice', 'isNew', 'isHot', 'isOnSale', 'listPicUrl', 'gallery', 'goodsBrief', 'goodsDesc', 'primaryPicUrl', 'goodsUnit', 'keywords', 'categoryId', 'brandId']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
214
litemall-admin/src/views/goods/list.vue
Normal file
214
litemall-admin/src/views/goods/list.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品编号" v-model="listQuery.goodsSn">
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="props">
|
||||
<el-form label-position="left" class="table-expand">
|
||||
<el-form-item label="宣传画廊">
|
||||
<img class="gallery" v-for="pic in props.row.gallery" :key="pic" :src="pic"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品介绍">
|
||||
<span>{{ props.row.brief }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品单位">
|
||||
<span>{{ props.row.unit }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="关键字">
|
||||
<span>{{ props.row.keyword }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目ID">
|
||||
<span>{{ props.row.categoryId }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="品牌商ID">
|
||||
<span>{{ props.row.brandId }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="商品编号" prop="goodsSn">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100" label="名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" property="iconUrl" label="图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.picUrl" width="40"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="详情" prop="desc">
|
||||
<template slot-scope="scope">
|
||||
<el-dialog title="商品详情" :visible.sync="descDialogVisible">
|
||||
<div v-html="descDetail"></div>
|
||||
</el-dialog>
|
||||
<el-button type="primary" size="mini" @click="showDesc(scope.row.desc)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="专柜价格" prop="counterPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="当前价格" prop="retailPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="是否新品" prop="isNew">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isNew ? 'success' : 'error' ">{{scope.row.isNew ? '新品' : '非新品'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="是否热品" prop="isHot">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isHot ? 'success' : 'error' ">{{scope.row.isHot ? '热品' : '非热品'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="是否在售" prop="isOnSale">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isOnSale ? 'success' : 'error' ">{{scope.row.isOnSale ? '在售' : '未售'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<el-tooltip placement="top" content="返回顶部">
|
||||
<back-to-top :visibilityHeight="100" ></back-to-top>
|
||||
</el-tooltip>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.table-expand label {
|
||||
width: 100px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.gallery {
|
||||
width: 80px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listGoods, deleteGoods } from '@/api/goods'
|
||||
import BackToTop from '@/components/BackToTop'
|
||||
|
||||
export default {
|
||||
name: 'GoodsList',
|
||||
components: { BackToTop },
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
total: 0,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
goodsSn: undefined,
|
||||
name: undefined,
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
descDetail: '',
|
||||
descDialogVisible: false,
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listGoods(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
handleCreate() {
|
||||
this.$router.push({ path: '/goods/create' })
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.$router.push({ path: '/goods/edit', query: { id: row.id }})
|
||||
},
|
||||
showDesc(desc) {
|
||||
this.descDetail = desc
|
||||
this.descDialogVisible = true
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteGoods(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['商品ID', '商品编号', '名称', '专柜价格', '当前价格', '是否新品', '是否热品', '是否在售', '首页主图', '宣传图片列表', '商品介绍', '详细介绍', '商品图片', '商品单位', '关键字', '类目ID', '品牌商ID']
|
||||
const filterVal = ['id', 'goodsSn', 'name', 'counterPrice', 'retailPrice', 'isNew', 'isHot', 'isOnSale', 'listPicUrl', 'gallery', 'brief', 'desc', 'picUrl', 'goodsUnit', 'keywords', 'categoryId', 'brandId']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,275 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="props">
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="100px" label="货品ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品ID" prop="goodsId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="150px" label="商品规格ID列表" prop="goodsSpecificationIds">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.goodsSpecificationIds.join(',') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="货品数量" prop="goodsNumber">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="货品价格" prop="retailPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="货品图片" prop="url">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<el-dialog title="添加货品" :visible.sync="createDialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品ID" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createDialogFormVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="createData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改对话框 -->
|
||||
<el-dialog title="修改货品" :visible.sync="editDialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品ID" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品规格ID列表" prop="goodsSpecificationIds">
|
||||
<el-input v-model="dataForm.goodsSpecificationIds" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品数量" prop="goodsNumber">
|
||||
<el-input v-model="dataForm.goodsNumber"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品价格" prop="retailPrice">
|
||||
<el-input v-model="dataForm.retailPrice"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="货品图片" prop="url">
|
||||
<el-input v-model="dataForm.url"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="editDialogFormVisible = false">取消</el-button>
|
||||
\ <el-button type="primary" @click="updateData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listProduct, createProduct, updateProduct, deleteProduct } from '@/api/product'
|
||||
import { createStorage } from '@/api/storage'
|
||||
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Product',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
goodsId: undefined,
|
||||
sort: '+id'
|
||||
},
|
||||
createDialogFormVisible: false,
|
||||
editDialogFormVisible: false,
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
goodsSpecificationIds: undefined,
|
||||
goodsNumber: 0,
|
||||
retailPrice: 0,
|
||||
url: undefined
|
||||
},
|
||||
rules: {
|
||||
goodsId: [{ required: true, message: '商品ID不能为空', trigger: 'blur' }],
|
||||
goodsSpecificationIds: [{ required: true, message: '商品规格ID列表不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listProduct(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm() {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
goodsSpecificationIds: undefined,
|
||||
goodsNumber: 0,
|
||||
retailPrice: 0,
|
||||
url: undefined
|
||||
}
|
||||
},
|
||||
uploadUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.url = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.createDialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
createProduct(this.dataForm).then(response => {
|
||||
this.getList()
|
||||
this.createDialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.editDialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateProduct(this.dataForm).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.dataForm.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.dataForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.editDialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteProduct(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['货品ID', '商品ID', '商品规格ID列表', '货品数量', '货品价格', '货品图片']
|
||||
const filterVal = ['id', 'goodsId', 'goodsSpecificationIds', 'goodsNumber', 'retailPrice', 'url']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '货品信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,226 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
<el-table-column align="center" width="150px" label="商品参数ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品ID" prop="goodsId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品规格名称" prop="specification">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="商品规格值" prop="value">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="商品规格图片" prop="picUrl">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<!-- 添加或修改对话框 -->
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="商品ID" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品规格名" prop="specification">
|
||||
<el-input v-model="dataForm.specification"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品规格值" prop="value">
|
||||
<el-input v-model="dataForm.value"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品规格图片" prop="picUrl">
|
||||
<el-input v-model="dataForm.picUrl"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">确定</el-button>
|
||||
<el-button v-else type="primary" @click="updateData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listGoodsSpecification, createGoodsSpecification, updateGoodsSpecification, deleteGoodsSpecification } from '@/api/goods-specification'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'GoodsSpecification',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
goodsId: undefined,
|
||||
sort: '+id'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
specification: undefined,
|
||||
value: undefined,
|
||||
picUrl: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
update: '编辑',
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
goodsId: [{ required: true, message: '商品ID不能为空', trigger: 'blur' }],
|
||||
specification: [{ required: true, message: '商品规格名称不能为空', trigger: 'blur' }],
|
||||
value: [{ required: true, message: '商品规格值不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listGoodsSpecification(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm() {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
goodsId: undefined,
|
||||
specification: undefined,
|
||||
value: undefined,
|
||||
picUrl: undefined
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
createGoodsSpecification(this.dataForm).then(response => {
|
||||
this.list.unshift(response.data.data)
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.dialogStatus = 'update'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateGoodsSpecification(this.dataForm).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.dataForm.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.dataForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteGoodsSpecification(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['商品规格ID', '商品ID', '商品规格名称', '商品规格值', '商品规格图片']
|
||||
const filterVal = ['id', 'goodsId', 'specification', 'value', 'picUrl']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品规格信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,10 +0,0 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'authredirect',
|
||||
created() {
|
||||
const hash = window.location.search.slice(1)
|
||||
window.opener.location.href = window.location.origin + '/login#' + hash
|
||||
window.close()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="login-container">
|
||||
<el-form class="login-form" autoComplete="on" :model="loginForm" :rules="loginRules" ref="loginForm" label-position="left">
|
||||
<div class="title-container">
|
||||
<h3 class="title">系统登录</h3>
|
||||
<h3 class="title">管理员登录</h3>
|
||||
</div>
|
||||
<el-form-item prop="username">
|
||||
<span class="svg-container svg-container_login">
|
||||
@@ -27,26 +27,13 @@
|
||||
<span>管理员用户名 : admin123</span>
|
||||
<span>管理员密码 : admin123</span>
|
||||
</div>
|
||||
|
||||
<el-button class="thirdparty-button" type="primary" @click="showDialog=true">第三方登录</el-button>
|
||||
</el-form>
|
||||
|
||||
<el-dialog title="第三方登录" :visible.sync="showDialog" append-to-body>
|
||||
本地不能模拟,请结合自己业务进行模拟!!!
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<social-sign />
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SocialSign from './socialsignin'
|
||||
|
||||
export default {
|
||||
components: { SocialSign },
|
||||
name: 'login',
|
||||
data() {
|
||||
const validateUsername = (rule, value, callback) => {
|
||||
@@ -73,8 +60,7 @@ export default {
|
||||
password: [{ required: true, trigger: 'blur', validator: validatePassword }]
|
||||
},
|
||||
passwordType: 'password',
|
||||
loading: false,
|
||||
showDialog: false
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -99,31 +85,7 @@ export default {
|
||||
return false
|
||||
}
|
||||
})
|
||||
},
|
||||
afterQRScan() {
|
||||
// const hash = window.location.hash.slice(1)
|
||||
// const hashObj = getQueryObject(hash)
|
||||
// const originUrl = window.location.origin
|
||||
// history.replaceState({}, '', originUrl)
|
||||
// const codeMap = {
|
||||
// wechat: 'code',
|
||||
// tencent: 'code'
|
||||
// }
|
||||
// const codeName = hashObj[codeMap[this.auth_type]]
|
||||
// if (!codeName) {
|
||||
// alert('第三方登录失败')
|
||||
// } else {
|
||||
// this.$store.dispatch('LoginByThirdparty', codeName).then(() => {
|
||||
// this.$router.push({ path: '/' })
|
||||
// })
|
||||
// }
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// window.addEventListener('hashchange', this.afterQRScan)
|
||||
},
|
||||
destroyed() {
|
||||
// window.removeEventListener('hashchange', this.afterQRScan)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -210,12 +172,6 @@ $light_gray:#eee;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.set-language {
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
.show-pwd {
|
||||
position: absolute;
|
||||
@@ -226,10 +182,5 @@ $light_gray:#eee;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
.thirdparty-button {
|
||||
position: absolute;
|
||||
right: 35px;
|
||||
bottom: 28px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<template>
|
||||
<div class="social-signup-container">
|
||||
<div class="sign-btn" @click="wechatHandleClick('wechat')">
|
||||
<span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon"></svg-icon></span> 微信
|
||||
</div>
|
||||
<div class="sign-btn" @click="tencentHandleClick('tencent')">
|
||||
<span class="qq-svg-container"><svg-icon icon-class="qq" class="icon"></svg-icon></span> QQ
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import openWindow from '@/utils/openWindow'
|
||||
|
||||
export default {
|
||||
name: 'social-signin',
|
||||
methods: {
|
||||
wechatHandleClick(thirdpart) {
|
||||
this.$store.commit('SET_AUTH_TYPE', thirdpart)
|
||||
const appid = 'xxxxx'
|
||||
const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/authredirect')
|
||||
const url = 'https://open.weixin.qq.com/connect/qrconnect?appid=' + appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=snsapi_login#wechat_redirect'
|
||||
openWindow(url, thirdpart, 540, 540)
|
||||
},
|
||||
tencentHandleClick(thirdpart) {
|
||||
this.$store.commit('SET_AUTH_TYPE', thirdpart)
|
||||
const client_id = 'xxxxx'
|
||||
const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/authredirect')
|
||||
const url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri
|
||||
openWindow(url, thirdpart, 540, 540)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.social-signup-container {
|
||||
margin: 20px 0;
|
||||
.sign-btn {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
.icon {
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.wx-svg-container,
|
||||
.qq-svg-container {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
padding-top: 1px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.wx-svg-container {
|
||||
background-color: #8dc349;
|
||||
}
|
||||
.qq-svg-container {
|
||||
background-color: #6BA2D6;
|
||||
margin-left: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -7,44 +7,33 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入品牌商名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="props">
|
||||
</template>
|
||||
<el-table-column align="center" label="品牌商ID" prop="id">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="150px" label="品牌商ID" prop="id" sortable>
|
||||
<el-table-column align="center" label="品牌商名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="品牌商名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="300px" label="介绍" prop="simpleDesc">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="50px" label="底价" prop="floorPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否显示" prop="isShow">
|
||||
<el-table-column align="center" property="picUrl" label="品牌商图片">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isShow ? 'success' : 'error' ">{{scope.row.isShow ? '可显示' : '不显示'}}</el-tag>
|
||||
<img :src="scope.row.picUrl" width="80" v-if="scope.row.picUrl"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否新上" prop="isNew">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isNew ? 'success' : 'error' ">{{scope.row.isShow ? '是' : '否'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" min-width="400px" label="介绍" prop="desc">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="底价" prop="floorPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -66,51 +55,17 @@
|
||||
<el-input v-model="dataForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="介绍" prop="simpleDesc">
|
||||
<el-input v-model="dataForm.simpleDesc"></el-input>
|
||||
<el-input v-model="dataForm.desc"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="品牌商图片" prop="picUrl">
|
||||
<el-input v-model="dataForm.picUrl"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadPicUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadPicUrl">
|
||||
<img v-if="dataForm.picUrl" :src="dataForm.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="宣传图片" prop="listPicUrl">
|
||||
<el-input v-model="dataForm.listPicUrl"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadListPicUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="APP宣传图片" prop="appListPicUrl">
|
||||
<el-input v-model="dataForm.appListPicUrl"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadAppListPicUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form-item>
|
||||
<el-form-item label="底价" prop="floorPrice">
|
||||
<el-input v-model="dataForm.floorPrice"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示" prop="isShow">
|
||||
<el-select v-model="dataForm.isShow" placeholder="请选择">
|
||||
<el-option label="显示" :value="true">
|
||||
</el-option>
|
||||
<el-option label="不显示" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否新上" prop="isNew">
|
||||
<el-select v-model="dataForm.isNew" placeholder="请选择">
|
||||
<el-option label="新上" :value="true">
|
||||
</el-option>
|
||||
<el-option label="不是新上" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="新上宣传图片" prop="newPicUrl" v-if="dataForm.isNew === 'true'">
|
||||
<el-input v-model="dataForm.newPicUrl"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadNewPicUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
@@ -123,31 +78,40 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listBrand, createBrand, updateBrand, deleteBrand } from '@/api/brand'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { uploadPath } from '@/api/storage'
|
||||
|
||||
export default {
|
||||
name: 'Brand',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
@@ -156,19 +120,15 @@ export default {
|
||||
limit: 20,
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
name: '',
|
||||
simpleDesc: '',
|
||||
desc: '',
|
||||
floorPrice: undefined,
|
||||
picUrl: undefined,
|
||||
listPicUrl: undefined,
|
||||
appListPicUrl: undefined,
|
||||
isShow: undefined,
|
||||
isNew: undefined,
|
||||
newPicUrl: undefined
|
||||
picUrl: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
@@ -177,7 +137,7 @@ export default {
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
name: [{ required: true, message: '类目名称不能为空', trigger: 'blur' }]
|
||||
name: [{ required: true, message: '品牌商名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
@@ -214,14 +174,9 @@ export default {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
name: '',
|
||||
simpleDesc: '',
|
||||
desc: '',
|
||||
floorPrice: undefined,
|
||||
picUrl: undefined,
|
||||
listPicUrl: undefined,
|
||||
appListPicUrl: undefined,
|
||||
isShow: undefined,
|
||||
isNew: undefined,
|
||||
newPicUrl: undefined
|
||||
picUrl: undefined
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
@@ -232,41 +187,8 @@ export default {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
uploadPicUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.picUrl = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
},
|
||||
uploadListPicUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.listPicUrl = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
},
|
||||
uploadAppListPicUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.appListPicUrl = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
},
|
||||
uploadNewPicUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.newPicUrl = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
uploadPicUrl: function(response) {
|
||||
this.dataForm.picUrl = response.data.url
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
@@ -329,8 +251,8 @@ export default {
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['品牌商ID', '品牌商名称', '介绍', '低价', '是否显示', '品牌商图片', '宣传图片', 'APP宣传图片', '是否新上', '新上宣传图片']
|
||||
const filterVal = ['id', 'name', 'simpleDesc', 'floorPrice', 'isShow', 'picUrl', 'listPicUrl', 'appListPicUrl', 'isNew', 'newPicUrl']
|
||||
const tHeader = ['品牌商ID', '品牌商名称', '介绍', '低价', '品牌商图片']
|
||||
const filterVal = ['id', 'name', 'desc', 'floorPrice', 'picUrl']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '品牌商信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
|
||||
@@ -7,62 +7,49 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入类目名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column type="expand">
|
||||
<template slot-scope="props">
|
||||
<el-form label-position="left" class="demo-table-expand">
|
||||
<el-form-item label="首页页面类目图标">
|
||||
<img :src="props.row.iconUrl">
|
||||
</el-form-item>
|
||||
<el-form-item label="首页页面类目横幅图片">
|
||||
<img :src="props.row.bannerUrl">
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页标题">
|
||||
<span>{{ props.row.frontName }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页介绍">
|
||||
<span>{{ props.row.frontDesc }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页横幅">
|
||||
<img :src="props.row.wapBannerUrl">
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table-column align="center" label="类目ID" prop="id">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="类目名" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" property="iconUrl" label="类目图标">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.iconUrl" width="40" v-if="scope.row.iconUrl"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" width="100px" label="类目ID" prop="id" sortable>
|
||||
<el-table-column align="center" property="picUrl" label="类目图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.picUrl" width="80" v-if="scope.row.picUrl"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="关键字" prop="keyword">
|
||||
<el-table-column align="center" label="关键字" prop="keyword">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="级别" prop="level"
|
||||
<el-table-column align="center" min-width="100" label="简介" prop="desc">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="级别" prop="level"
|
||||
:filters="[{ text: '一级类目', value: 'L1' }, { text: '二级类目', value: 'L2' }]" :filter-method="filterLevel">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.level === 'L1' ? 'primary' : 'info' ">{{scope.row.level === 'L1' ? '一级类目' : '二级类目'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="父类目ID" prop="parentId">
|
||||
<el-table-column align="center" label="父类目ID" prop="pid">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否显示" prop="isShow">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isShow ? 'success' : 'error' ">{{scope.row.isShow ? '可显示' : '不显示'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -83,47 +70,38 @@
|
||||
<el-form-item label="类目名称" prop="name">
|
||||
<el-input v-model="dataForm.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目关键字" prop="keyword">
|
||||
<el-form-item label="关键字" prop="keyword">
|
||||
<el-input v-model="dataForm.keyword"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目级别" prop="level">
|
||||
<el-select v-model="dataForm.level" placeholder="请选择">
|
||||
<el-form-item label="级别" prop="level">
|
||||
<el-select v-model="dataForm.level" @change="onLevelChange">
|
||||
<el-option label="一级类目" value="L1">
|
||||
</el-option>
|
||||
<el-option label="二级类目" value="L2">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="父类目" prop="parentId" v-if="dataForm.level === 'L2'">
|
||||
<el-select v-model="dataForm.parentId" placeholder="请选择">
|
||||
<el-option v-for="(key, val) in catL1" :key="key" :label="key" :value="val">
|
||||
<el-form-item label="父类目" prop="pid" v-if="dataForm.level === 'L2'">
|
||||
<el-select v-model="dataForm.pid">
|
||||
<el-option v-for="item in catL1" :key="item.value" :label="item.label" :value="item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="图标" prop="iconUrl">
|
||||
<el-input v-model="dataForm.iconUrl"></el-input>
|
||||
<el-upload action="http://localhost:8080/storage/create" :show-file-list="false" :on-success="handleIconUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<el-form-item label="类目图标" prop="iconUrl">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadIconUrl">
|
||||
<img v-if="dataForm.iconUrl" :src="dataForm.iconUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="首页横幅" prop="bannerUrl">
|
||||
<el-input v-model="dataForm.bannerUrl"></el-input>
|
||||
<el-upload action="http://localhost:8080/storage/create" :show-file-list="false" :on-success="handleBannerUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页标题" prop="frontName">
|
||||
<el-input v-model="dataForm.frontName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页介绍" prop="frontDesc">
|
||||
<el-input v-model="dataForm.frontDesc"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目页横幅" prop="wapBannerUrl">
|
||||
<el-input v-model="dataForm.wapBannerUrl"></el-input>
|
||||
<el-upload action="http://localhost:8080/storage/create" :show-file-list="false" :on-success="handleWapBannerUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<el-form-item label="类目图片" prop="picUrl">
|
||||
<el-upload class="avatar-uploader" :action='uploadPath' list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadPicUrl">
|
||||
<img v-if="dataForm.picUrl" :src="dataForm.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="类目简介" prop="desc">
|
||||
<el-input v-model="dataForm.desc"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
@@ -136,30 +114,40 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listCategory, listCatL1, createCategory, updateCategory, deleteCategory } from '@/api/category'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { uploadPath } from '@/api/storage'
|
||||
|
||||
export default {
|
||||
name: 'Category',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
@@ -168,21 +156,19 @@ export default {
|
||||
limit: 20,
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
catL1: {},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
name: '',
|
||||
keyword: '',
|
||||
level: 'L1',
|
||||
parentId: '',
|
||||
isShow: 'true',
|
||||
frontName: '',
|
||||
frontDesc: '',
|
||||
level: 'L2',
|
||||
pid: undefined,
|
||||
desc: '',
|
||||
iconUrl: undefined,
|
||||
bannerUrl: undefined,
|
||||
wapBannerUrl: undefined
|
||||
picUrl: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
@@ -191,8 +177,7 @@ export default {
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
name: [{ required: true, message: '类目名称不能为空', trigger: 'blur' }],
|
||||
keyword: [{ required: true, message: '类目关键字不能为空', trigger: 'blur' }]
|
||||
name: [{ required: true, message: '类目名不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
@@ -236,19 +221,21 @@ export default {
|
||||
id: undefined,
|
||||
name: '',
|
||||
keyword: '',
|
||||
level: 'L1',
|
||||
parentId: '',
|
||||
isShow: 'true',
|
||||
frontName: '',
|
||||
frontDesc: '',
|
||||
level: 'L2',
|
||||
pid: undefined,
|
||||
desc: '',
|
||||
iconUrl: undefined,
|
||||
bannerUrl: undefined,
|
||||
wapBannerUrl: undefined
|
||||
picUrl: undefined
|
||||
}
|
||||
},
|
||||
filterLevel(value, row) {
|
||||
filterLevel: function(value, row) {
|
||||
return row.level === value
|
||||
},
|
||||
onLevelChange: function(value) {
|
||||
if (value === 'L1') {
|
||||
this.pid = undefined
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
@@ -257,20 +244,11 @@ export default {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
handleIconUrl(response, file, fileList) {
|
||||
if (response.errno === 0) {
|
||||
this.dataForm.iconUrl = response.data.url
|
||||
}
|
||||
uploadIconUrl: function(response) {
|
||||
this.dataForm.iconUrl = response.data.url
|
||||
},
|
||||
handleBannerUrl(response, file, fileList) {
|
||||
if (response.errno === 0) {
|
||||
this.dataForm.bannerUrl = response.data.url
|
||||
}
|
||||
},
|
||||
handleWapBannerUrl(response, file, fileList) {
|
||||
if (response.errno === 0) {
|
||||
this.dataForm.wapBannerUrl = response.data.url
|
||||
}
|
||||
uploadPicUrl: function(response) {
|
||||
this.dataForm.picUrl = response.data.url
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
@@ -333,8 +311,8 @@ export default {
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['类目ID', '名称', '关键字', '级别', '父类目ID', '是否显示', '图标', '首页横幅', '类目页标题', '类目页介绍', '类目页横幅']
|
||||
const filterVal = ['id', 'name', 'keyword', 'level', 'parentId', 'isShow', 'iconUrl', 'bannerUrl', 'frontName', 'frontDesc', 'wapBannerUrl']
|
||||
const tHeader = ['类目ID', '名称', '关键字', '级别', '父类目ID', '类目图标', '类目图片', '简介']
|
||||
const filterVal = ['id', 'name', 'keyword', 'level', 'pid', 'iconUrl', 'picUrl', 'desc']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '商品类目信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入问题" v-model="listQuery.question">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -58,13 +58,9 @@
|
||||
|
||||
<script>
|
||||
import { listIssue, createIssue, updateIssue, deleteIssue } from '@/api/issue'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Issue',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -74,7 +70,8 @@ export default {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
question: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入跳转链接" v-model="listQuery.url">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -24,7 +24,7 @@
|
||||
<el-table-column align="center" min-width="300px" label="跳转链接" prop="url">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否热门" prop="isHot">
|
||||
<el-table-column align="center" min-width="100px" label="是否推荐" prop="isHot">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isHot ? 'success' : 'error' ">{{scope.row.isHot ? '是' : '否'}}</el-tag>
|
||||
</template>
|
||||
@@ -36,12 +36,6 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否显示" prop="isShow">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isShow ? 'success' : 'error' ">{{scope.row.isShow ? '可显示' : '不显示'}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
@@ -66,11 +60,11 @@
|
||||
<el-form-item label="跳转链接" prop="url">
|
||||
<el-input v-model="dataForm.url"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否热门" prop="isHot">
|
||||
<el-form-item label="是否推荐" prop="isHot">
|
||||
<el-select v-model="dataForm.isHot" placeholder="请选择">
|
||||
<el-option label="热门" :value="true">
|
||||
<el-option label="推荐" :value="true">
|
||||
</el-option>
|
||||
<el-option label="非热门" :value="false">
|
||||
<el-option label="普通" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -82,14 +76,6 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示" prop="isShow">
|
||||
<el-select v-model="dataForm.isShow" placeholder="请选择">
|
||||
<el-option label="显示" :value="true">
|
||||
</el-option>
|
||||
<el-option label="不显示" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
@@ -101,29 +87,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listKeyword, createKeyword, updateKeyword, deleteKeyword } from '@/api/keyword'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Keyword',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
@@ -134,15 +102,15 @@ export default {
|
||||
limit: 20,
|
||||
keyword: undefined,
|
||||
url: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
keyword: undefined,
|
||||
url: undefined,
|
||||
isNew: undefined,
|
||||
isDefault: undefined,
|
||||
isShow: undefined
|
||||
isHot: undefined,
|
||||
isDefault: undefined
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
@@ -151,8 +119,7 @@ export default {
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
keyword: [{ required: true, message: '关键词不能为空', trigger: 'blur' }],
|
||||
url: [{ required: true, message: '跳转链接称不能为空', trigger: 'blur' }]
|
||||
keyword: [{ required: true, message: '关键词不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
@@ -190,9 +157,8 @@ export default {
|
||||
id: undefined,
|
||||
keyword: undefined,
|
||||
url: undefined,
|
||||
isNew: undefined,
|
||||
isDefault: undefined,
|
||||
isShow: undefined
|
||||
isHot: undefined,
|
||||
isDefault: undefined
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
@@ -264,9 +230,9 @@ export default {
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['关键词ID', '关键词', '跳转链接', '是否新上', '是否默认', '是否显示']
|
||||
const filterVal = ['id', 'keyword', 'url', 'isNew', 'isDefault', 'isShow']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '关键词信息')
|
||||
const tHeader = ['关键词ID', '关键词', '跳转链接', '是否推荐', '是否默认']
|
||||
const filterVal = ['id', 'keyword', 'url', 'isHot', 'isDefault']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '关键词设置')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入订单编号" v-model="listQuery.orderSn">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -25,17 +25,14 @@
|
||||
<el-table-column align="center" min-width="100px" label="用户ID" prop="userId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="订单编号" prop="orderSn">
|
||||
<el-table-column align="center" min-width="200px" label="订单编号" prop="orderSn">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="订单状态" prop="orderStatus">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否删除" prop="isDelete">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isDelete ? 'success' : 'error' ">{{scope.row.isDelete ? '未删除' : '已删除'}}</el-tag>
|
||||
<el-tag>{{scope.row.orderStatus | orderStatusFilter}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="订单费用" prop="orderPrice">
|
||||
</el-table-column>
|
||||
@@ -43,10 +40,10 @@
|
||||
<el-table-column align="center" min-width="100px" label="实际费用" prop="actualPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleSend(scope.row)">发货</el-button>
|
||||
<el-button type="primary" size="mini" @click="handleRecv(scope.row)">收货</el-button>
|
||||
<el-button type="primary" size="mini" @click="handleShip(scope.row)" v-if="scope.row.orderStatus==201">发货</el-button>
|
||||
<el-button type="primary" size="mini" @click="handleRefund(scope.row)" v-if="scope.row.orderStatus==202">退款</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -59,46 +56,31 @@
|
||||
</div>
|
||||
|
||||
<!-- 发货对话框 -->
|
||||
<el-dialog title="发货" :visible.sync="sendDialogFormVisible">
|
||||
<el-form ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-dialog title="发货" :visible.sync="shipDialogVisible">
|
||||
<el-form ref="shipForm" :model="shipForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="快递公司" prop="shipChannel">
|
||||
<el-input v-model="dataForm.shipChannel"></el-input>
|
||||
<el-input v-model="shipForm.shipChannel"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递编号" prop="shipSn">
|
||||
<el-input v-model="dataForm.shipSn"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递发货时间" prop="shipStartTime">
|
||||
<el-date-picker v-model="dataForm.shipStartTime" type="datetime" placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
<el-input v-model="shipForm.shipSn"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="sendDialogFormVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="sendData">确定</el-button>
|
||||
<el-button @click="shipDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmShip">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 收货对话框 -->
|
||||
<el-dialog title="收货" :visible.sync="recvDialogFormVisible">
|
||||
<el-form ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="快递公司" prop="shipChannel">
|
||||
<el-input disabled v-model="dataForm.shipChannel"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递编号" prop="shipSn">
|
||||
<el-input disabled v-model="dataForm.shipSn"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递发货时间" prop="shipStartTime">
|
||||
<el-date-picker disabled v-model="dataForm.shipStartTime" type="datetime" placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="快递收货时间" prop="shipEndTime">
|
||||
<el-date-picker v-model="dataForm.shipEndTime" type="datetime" placeholder="选择日期时间">
|
||||
</el-date-picker>
|
||||
<!-- 退款对话框 -->
|
||||
<el-dialog title="退款" :visible.sync="refundDialogVisible">
|
||||
<el-form ref="refundForm" :model="refundForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="退款金额" prop="refundMoney">
|
||||
<el-input v-model="refundForm.refundMoney" :disabled="true"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="recvDialogFormVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="recvData">确定</el-button>
|
||||
<el-button @click="refundDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmRefund">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
@@ -120,14 +102,10 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listOrder, updateOrder } from '@/api/order'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { listOrder, shipOrder, refundOrder } from '@/api/order'
|
||||
|
||||
export default {
|
||||
name: 'Order',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
@@ -138,20 +116,39 @@ export default {
|
||||
limit: 20,
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
shipForm: {
|
||||
orderId: undefined,
|
||||
shipChannel: undefined,
|
||||
shipSn: undefined,
|
||||
shipStartTime: undefined,
|
||||
shipEndTime: undefined
|
||||
shipSn: undefined
|
||||
},
|
||||
sendDialogFormVisible: false,
|
||||
recvDialogFormVisible: false,
|
||||
shipDialogVisible: false,
|
||||
refundForm: {
|
||||
orderId: undefined,
|
||||
refundMoney: undefined
|
||||
},
|
||||
refundDialogVisible: false,
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
orderStatusFilter(status) {
|
||||
const statusMap = {
|
||||
'101': '未付款',
|
||||
'102': '已取消',
|
||||
'103': '已取消',
|
||||
'201': '已付款',
|
||||
'202': '申请退款',
|
||||
'203': '已退款',
|
||||
'301': '已发货',
|
||||
'401': '确认收货',
|
||||
'402': '确认收货'
|
||||
}
|
||||
return statusMap[status]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
@@ -180,69 +177,53 @@ export default {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm(row) {
|
||||
this.dataForm.id = row.id
|
||||
this.dataForm.shipChannel = row.shipChannel
|
||||
this.dataForm.shipSn = row.shipSn
|
||||
this.dataForm.shipStartTime = row.shipStartTime
|
||||
this.dataForm.shipEndTime = row.shipEndTime
|
||||
},
|
||||
handleSend(row) {
|
||||
this.resetForm(row)
|
||||
this.sendDialogFormVisible = true
|
||||
handleShip(row) {
|
||||
this.shipForm.orderId = row.id
|
||||
this.shipForm.shipChannel = row.shipChannel
|
||||
this.shipForm.shipSn = row.shipSn
|
||||
|
||||
this.shipDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
this.$refs['shipForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
sendData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
confirmShip() {
|
||||
this.$refs['shipForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateOrder(this.dataForm).then(response => {
|
||||
const updatedOrder = response.data.data
|
||||
for (const v of this.list) {
|
||||
if (v.id === updatedOrder.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, updatedOrder)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.sendDialogFormVisible = false
|
||||
shipOrder(this.shipForm).then(response => {
|
||||
this.shipDialogVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
message: '确认发货成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleRecv(row) {
|
||||
this.resetForm(row)
|
||||
this.recvDialogFormVisible = true
|
||||
handleRefund(row) {
|
||||
this.refundForm.orderId = row.id
|
||||
this.refundForm.refundMoney = row.actualPrice
|
||||
|
||||
this.refundDialogVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
this.$refs['refundForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
recvData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
confirmRefund() {
|
||||
this.$refs['refundForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateOrder(this.dataForm).then(response => {
|
||||
const updatedOrder = response.data.data
|
||||
for (const v of this.list) {
|
||||
if (v.id === updatedOrder.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, updatedOrder)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.recvDialogFormVisible = false
|
||||
refundOrder(this.refundForm).then(response => {
|
||||
this.refundDialogVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
message: '确认退款成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入行政区域编码" v-model="listQuery.code">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -46,13 +46,9 @@
|
||||
|
||||
<script>
|
||||
import { listRegion } from '@/api/region'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Keyword',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: undefined,
|
||||
@@ -62,8 +58,7 @@ export default {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
name: undefined,
|
||||
code: undefined,
|
||||
sort: '+id'
|
||||
code: undefined
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
|
||||
@@ -7,40 +7,43 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入广告内容" v-model="listQuery.content">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
|
||||
<el-table-column align="center" width="100px" label="广告ID" prop="id" sortable>
|
||||
<el-table-column align="center" label="广告ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="广告标题" prop="name">
|
||||
<el-table-column align="center" label="广告标题" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="广告内容" prop="content">
|
||||
<el-table-column align="center" label="广告内容" prop="content">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="广告图片" prop="url">
|
||||
<el-table-column align="center" label="广告图片" prop="url">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.url" width="80" v-if="scope.row.url"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="50px" label="广告位置" prop="position">
|
||||
<el-table-column align="center" label="广告位置" prop="position">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="200px" label="活动链接" prop="link">
|
||||
<el-table-column align="center" label="活动链接" prop="link">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否启用" prop="enabled">
|
||||
<el-table-column align="center" label="是否启用" prop="enabled">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.enabled ? 'success' : 'error' ">{{ scope.row.enabled ? '启用' : '不启用' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -65,9 +68,9 @@
|
||||
<el-input v-model="dataForm.content"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="广告图片" prop="url">
|
||||
<el-input v-model="dataForm.url"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadUrl">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<el-upload class="avatar-uploader" :action="uploadPath" list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadUrl">
|
||||
<img v-if="dataForm.url" :src="dataForm.url" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item label="广告位置" prop="position">
|
||||
@@ -99,31 +102,40 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listAd, createAd, updateAd, deleteAd } from '@/api/ad'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { uploadPath } from '@/api/storage'
|
||||
|
||||
export default {
|
||||
name: 'Ad',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
@@ -132,7 +144,8 @@ export default {
|
||||
limit: 20,
|
||||
name: undefined,
|
||||
content: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
@@ -204,14 +217,8 @@ export default {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
uploadUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.url = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
uploadUrl: function(response) {
|
||||
this.dataForm.url = response.data.url
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
|
||||
@@ -7,39 +7,41 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入专题子标题" v-model="listQuery.subtitle">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-edit" @click="handleCreate">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-download" @click="handleDownload" :loading="downloadLoading">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
|
||||
<el-table-column align="center" width="100px" label="专题ID" prop="id" sortable>
|
||||
<el-table-column align="center" label="专题标题" prop="title">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="专题标题" prop="title">
|
||||
<el-table-column align="center" label="专题子标题" min-width="200" prop="subtitle">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="专题子内容" prop="subtitle">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="400px" label="内容" prop="content">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="80px" label="底价" prop="priceInfo">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="80px" label="阅读数量" prop="readCount">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="是否显示" prop="isShow">
|
||||
<el-table-column align="center" property="picUrl" label="图片">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isShow ? 'success' : 'error' ">{{scope.row.isShow ? '显示' : '不显示'}}</el-tag>
|
||||
<img :src="scope.row.picUrl" width="80"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="专题详情" prop="content">
|
||||
<template slot-scope="scope">
|
||||
<el-dialog title="专题详情" :visible.sync="contentDialogVisible">
|
||||
<div v-html="contentDetail"></div>
|
||||
</el-dialog>
|
||||
<el-button type="primary" size="mini" @click="showContent(scope.row.content)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="底价" prop="price">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="阅读数量" prop="readCount">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" min-width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -67,23 +69,21 @@
|
||||
<el-form-item label="专题子标题" prop="subtitle">
|
||||
<el-input v-model="dataForm.subtitle"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="专题图片" prop="picUrl">
|
||||
<el-upload class="avatar-uploader" :action="uploadPath" list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadPicUrl">
|
||||
<img v-if="dataForm.picUrl" :src="dataForm.picUrl" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 700px;" label="专题内容">
|
||||
<editor :init="editorInit" v-model="dataForm.content"></editor>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品低价" prop="priceInfo">
|
||||
<el-input v-model="dataForm.priceInfo"></el-input>
|
||||
<el-form-item label="商品低价" prop="price">
|
||||
<el-input v-model="dataForm.price"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="阅读量" prop="readCount">
|
||||
<el-input v-model="dataForm.readCount"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示" prop="isShow">
|
||||
<el-select v-model="dataForm.isShow" placeholder="请选择">
|
||||
<el-option label="显示" :value="true">
|
||||
</el-option>
|
||||
<el-option label="不显示" :value="false">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
@@ -96,37 +96,46 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.demo-table-expand {
|
||||
font-size: 0;
|
||||
}
|
||||
.demo-table-expand label {
|
||||
width: 200px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.demo-table-expand .el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.el-dialog {
|
||||
width: 800px;
|
||||
}
|
||||
}
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listTopic, createTopic, updateTopic, deleteTopic } from '@/api/topic'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { createStorage, uploadPath } from '@/api/storage'
|
||||
import BackToTop from '@/components/BackToTop'
|
||||
import Editor from '@tinymce/tinymce-vue'
|
||||
|
||||
export default {
|
||||
name: 'Topic',
|
||||
components: { BackToTop, Editor },
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadPath,
|
||||
list: undefined,
|
||||
total: undefined,
|
||||
listLoading: true,
|
||||
@@ -135,17 +144,21 @@ export default {
|
||||
limit: 20,
|
||||
title: undefined,
|
||||
subtitle: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
titile: undefined,
|
||||
subtitle: undefined,
|
||||
picUrl: undefined,
|
||||
content: '',
|
||||
priceInfo: undefined,
|
||||
price: undefined,
|
||||
readCount: undefined,
|
||||
isShow: false
|
||||
goods: []
|
||||
},
|
||||
contentDetail: '',
|
||||
contentDialogVisible: false,
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
@@ -207,10 +220,11 @@ export default {
|
||||
id: undefined,
|
||||
titile: undefined,
|
||||
subtitle: undefined,
|
||||
picUrl: undefined,
|
||||
content: '',
|
||||
priceInfo: undefined,
|
||||
price: undefined,
|
||||
readCount: undefined,
|
||||
isShow: false
|
||||
goods: []
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
@@ -221,14 +235,8 @@ export default {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
uploadUrl(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.url = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
uploadPicUrl: function(response) {
|
||||
this.dataForm.picUrl = response.data.url
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
@@ -246,6 +254,10 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
showContent(content) {
|
||||
this.contentDetail = content
|
||||
this.contentDialogVisible = true
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.dialogStatus = 'update'
|
||||
@@ -291,8 +303,8 @@ export default {
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['专题ID', '专题标题', '专题子标题', '专题内容', '商品低价', '阅读量', '是否显示']
|
||||
const filterVal = ['id', 'title', 'subtitle', 'content', 'priceInfo', 'readCount', 'isShow']
|
||||
const tHeader = ['专题ID', '专题标题', '专题子标题', '专题内容', '专题图片', '商品低价', '阅读量', '专题商品']
|
||||
const filterVal = ['id', 'title', 'subtitle', 'content', 'picUrl', 'price', 'readCount', 'goods']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '专题信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
|
||||
37
litemall-admin/src/views/stat/goods.vue
Normal file
37
litemall-admin/src/views/stat/goods.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-line :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statGoods } from '@/api/stat'
|
||||
import VeLine from 'v-charts/lib/line'
|
||||
|
||||
export default {
|
||||
components: { VeLine },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statGoods().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'orders': '订单量',
|
||||
'products': '下单货品数量',
|
||||
'amount': '下单货品总额'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
37
litemall-admin/src/views/stat/order.vue
Normal file
37
litemall-admin/src/views/stat/order.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-line :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statOrder } from '@/api/stat'
|
||||
import VeLine from 'v-charts/lib/line'
|
||||
export default {
|
||||
components: { VeLine },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statOrder().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'orders': '订单量',
|
||||
'customers': '下单用户',
|
||||
'amount': '订单总额',
|
||||
'pcr': '客单价'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
38
litemall-admin/src/views/stat/user.vue
Normal file
38
litemall-admin/src/views/stat/user.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<ve-histogram :extend="chartExtend" :data="chartData" :settings="chartSettings"></ve-histogram>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { statUser } from '@/api/stat'
|
||||
import VeHistogram from 'v-charts/lib/histogram'
|
||||
|
||||
export default {
|
||||
components: { VeHistogram },
|
||||
data() {
|
||||
return {
|
||||
chartData: {},
|
||||
chartSettings: {},
|
||||
chartExtend: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
statUser().then(response => {
|
||||
this.chartData = response.data.data
|
||||
this.chartSettings = {
|
||||
labelMap: {
|
||||
'users': '用户增长数'
|
||||
}
|
||||
}
|
||||
this.chartExtend = {
|
||||
xAxis: { boundaryGap: true },
|
||||
series: {
|
||||
label: { show: true, position: 'top' }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -5,23 +5,26 @@
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入管理员名称" v-model="listQuery.username">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
<el-table-column align="center" width="100px" label="管理员ID" prop="id" sortable>
|
||||
<el-table-column align="center" label="管理员ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="管理员名称" prop="username">
|
||||
<el-table-column align="center" label="管理员名称" prop="username">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="管理员头像" prop="avatar">
|
||||
<el-table-column align="center" label="管理员头像" prop="avatar">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.avatar" width="40" v-if="scope.row.avatar"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -49,9 +52,9 @@
|
||||
<el-input type="password" v-model="dataForm.checkPassword" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="管理员头像" prop="avatar">
|
||||
<el-input v-model="dataForm.avatar"></el-input>
|
||||
<el-upload action="#" list-type="picture" :show-file-list="false" :limit="1" :http-request="uploadAvatar">
|
||||
<el-button size="small" type="primary">点击上传</el-button>
|
||||
<el-upload class="avatar-uploader" :action="uploadPath" list-type="picture-card" :show-file-list="false" accept=".jpg,.jpeg,.png,.gif" :on-success="uploadAvatar">
|
||||
<img v-if="dataForm.avatar" :src="dataForm.avatar" class="avatar">
|
||||
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -65,16 +68,38 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #20a0ff;
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { listAdmin, createAdmin, updateAdmin, deleteAdmin } from '@/api/admin'
|
||||
import { createStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
import { uploadPath } from '@/api/storage'
|
||||
|
||||
export default {
|
||||
name: 'Admin',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
var validatePass = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
@@ -96,6 +121,7 @@ export default {
|
||||
}
|
||||
}
|
||||
return {
|
||||
uploadPath,
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: true,
|
||||
@@ -103,7 +129,8 @@ export default {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
username: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
@@ -169,14 +196,8 @@ export default {
|
||||
avatar: undefined
|
||||
}
|
||||
},
|
||||
uploadAvatar(item) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', item.file)
|
||||
createStorage(formData).then(res => {
|
||||
this.dataForm.avatar = res.data.data.url
|
||||
}).catch(() => {
|
||||
this.$message.error('上传失败,请重新上传')
|
||||
})
|
||||
uploadAvatar: function(response) {
|
||||
this.dataForm.avatar = response.data.url
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
|
||||
@@ -7,32 +7,36 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入对象名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
<el-table-column align="center" width="100px" label="存储ID" prop="id" sortable>
|
||||
|
||||
<el-table-column align="center" label="对象KEY" prop="key">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="对象KEY" prop="key">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="对象名称" prop="name">
|
||||
<el-table-column align="center" label="对象名称" prop="name">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="对象类型" prop="type">
|
||||
<el-table-column align="center" label="对象类型" prop="type">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="对象大小" prop="size">
|
||||
<el-table-column align="center" label="对象大小" prop="size">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="访问链接" prop="url">
|
||||
</el-table-column>
|
||||
<el-table-column align="center" property="url" label="图片">
|
||||
<template slot-scope="scope">
|
||||
<img :src="scope.row.url" width="40"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="图片链接" prop="url">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -72,13 +76,9 @@
|
||||
|
||||
<script>
|
||||
import { listStorage, createStorage, updateStorage, deleteStorage } from '@/api/storage'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Storage',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -89,7 +89,8 @@ export default {
|
||||
limit: 20,
|
||||
key: undefined,
|
||||
name: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
createDialogVisible: false,
|
||||
dataForm: {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入收货人名称" v-model="listQuery.name">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -104,13 +104,9 @@
|
||||
<script>
|
||||
import { listAddress, createAddress, updateAddress, deleteAddress } from '@/api/address'
|
||||
import { listSubRegion } from '@/api/region'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'UserAddress',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -121,7 +117,8 @@ export default {
|
||||
limit: 20,
|
||||
name: undefined,
|
||||
userId: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
provinces: {},
|
||||
cities: {},
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
|
||||
<!-- 查询和其他操作 -->
|
||||
<div class="filter-container">
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入用户ID" v-model="listQuery.userId">
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
<el-table size="small" :data="list" v-loading="listLoading" element-loading-text="正在查询中。。。" border fit highlight-current-row>
|
||||
<el-table-column align="center" width="100px" label="购物车ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="用户ID" prop="userId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品ID" prop="goodsId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品编码" prop="goodsSn">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品名称" prop="goodsName">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="商品图片" prop="picUrl">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="货品ID" prop="productId">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="货品价格" prop="retailPrice">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="货品数量" prop="number">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="listQuery.page"
|
||||
:page-sizes="[10,20,30,50]" :page-size="listQuery.limit" layout="total, sizes, prev, pager, next, jumper" :total="total">
|
||||
</el-pagination>
|
||||
</div>
|
||||
|
||||
<!-- 添加或修改对话框 -->
|
||||
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible">
|
||||
<el-form :rules="rules" ref="dataForm" :model="dataForm" status-icon label-position="left" label-width="100px" style='width: 400px; margin-left:50px;'>
|
||||
<el-form-item label="用户ID" prop="userId">
|
||||
<el-input v-model="dataForm.userId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品ID" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品编码" prop="goodsId">
|
||||
<el-input v-model="dataForm.goodsId"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">取消</el-button>
|
||||
<el-button v-if="dialogStatus=='create'" type="primary" @click="createData">确定</el-button>
|
||||
<el-button v-else type="primary" @click="updateData">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listCart, createCart, updateCart, deleteCart } from '@/api/cart'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'FootPrint',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
total: null,
|
||||
listLoading: true,
|
||||
listQuery: {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
userId: undefined,
|
||||
goodsId: undefined,
|
||||
sort: '+id'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
userId: '',
|
||||
goodsId: '',
|
||||
productId: ''
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
textMap: {
|
||||
update: '编辑',
|
||||
create: '创建'
|
||||
},
|
||||
rules: {
|
||||
userId: [{ required: true, message: '用户ID不能为空', trigger: 'blur' }],
|
||||
goodsId: [{ required: true, message: '商品ID不能为空', trigger: 'blur' }],
|
||||
productId: [{ required: true, message: '货品ID不能为空', trigger: 'blur' }]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
this.listLoading = true
|
||||
listCart(this.listQuery).then(response => {
|
||||
this.list = response.data.data.items
|
||||
this.total = response.data.data.total
|
||||
this.listLoading = false
|
||||
}).catch(() => {
|
||||
this.list = []
|
||||
this.total = 0
|
||||
this.listLoading = false
|
||||
})
|
||||
},
|
||||
handleFilter() {
|
||||
this.listQuery.page = 1
|
||||
this.getList()
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.listQuery.limit = val
|
||||
this.getList()
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.listQuery.page = val
|
||||
this.getList()
|
||||
},
|
||||
resetForm() {
|
||||
this.dataForm = {
|
||||
id: undefined,
|
||||
userId: '',
|
||||
goodsId: '',
|
||||
productId: ''
|
||||
}
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
createData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
createCart(this.dataForm).then(response => {
|
||||
this.list.unshift(response.data.data)
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '创建成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.dataForm = Object.assign({}, row)
|
||||
this.dialogStatus = 'update'
|
||||
this.dialogFormVisible = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs['dataForm'].clearValidate()
|
||||
})
|
||||
},
|
||||
updateData() {
|
||||
this.$refs['dataForm'].validate((valid) => {
|
||||
if (valid) {
|
||||
updateCart(this.dataForm).then(() => {
|
||||
for (const v of this.list) {
|
||||
if (v.id === this.dataForm.id) {
|
||||
const index = this.list.indexOf(v)
|
||||
this.list.splice(index, 1, this.dataForm)
|
||||
break
|
||||
}
|
||||
}
|
||||
this.dialogFormVisible = false
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '更新成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
deleteCart(row).then(response => {
|
||||
this.$notify({
|
||||
title: '成功',
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
const index = this.list.indexOf(row)
|
||||
this.list.splice(index, 1)
|
||||
})
|
||||
},
|
||||
handleDownload() {
|
||||
this.downloadLoading = true
|
||||
import('@/vendor/Export2Excel').then(excel => {
|
||||
const tHeader = ['购物车ID', '用户ID', '商品ID', '商品名称', '商品编号', '商品图片', '货品ID', '货品价格', '货品数量']
|
||||
const filterVal = ['id', 'userId', 'goodsId', 'goodsName', 'goodsSn', 'pic_url', 'productId', 'retailPrice', 'number']
|
||||
excel.export_json_to_excel2(tHeader, this.list, filterVal, '用户购物车信息')
|
||||
this.downloadLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.valueId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -67,13 +67,9 @@
|
||||
|
||||
<script>
|
||||
import { listCollect, createCollect, updateCollect, deleteCollect } from '@/api/collect'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'Collect',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -84,7 +80,8 @@ export default {
|
||||
limit: 20,
|
||||
userId: undefined,
|
||||
valueId: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入商品ID" v-model="listQuery.goodsId">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -67,13 +67,9 @@
|
||||
|
||||
<script>
|
||||
import { listFootprint, createFootprint, updateFootprint, deleteFootprint } from '@/api/footprint'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'FootPrint',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -84,7 +80,8 @@ export default {
|
||||
limit: 20,
|
||||
userId: undefined,
|
||||
goodsId: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入搜索历史关键字" v-model="listQuery.keyword">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -66,13 +66,9 @@
|
||||
|
||||
<script>
|
||||
import { listHistory, createHistory, updateHistory, deleteHistory } from '@/api/history'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'History',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: null,
|
||||
@@ -83,7 +79,8 @@ export default {
|
||||
limit: 20,
|
||||
userId: undefined,
|
||||
keyword: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
</el-input>
|
||||
<el-input clearable class="filter-item" style="width: 200px;" placeholder="请输入手机号" v-model="listQuery.mobile">
|
||||
</el-input>
|
||||
<el-button class="filter-item" type="primary" v-waves icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">查找</el-button>
|
||||
<el-button class="filter-item" type="primary" @click="handleCreate" icon="el-icon-edit">添加</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" v-waves icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
<el-button class="filter-item" type="primary" :loading="downloadLoading" icon="el-icon-download" @click="handleDownload">导出</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 查询结果 -->
|
||||
@@ -17,29 +17,34 @@
|
||||
<el-table-column align="center" width="100px" label="用户ID" prop="id" sortable>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="用户名" prop="username">
|
||||
<el-table-column align="center" label="用户名" prop="username">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="手机号码" prop="mobile">
|
||||
<el-table-column align="center" label="手机号码" prop="mobile">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="50px" label="性别" prop="gender">
|
||||
<el-table-column align="center" label="性别" prop="gender">
|
||||
<template slot-scope="scope">
|
||||
<el-tag >{{genderDic[scope.row.status]}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="生日" prop="birthday">
|
||||
<el-table-column align="center" label="生日" prop="birthday">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="用户等级" prop="userLevel">
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" min-width="100px" label="状态" prop="status"
|
||||
:filters="[{ text: '可用', value: '可用' }, { text: '禁用', value: '禁用' }, { text: '删除', value: '删除' }]" :filter-method="filterStatus">
|
||||
<el-table-column align="center" label="用户等级" prop="userLevel">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status | statusFilter">{{scope.row.status}}</el-tag>
|
||||
<el-tag >{{levelDic[scope.row.userLevel]}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="状态" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<el-tag>{{statusDic[scope.row.status]}}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column align="center" label="操作" width="250" class-name="small-padding fixed-width">
|
||||
<el-table-column align="center" label="操作" width="200" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button>
|
||||
<el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>
|
||||
@@ -70,36 +75,36 @@
|
||||
<el-input type="password" v-model="dataForm.checkPassword" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<el-select v-model="dataForm.gender" placeholder="请选择">
|
||||
<el-option label="未知" value="未知">
|
||||
<el-select v-model="dataForm.gender">
|
||||
<el-option label="未知" :value="0">
|
||||
</el-option>
|
||||
<el-option label="男" value="男">
|
||||
<el-option label="男" :value="1">
|
||||
</el-option>
|
||||
<el-option label="女" value="女">
|
||||
<el-option label="女" :value="2">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="生日" prop="birthday">
|
||||
<el-date-picker v-model="dataForm.birthday" type="date" placeholder="选择日期" value-format="yyyy-MM-dd">
|
||||
<el-date-picker v-model="dataForm.birthday" type="date" value-format="yyyy-MM-dd">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户等级" prop="userLevel">
|
||||
<el-select v-model="dataForm.userLevel" placeholder="请选择">
|
||||
<el-option label="普通用户" value="普通用户">
|
||||
<el-select v-model="dataForm.userLevel">
|
||||
<el-option label="普通用户" :value="0">
|
||||
</el-option>
|
||||
<el-option label="VIP用户" value="VIP用户">
|
||||
<el-option label="VIP用户" :value="1">
|
||||
</el-option>
|
||||
<el-option label="高级VIP用户" value="高级VIP用户">
|
||||
<el-option label="高级VIP用户" :value="2">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="dataForm.status" placeholder="请选择">
|
||||
<el-option label="可用" value="可用">
|
||||
<el-select v-model="dataForm.status">
|
||||
<el-option label="可用" :value="0">
|
||||
</el-option>
|
||||
<el-option label="禁用" value="禁用">
|
||||
<el-option label="禁用" :value="1">
|
||||
</el-option>
|
||||
<el-option label="删除" value="删除">
|
||||
<el-option label="注销" :value="2">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -116,13 +121,9 @@
|
||||
|
||||
<script>
|
||||
import { fetchList, createUser, updateUser } from '@/api/user'
|
||||
import waves from '@/directive/waves' // 水波纹指令
|
||||
|
||||
export default {
|
||||
name: 'User',
|
||||
directives: {
|
||||
waves
|
||||
},
|
||||
data() {
|
||||
var validatePass = (rule, value, callback) => {
|
||||
if (value === '') {
|
||||
@@ -152,7 +153,8 @@ export default {
|
||||
limit: 20,
|
||||
username: undefined,
|
||||
mobile: undefined,
|
||||
sort: '+id'
|
||||
sort: 'add_time',
|
||||
order: 'desc'
|
||||
},
|
||||
dataForm: {
|
||||
id: undefined,
|
||||
@@ -160,10 +162,10 @@ export default {
|
||||
mobile: '',
|
||||
password: undefined,
|
||||
checkPassword: undefined,
|
||||
gender: '男',
|
||||
userLevel: '普通用户',
|
||||
gender: 0,
|
||||
userLevel: 0,
|
||||
birthday: undefined,
|
||||
status: '可用'
|
||||
status: 0
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
dialogStatus: '',
|
||||
@@ -183,17 +185,10 @@ export default {
|
||||
{ validator: validatePass2, trigger: 'blur' }
|
||||
]
|
||||
},
|
||||
downloadLoading: false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
statusFilter(status) {
|
||||
const statusMap = {
|
||||
'可用': 'success',
|
||||
'禁用': 'info',
|
||||
'删除': 'danger'
|
||||
}
|
||||
return statusMap[status]
|
||||
downloadLoading: false,
|
||||
genderDic: ['未知', '男', '女'],
|
||||
levelDic: ['普通用户', 'VIP用户', '高级VIP用户'],
|
||||
statusDic: ['可用', '禁用', '注销']
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -231,15 +226,12 @@ export default {
|
||||
mobile: '',
|
||||
pass: undefined,
|
||||
checkPass: undefined,
|
||||
gender: '男',
|
||||
userLevel: '普通用户',
|
||||
gender: 0,
|
||||
userLevel: 0,
|
||||
birthday: undefined,
|
||||
status: '可用'
|
||||
status: 0
|
||||
}
|
||||
},
|
||||
filterStatus(value, row) {
|
||||
return row.status === value
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetForm()
|
||||
this.dialogStatus = 'create'
|
||||
|
||||
@@ -47,6 +47,21 @@
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
@@ -25,3 +25,7 @@ logging.level.root=ERROR
|
||||
logging.level.org.springframework=ERROR
|
||||
logging.level.org.mybatis=ERROR
|
||||
logging.level.org.linlinjava.litemall=DEBUG
|
||||
|
||||
# 开发者应该设置成自己的域名,必须附带http或者https
|
||||
org.linlinjava.litemall.os.address=http://122.152.206.172
|
||||
org.linlinjava.litemall.os.port=8080
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
@@ -25,3 +25,7 @@ logging.level.root=ERROR
|
||||
logging.level.org.springframework=ERROR
|
||||
logging.level.org.mybatis=ERROR
|
||||
logging.level.org.linlinjava.litemall=DEBUG
|
||||
|
||||
# 开发者应该设置成自己的域名,必须附带http或者https
|
||||
org.linlinjava.litemall.os.address=http://127.0.0.1
|
||||
org.linlinjava.litemall.os.port=8080
|
||||
|
||||
@@ -7,9 +7,9 @@ spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true
|
||||
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
|
||||
spring.datasource.druid.username=litemall
|
||||
spring.datasource.druid.password=litemall123456
|
||||
spring.datasource.druid.initial-size=50
|
||||
spring.datasource.druid.max-active=100
|
||||
spring.datasource.druid.min-idle=20
|
||||
spring.datasource.druid.initial-size=10
|
||||
spring.datasource.druid.max-active=50
|
||||
spring.datasource.druid.min-idle=10
|
||||
spring.datasource.druid.max-wait=60000
|
||||
spring.datasource.druid.pool-prepared-statements=true
|
||||
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
|
||||
@@ -23,4 +23,8 @@ spring.datasource.druid.filters=stat,wall,log4j
|
||||
logging.level.root=ERROR
|
||||
logging.level.org.springframework=ERROR
|
||||
logging.level.org.mybatis=ERROR
|
||||
logging.level.org.linlinjava.litemall=ERROR
|
||||
logging.level.org.linlinjava.litemall=ERROR
|
||||
|
||||
# 开发者应该设置成自己的域名,必须附带http或者https
|
||||
org.linlinjava.litemall.os.address=https://www.example.com
|
||||
org.linlinjava.litemall.os.port=443
|
||||
@@ -34,4 +34,21 @@
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,15 +1,18 @@
|
||||
package org.linlinjava.litemall.core.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@@ -19,18 +22,24 @@ import java.time.format.DateTimeFormatter;
|
||||
|
||||
@Configuration
|
||||
public class JacksonConfig {
|
||||
@Bean
|
||||
@Primary
|
||||
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
|
||||
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
return objectMapper;
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public Jackson2ObjectMapperBuilderCustomizer customJackson() {
|
||||
return new Jackson2ObjectMapperBuilderCustomizer() {
|
||||
@Override
|
||||
public void customize(Jackson2ObjectMapperBuilder builder) {
|
||||
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
builder.serializerByType(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
builder.serializerByType(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
|
||||
builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
builder.serializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
builder.failOnUnknownProperties(false);
|
||||
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,22 @@ public class JacksonUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Byte parseByte(String body, String field) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode node = null;
|
||||
try {
|
||||
node = mapper.readTree(body);
|
||||
JsonNode leaf = node.get(field);
|
||||
if(leaf != null) {
|
||||
Integer value = leaf.asInt();
|
||||
return value.byteValue();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static <T> T parseObject(String body, String field, Class<T> clazz) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
JsonNode node = null;
|
||||
@@ -112,4 +128,5 @@ public class JacksonUtil {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,46 +41,27 @@ public class ResponseUtil {
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static Object fail401() {
|
||||
return fail(401, "请登录");
|
||||
|
||||
|
||||
public static Object badArgument(){
|
||||
return fail(401, "参数不对");
|
||||
}
|
||||
|
||||
|
||||
public static Object badArgumentValue(){
|
||||
return fail(402, "参数值不对");
|
||||
}
|
||||
|
||||
public static Object unlogin(){
|
||||
return fail401();
|
||||
}
|
||||
|
||||
public static Object fail402() {
|
||||
return fail(402, "参数不对");
|
||||
}
|
||||
|
||||
public static Object badArgument(){
|
||||
return fail402();
|
||||
}
|
||||
|
||||
public static Object fail403() {
|
||||
return fail(403, "参数值不对");
|
||||
}
|
||||
|
||||
public static Object badArgumentValue(){
|
||||
return fail403();
|
||||
}
|
||||
|
||||
public static Object fail501() {
|
||||
return fail(501, "业务不支持");
|
||||
}
|
||||
|
||||
public static Object unsupport(){
|
||||
return fail501();
|
||||
}
|
||||
|
||||
public static Object fail502() {
|
||||
return fail(502, "系统内部错误");
|
||||
return fail(501, "请登录");
|
||||
}
|
||||
|
||||
public static Object serious(){
|
||||
return fail502();
|
||||
return fail(502, "系统内部错误");
|
||||
}
|
||||
|
||||
|
||||
public static Object unsupport(){
|
||||
return fail(503, "业务不支持");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
<table tableName="litemall_admin">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="last_login_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="update_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_brand">
|
||||
@@ -76,7 +75,7 @@
|
||||
</table>
|
||||
<table tableName="litemall_cart">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride column="goods_specification_ids" javaType="java.lang.Integer[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
|
||||
<columnOverride column="specifications" javaType="java.lang.String[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_category">
|
||||
@@ -92,14 +91,6 @@
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
<columnOverride column="pic_urls" javaType="java.lang.String[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
|
||||
</table>
|
||||
<table tableName="litemall_coupon">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="send_start"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="send_end"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="use_start"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="use_end"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_footprint">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
@@ -129,19 +120,18 @@
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="pay_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="ship_start_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="ship_end_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="ship_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="confirm_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="end_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_order_goods">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride column="goods_specification_ids" javaType="java.lang.Integer[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
|
||||
<columnOverride column="specifications" javaType="java.lang.String[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_product">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride column="goods_specification_ids" javaType="java.lang.Integer[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
|
||||
<columnOverride column="specifications" javaType="java.lang.String[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonStringArrayTypeHandler"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_region">
|
||||
@@ -158,6 +148,7 @@
|
||||
</table>
|
||||
<table tableName="litemall_topic">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride column="goods" javaType="java.lang.Integer[]" typeHandler="org.linlinjava.litemall.db.mybatis.JsonIntegerArrayTypeHandler"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_user">
|
||||
@@ -166,12 +157,5 @@
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="last_login_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
<table tableName="litemall_user_coupon">
|
||||
<generatedKey column="id" sqlStatement="MySql" identity="true" />
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="used_time"/>
|
||||
<columnOverride javaType="java.time.LocalDateTime" column="add_time"/>
|
||||
</table>
|
||||
|
||||
|
||||
</context>
|
||||
</generatorConfiguration>
|
||||
@@ -41,6 +41,22 @@
|
||||
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.mybatis.generator</groupId>
|
||||
@@ -62,7 +78,7 @@
|
||||
<dependency>
|
||||
<groupId>com.itfsw</groupId>
|
||||
<artifactId>mybatis-generator-plugin</artifactId>
|
||||
<version>1.2.3</version>
|
||||
<version>1.2.6</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
21
litemall-db/sql/README.md
Normal file
21
litemall-db/sql/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
这里的数据库由三个sql文件组成:
|
||||
|
||||
1. litemall_schema.sql
|
||||
|
||||
作用是创建空数据库、创建用户、设置访问权限。
|
||||
|
||||
开发者开发测试阶段可以使用,但是部署生产阶段一定要注意修改这里的默认用户名和密码。
|
||||
|
||||
2. litemall_table.sql
|
||||
|
||||
作用是创建数据库表,但是没有创建任何数据。
|
||||
|
||||
因此,开发者可以在部署生产阶段直接使用。
|
||||
|
||||
3. litemall_data.sql
|
||||
|
||||
作用是创建测试数据。
|
||||
|
||||
这里的测试数据来自开源项目[nideshop-mini-program](https://github.com/tumobi/nideshop-mini-program)
|
||||
|
||||
开发者开发测试阶段可以使用,但是部署开发阶段应该使用自己的数据。
|
||||
File diff suppressed because one or more lines are too long
526
litemall-db/sql/litemall_table.sql
Normal file
526
litemall-db/sql/litemall_table.sql
Normal file
@@ -0,0 +1,526 @@
|
||||
-- MySQL dump 10.13 Distrib 5.7.17, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: 127.0.0.1 Database: litemall
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 5.7.21-log
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_ad`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_ad`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_ad` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(63) NOT NULL DEFAULT '' COMMENT '广告标题',
|
||||
`link` varchar(255) NOT NULL DEFAULT '' COMMENT '所广告的商品页面或者活动页面链接地址',
|
||||
`url` varchar(255) NOT NULL COMMENT '广告宣传图片',
|
||||
`position` tinyint(3) DEFAULT '1' COMMENT '广告位置:1则是首页',
|
||||
`content` varchar(255) DEFAULT '' COMMENT '活动内容',
|
||||
`start_time` datetime DEFAULT NULL COMMENT '广告开始时间',
|
||||
`end_time` datetime DEFAULT NULL COMMENT '广告结束时间',
|
||||
`enabled` tinyint(1) DEFAULT '0' COMMENT '是否启动',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `enabled` (`enabled`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='广告表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_address`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_address`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_address` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(63) NOT NULL DEFAULT '' COMMENT '收货人名称',
|
||||
`user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户表的用户ID',
|
||||
`province_id` int(11) NOT NULL DEFAULT '0' COMMENT '行政区域表的省ID',
|
||||
`city_id` int(11) NOT NULL DEFAULT '0' COMMENT '行政区域表的市ID',
|
||||
`area_id` int(11) NOT NULL DEFAULT '0' COMMENT '行政区域表的区县ID',
|
||||
`address` varchar(127) NOT NULL DEFAULT '' COMMENT '具体收货地址',
|
||||
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号码',
|
||||
`is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否默认地址',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收货地址表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_admin`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_admin`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_admin` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(63) NOT NULL DEFAULT '' COMMENT '管理员名称',
|
||||
`password` varchar(63) NOT NULL DEFAULT '' COMMENT '管理员密码',
|
||||
`last_login_ip` varchar(63) DEFAULT '' COMMENT '最近一次登录IP地址',
|
||||
`last_login_time` datetime DEFAULT NULL COMMENT '最近一次登录时间',
|
||||
`avatar` varchar(255) DEFAULT '''' COMMENT '头像图片',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='管理员表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_brand`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_brand`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_brand` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '品牌商名称',
|
||||
`desc` varchar(255) NOT NULL DEFAULT '' COMMENT '品牌商简介',
|
||||
`pic_url` varchar(255) NOT NULL DEFAULT '' COMMENT '品牌商页的品牌商图片',
|
||||
`sort_order` tinyint(3) DEFAULT '50',
|
||||
`floor_price` decimal(10,2) DEFAULT '0.00' COMMENT '品牌商的商品低价,仅用于页面展示',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1046001 DEFAULT CHARSET=utf8mb4 COMMENT='品牌商表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_cart`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_cart`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_cart` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) DEFAULT NULL COMMENT '用户表的用户ID',
|
||||
`goods_id` int(11) DEFAULT NULL COMMENT '商品表的商品ID',
|
||||
`goods_sn` varchar(63) DEFAULT NULL COMMENT '商品编号',
|
||||
`goods_name` varchar(127) DEFAULT NULL COMMENT '商品名称',
|
||||
`product_id` int(11) DEFAULT NULL COMMENT '商品货品表的货品ID',
|
||||
`price` decimal(10,2) DEFAULT '0.00' COMMENT '商品货品的价格',
|
||||
`number` smallint(5) DEFAULT '0' COMMENT '商品货品的数量',
|
||||
`specifications` varchar(1023) DEFAULT NULL COMMENT '商品规格值列表,采用JSON数组格式',
|
||||
`checked` tinyint(1) DEFAULT '1' COMMENT '购物车中商品是否选择状态',
|
||||
`pic_url` varchar(255) DEFAULT NULL COMMENT '商品图片或者商品货品图片',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='购物车商品表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_category`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_category`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_category` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(63) NOT NULL DEFAULT '' COMMENT '类目名称',
|
||||
`keywords` varchar(1023) NOT NULL DEFAULT '' COMMENT '类目关键字,以JSON数组格式',
|
||||
`desc` varchar(255) DEFAULT '' COMMENT '类目广告语介绍',
|
||||
`pid` int(11) NOT NULL DEFAULT '0' COMMENT '父类目ID',
|
||||
`icon_url` varchar(255) DEFAULT '' COMMENT '类目图标',
|
||||
`pic_url` varchar(255) DEFAULT '' COMMENT '类目图片',
|
||||
`level` varchar(255) DEFAULT 'L1',
|
||||
`sort_order` tinyint(3) DEFAULT '50' COMMENT '排序',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent_id` (`pid`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1036005 DEFAULT CHARSET=utf8mb4 COMMENT='类目表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_collect`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_collect`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_collect` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户表的用户ID',
|
||||
`value_id` int(11) NOT NULL DEFAULT '0' COMMENT '如果type=0,则是商品ID;如果type=1,则是专题ID',
|
||||
`type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '收藏类型,如果type=0,则是商品ID;如果type=1,则是专题ID',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
KEY `goods_id` (`value_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='收藏表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_comment`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_comment`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_comment` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`value_id` int(11) NOT NULL DEFAULT '0' COMMENT '如果type=0,则是商品评论;如果是type=1,则是专题评论。',
|
||||
`type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '评论类型,如果type=0,则是商品评论;如果是type=1,则是专题评论。',
|
||||
`content` varchar(1023) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '评论内容',
|
||||
`user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户表的用户ID',
|
||||
`has_picture` tinyint(1) DEFAULT '0' COMMENT '是否含有图片',
|
||||
`pic_urls` varchar(1023) DEFAULT NULL COMMENT '图片地址列表,采用JSON数组格式',
|
||||
`star` smallint(6) DEFAULT '1' COMMENT '评分, 1-5',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `id_value` (`value_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1002 DEFAULT CHARSET=utf8 COMMENT='评论表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_footprint`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_footprint`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_footprint` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户表的用户ID',
|
||||
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '浏览商品ID',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户浏览足迹表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_goods`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_goods`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_goods` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`goods_sn` varchar(63) NOT NULL DEFAULT '' COMMENT '商品编号',
|
||||
`name` varchar(127) NOT NULL DEFAULT '' COMMENT '商品名称',
|
||||
`category_id` int(11) DEFAULT '0' COMMENT '商品所属类目ID',
|
||||
`brand_id` int(11) DEFAULT '0',
|
||||
`gallery` varchar(1023) DEFAULT NULL COMMENT '商品宣传图片列表,采用JSON数组格式',
|
||||
`keywords` varchar(255) DEFAULT '' COMMENT '商品关键字,采用逗号间隔',
|
||||
`brief` varchar(255) DEFAULT '' COMMENT '商品简介',
|
||||
`is_on_sale` tinyint(1) DEFAULT '1' COMMENT '是否上架',
|
||||
`sort_order` smallint(4) DEFAULT '100',
|
||||
`pic_url` varchar(255) DEFAULT NULL COMMENT '商品页面商品图片',
|
||||
`is_new` tinyint(1) DEFAULT '0' COMMENT '是否新品首发,如果设置则可以在新品首发页面展示',
|
||||
`is_hot` tinyint(1) DEFAULT '0' COMMENT '是否人气推荐,如果设置则可以在人气推荐页面展示',
|
||||
`unit` varchar(31) DEFAULT '’件‘' COMMENT '商品单位,例如件、盒',
|
||||
`counter_price` decimal(10,2) DEFAULT '0.00' COMMENT '专柜价格',
|
||||
`retail_price` decimal(10,2) DEFAULT '100000.00' COMMENT '零售价格',
|
||||
`desc` text COMMENT '商品详细介绍,是富文本格式',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `goods_sn` (`goods_sn`),
|
||||
KEY `cat_id` (`category_id`),
|
||||
KEY `brand_id` (`brand_id`),
|
||||
KEY `sort_order` (`sort_order`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1181003 DEFAULT CHARSET=utf8mb4 COMMENT='商品基本信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_goods_attribute`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_goods_attribute`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_goods_attribute` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品表的商品ID',
|
||||
`attribute` varchar(255) NOT NULL COMMENT '商品参数名称',
|
||||
`value` varchar(255) NOT NULL COMMENT '商品参数值',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `goods_id` (`goods_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=874 DEFAULT CHARSET=utf8mb4 COMMENT='商品参数表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_goods_specification`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_goods_specification`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_goods_specification` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品表的商品ID',
|
||||
`specification` varchar(255) NOT NULL DEFAULT '' COMMENT '商品规格名称',
|
||||
`value` varchar(255) NOT NULL DEFAULT '' COMMENT '商品规格值',
|
||||
`pic_url` varchar(255) NOT NULL DEFAULT '' COMMENT '商品规格图片',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `goods_id` (`goods_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=260 DEFAULT CHARSET=utf8mb4 COMMENT='商品规格表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_issue`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_issue`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_issue` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`question` varchar(255) DEFAULT NULL COMMENT '问题标题',
|
||||
`answer` varchar(255) DEFAULT NULL COMMENT '问题答案',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='常见问题表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_keyword`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_keyword`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_keyword` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`keyword` varchar(127) NOT NULL DEFAULT '' COMMENT '关键字',
|
||||
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '关键字的跳转链接',
|
||||
`is_hot` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否是热门关键字',
|
||||
`is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否是默认关键字',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '100' COMMENT '排序',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COMMENT='关键字表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_order`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_order`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_order` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL COMMENT '用户表的用户ID',
|
||||
`order_sn` varchar(63) NOT NULL COMMENT '订单编号',
|
||||
`order_status` smallint(6) NOT NULL COMMENT '订单状态',
|
||||
`consignee` varchar(63) NOT NULL COMMENT '收货人名称',
|
||||
`mobile` varchar(63) NOT NULL COMMENT '收货人手机号',
|
||||
`address` varchar(127) NOT NULL COMMENT '收货具体地址',
|
||||
`goods_price` decimal(10,2) NOT NULL COMMENT '商品总费用',
|
||||
`freight_price` decimal(10,2) NOT NULL COMMENT '配送费用',
|
||||
`coupon_price` decimal(10,2) NOT NULL COMMENT '优惠券减免',
|
||||
`integral_price` decimal(10,2) NOT NULL COMMENT '用户积分减免',
|
||||
`order_price` decimal(10,2) NOT NULL COMMENT '订单费用, = goods_price + freight_price - coupon_price',
|
||||
`actual_price` decimal(10,2) NOT NULL COMMENT '实付费用, = order_price - integral_price',
|
||||
`pay_id` varchar(63) DEFAULT NULL COMMENT '微信付款编号',
|
||||
`pay_time` datetime DEFAULT NULL COMMENT '微信付款时间',
|
||||
`ship_sn` varchar(63) DEFAULT NULL COMMENT '发货编号',
|
||||
`ship_channel` varchar(63) DEFAULT NULL COMMENT '发货快递公司',
|
||||
`ship_time` datetime DEFAULT NULL COMMENT '发货开始时间',
|
||||
`confirm_time` datetime DEFAULT NULL COMMENT '用户确认收货时间',
|
||||
`end_time` datetime DEFAULT NULL COMMENT '订单关闭时间',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='订单表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_order_goods`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_order_goods`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_order_goods` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`order_id` int(11) NOT NULL DEFAULT '0' COMMENT '订单表的订单ID',
|
||||
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品表的商品ID',
|
||||
`goods_name` varchar(127) NOT NULL DEFAULT '' COMMENT '商品名称',
|
||||
`goods_sn` varchar(63) NOT NULL DEFAULT '' COMMENT '商品编号',
|
||||
`product_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品货品表的货品ID',
|
||||
`number` smallint(5) NOT NULL DEFAULT '0' COMMENT '商品货品的购买数量',
|
||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品货品的售价',
|
||||
`specifications` varchar(1023) NOT NULL COMMENT '商品货品的规格列表',
|
||||
`pic_url` varchar(255) NOT NULL DEFAULT '' COMMENT '商品货品图片或者商品图片',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `order_id` (`order_id`),
|
||||
KEY `goods_id` (`goods_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单商品表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_product`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_product`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_product` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`goods_id` int(11) NOT NULL DEFAULT '0' COMMENT '商品表的商品ID',
|
||||
`specifications` varchar(1023) NOT NULL COMMENT '商品规格值列表,采用JSON数组格式',
|
||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '商品货品价格',
|
||||
`number` int(11) NOT NULL DEFAULT '0' COMMENT '商品货品数量',
|
||||
`url` varchar(125) DEFAULT NULL COMMENT '商品货品图片',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=259 DEFAULT CHARSET=utf8mb4 COMMENT='商品货品表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_region`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_region`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_region` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`pid` int(11) NOT NULL DEFAULT '0' COMMENT '行政区域父ID,例如区县的pid指向市,市的pid指向省,省的pid则是0',
|
||||
`name` varchar(120) NOT NULL DEFAULT '' COMMENT '行政区域名称',
|
||||
`type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '行政区域类型,如如1则是省, 如果是2则是市,如果是3则是区县',
|
||||
`code` int(11) NOT NULL DEFAULT '0' COMMENT '行政区域编码',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent_id` (`pid`),
|
||||
KEY `region_type` (`type`),
|
||||
KEY `agency_id` (`code`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=46183 DEFAULT CHARSET=utf8mb4 COMMENT='行政区域表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_search_history`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_search_history`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_search_history` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`user_id` int(11) NOT NULL COMMENT '用户表的用户ID',
|
||||
`keyword` varchar(63) NOT NULL COMMENT '搜索关键字',
|
||||
`from` varchar(63) NOT NULL DEFAULT '' COMMENT '搜索来源,如pc、wx、app',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='搜索历史表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_storage`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_storage`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_storage` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`key` varchar(63) NOT NULL COMMENT '文件的唯一索引',
|
||||
`name` varchar(255) NOT NULL COMMENT '文件名',
|
||||
`type` varchar(20) NOT NULL COMMENT '文件类型',
|
||||
`size` int(11) NOT NULL COMMENT '文件大小',
|
||||
`modified` datetime DEFAULT NULL COMMENT '最后更新时间',
|
||||
`url` varchar(255) DEFAULT NULL COMMENT '文件访问链接',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文件存储表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_topic`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_topic`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_topic` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL DEFAULT '''' COMMENT '专题标题',
|
||||
`subtitle` varchar(255) NOT NULL DEFAULT '''' COMMENT '专题子标题',
|
||||
`content` text NOT NULL COMMENT '专题内容,富文本格式',
|
||||
`price` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '专题相关商品最低价',
|
||||
`read_count` varchar(255) NOT NULL DEFAULT '1k' COMMENT '专题阅读量',
|
||||
`pic_url` varchar(255) NOT NULL DEFAULT '' COMMENT '专题图片',
|
||||
`sort_order` int(11) NOT NULL DEFAULT '100' COMMENT '排序',
|
||||
`goods` varchar(1023) DEFAULT NULL COMMENT '专题相关商品,采用JSON数组格式',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `topic_id` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=315 DEFAULT CHARSET=utf8mb4 COMMENT='专题表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `litemall_user`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `litemall_user`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `litemall_user` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(63) NOT NULL COMMENT '用户名称',
|
||||
`password` varchar(63) NOT NULL DEFAULT '' COMMENT '用户密码',
|
||||
`gender` tinyint(3) NOT NULL DEFAULT '0' COMMENT '性别:0 未知, 1男, 1 女',
|
||||
`birthday` date DEFAULT NULL COMMENT '生日',
|
||||
`last_login_time` datetime DEFAULT NULL COMMENT '最近一次登录时间',
|
||||
`last_login_ip` varchar(63) NOT NULL DEFAULT '' COMMENT '最近一次登录IP地址',
|
||||
`user_level` tinyint(3) DEFAULT '0' COMMENT '0 普通用户,1 VIP用户,2 高级VIP用户',
|
||||
`nickname` varchar(63) NOT NULL DEFAULT '' COMMENT '用户昵称或网络名称',
|
||||
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '用户手机号码',
|
||||
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '用户头像图片',
|
||||
`weixin_openid` varchar(63) NOT NULL DEFAULT '' COMMENT '微信登录openid',
|
||||
`status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0 可用, 1 禁用, 2 注销',
|
||||
`add_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `user_name` (`username`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2018-07-05 22:36:57
|
||||
File diff suppressed because one or more lines are too long
@@ -1,159 +0,0 @@
|
||||
package org.linlinjava.litemall.db.dao;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.linlinjava.litemall.db.domain.LitemallCoupon;
|
||||
import org.linlinjava.litemall.db.domain.LitemallCouponExample;
|
||||
|
||||
public interface LitemallCouponMapper {
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
long countByExample(LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int deleteByExample(LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int deleteByPrimaryKey(Integer id);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int insert(LitemallCoupon record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int insertSelective(LitemallCoupon record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
LitemallCoupon selectOneByExample(LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
LitemallCoupon selectOneByExampleSelective(@Param("example") LitemallCouponExample example, @Param("selective") LitemallCoupon.Column ... selective);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
List<LitemallCoupon> selectByExampleSelective(@Param("example") LitemallCouponExample example, @Param("selective") LitemallCoupon.Column ... selective);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
List<LitemallCoupon> selectByExample(LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
LitemallCoupon selectByPrimaryKeySelective(@Param("id") Integer id, @Param("selective") LitemallCoupon.Column ... selective);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
LitemallCoupon selectByPrimaryKey(Integer id);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
LitemallCoupon selectByPrimaryKeyWithLogicalDelete(@Param("id") Integer id, @Param("andLogicalDeleted") boolean andLogicalDeleted);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByExampleSelective(@Param("record") LitemallCoupon record, @Param("example") LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByExample(@Param("record") LitemallCoupon record, @Param("example") LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByPrimaryKeySelective(LitemallCoupon record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByPrimaryKey(LitemallCoupon record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
int logicalDeleteByExample(@Param("example") LitemallCouponExample example);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table litemall_coupon
|
||||
*
|
||||
* @mbg.generated
|
||||
* @project https://github.com/itfsw/mybatis-generator-plugin
|
||||
*/
|
||||
int logicalDeleteByPrimaryKey(Integer id);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user