V 0.1.0, 项目架构基本完成。

This commit is contained in:
Junling Bu
2018-03-23 00:20:46 +08:00
commit 6c14c43cba
648 changed files with 95965 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/.idea/
/private/
/storage/

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 linlinjava(linlinjava@163.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

119
README.md Normal file
View File

@@ -0,0 +1,119 @@
litemall
=====
又一个小商场系统。
项目代码
====
* [码云](https://gitee.com/linlinjava/litemall)
* [GitHub](https://github.com/linlinjava/litemall)
项目架构
====
![](./doc/pic/1.png)
技术栈
===
> 1. Spring Boot
> 2. Vue
> 3. 微信小程序
![](doc/pic/2.png)
效果
==
### 小商城效果
![](doc/pic/3.png)
* 首页
* 专题列表、专题详情
* 分类列表、分类详情
* 品牌列表、品牌详情
* 新品首发
* 人气推荐
* 商品搜索
* 商品详情
* 商品评价列表、商品评价
* 购物车
* 下单
* 我的主页
* 订单列表、订单详情
* 地址列表、地址添加、地址删除
* 我的收藏
* 我的足迹
### 管理平台效果
![](doc/pic/4.png)
* 会员管理
* 商场管理
* 商品管理
* 推广管理
* 系统管理
云演示
==
### 小商城演示访问
由于没有上线,只能在微信开发工具中测试运行:
1. 微信开发工具导入litemall-wx项目;
2. 项目配置启用“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”
3. 点击“编译”,即可在微信开发工具预览效果;
4. 也可以点击“预览”,然后手机扫描登陆。
![](doc/pic/5.gif)
### 管理平台演示访问
1. 浏览器打开,输入以下网址`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)
更新
==
* V 0.1.0,项目架构基本完成。
警告
==
> 1. 本项目仅用于学习练习
> 2. 数据库数据来自nideshop
> 3. 项目代码目前还不完善,仍处在开发中
> 4. 项目开源MIT但不承担任何使用后果
致谢
==
本项目基于或参考以下项目:
> 1. nideshop-mini-program
> 如果后端希望采用nodejs用户可以访问nideshop项目
> 2. platform
> 如果后端希望采用非spring boot版的普通spring版或者更多功能
> 用户可以访问platform项目
> 3. vue-element-admin
本项目所依赖的其他开源项目见相关章节

4
deploy/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/litemall-admin-api/litemall-admin-api.jar
/litemall-os-api/litemall-os-api.jar
/litemall-wx-api/litemall-wx-api.jar
/litemall-admin/dist.tar

24
deploy/README.md Normal file
View File

@@ -0,0 +1,24 @@
1. 项目进一步打包到deploy文件夹中
* litemall-os-api模块编译得到的litemall-os-api-0.1.0.jar 保存到deploy的litemall-os-api文件夹中同时重命名成litemall-os-api.jar
* litemall-wx-api模块编译得到的litemall-wx-api-0.1.0.jar 保存到deploy的litemall-wx-api文件夹中同时重命名成litemall-wx-api.jar
* litemall-admin-api模块编译得到的litemall-admin-api-0.1.0.jar 保存到deploy的litemall-admin-api文件夹中同时重命名成litemall-admin-api.jar
* litemall-admin模块编译以后把dist文件夹压缩然后放到deploy的litemall-admin文件夹中。
2. 使用FileZilla把deploy整个文件夹上传到云主机的/home/ubuntu文件夹中
3. 使用PuTTY登陆云主机
4. 运行脚本部署运行
```bash
sudo ./deploy/bin/deploy.sh
```
5. 测试部署是否成功
请确保litemall的Spring Boot应用模块所对应的端口已经打开
然后测试是否能够访问(xxx.xxx.xxx.xxx是云主机IP
> http://xxx.xxx.xxx.xxx:8081/storage/index/index
> http://xxx.xxx.xxx.xxx:8082/wx/index/index
> http://xxx.xxx.xxx.xxx:8083/admin/index/index

24
deploy/bin/deploy.sh Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
#部署litemall-admin静态文件应用
cd /home/ubuntu/deploy/litemall-admin
rm -rf dist
mkdir dist
tar -zxvf dist.tar -C dist
cd .
#部署三个Spring Boot应用
#如果服务已经启动,则尝试停止
sudo /etc/init.d/litemall-os-api stop
sudo /etc/init.d/litemall-wx-api stop
sudo /etc/init.d/litemall-admin-api stop
#部署Spring Boot应用成服务
sudo ln -f -s /home/ubuntu/deploy/litemall-os-api/litemall-os-api.jar /etc/init.d/litemall-os-api
sudo ln -f -s /home/ubuntu/deploy/litemall-wx-api/litemall-wx-api.jar /etc/init.d/litemall-wx-api
sudo ln -f -s /home/ubuntu/deploy/litemall-admin-api/litemall-admin-api.jar /etc/init.d/litemall-admin-api
#启动服务
sudo /etc/init.d/litemall-os-api restart
sudo /etc/init.d/litemall-wx-api restart
sudo /etc/init.d/litemall-admin-api restart

View File

@@ -0,0 +1,2 @@
RUN_ARGS=--spring.profiles.active=prod
JAVA_OPTS=

View File

@@ -0,0 +1,2 @@
RUN_ARGS=--spring.profiles.active=prod
JAVA_OPTS=

View File

@@ -0,0 +1,2 @@
RUN_ARGS=--spring.profiles.active=prod
JAVA_OPTS=

446
doc/1.md Normal file
View File

@@ -0,0 +1,446 @@
# 1 litemall系统
## 1.1 简介
litemall是一个简单的商场系统基于现有的开源项目重新实现一个完整的前后端项目包含小程序客户端和网页管理端。
![](./pic1/1-1.png)
项目的架构是三个系统和六个模块:
* 基础系统(core)由数据库、数据库业务模块litemall-db、对象存储模块litemall-os-api组成;
* 小商场系统(wxmall)由litemall-wx-api模块和litemall-wx模块组成
* 后台管理系统(admin)由litemall-admin-api模块和litemall-admin模块组成。
* 简单商城系统(mall),这里仅列出,目前没有开发计划。
而六个模块的开发设计到三种技术栈:
* Spring Boot技术栈采用IDEA开发工具开发litemall-db、litemall-os-api、litemall-admin-api和litemall-wx-api共四个模块
* miniprogram微信小程序技术栈采用微信小程序开发工具开发litemall-wx模块
* Vue技术栈采用VSC开发工具开发litemall-admin模块。
## 1.2 系统功能
从业务功能上目前由五个业务模块参考nideshop-mini-program和platform组成
* 会员业务模块
* 商场业务模块
* 商品业务模块
* 推广业务模块
* 系统业务模块(仅管理平台)
### 1.2.1 小程序端功能
* 首页
* 专题列表
* 专题详情
* 分类列表
* 分类详情
* 品牌列表
* 品牌详情
* 新品首发
* 人气推荐
* 商品搜索
* 商品详情
* 商品评价列表
* 商品评价
* 购物车
* 下单
* 我的主页
* 订单列表
* 订单详情
* 地址列表
* 地址添加
* 我的收藏
* 我的足迹
* 支付页面(待定)
* 优惠券选择(待定)
* 我的优惠券(待定)
### 1.2.2 管理平台功能
* 会员管理
* 会员管理
* 收货地址管理
* 会员收藏
* 会员足迹
* 搜索历史
* 购物车
* 会员等级(待定)
* 会员优惠劵(待定)
* 商城管理
* 区域配置
* 品牌制造商
* 订单管理
* 商品类目
* 通用问题
* 关键词
* 渠道管理(待定)
* 商品管理
* 商品管理
* 商品参数
* 商品规格
* 货品管理
* 用户评论
* 团购设置(待定)
* 商品满减搭配(待定)
* 推广管理
* 广告列表
* 专题管理
* 优惠劵管理(待定)
* 系统管理
* 管理员
* 对象存储
* 权限管理(待定)
* 定时任务(待定)
* 参数管理(待定)
* 系统日志(待定)
## 1.3 项目特点
存在以下特点:
* 数据库方面只是简单的表表和表之间的依赖关系没有采用外键设计而是依赖Java代码在service层面或者业务层面保证。这样做的好处是数据库频繁改动很方便不会因为外键而导致数据库难以修改;
* 涉及三种技术栈,但是每种技术栈仅涉及最基础的技术;
* 后端技术栈,仅涉及 SpringSpring Boot, Spring MVC和Mybatis技术其他后端技术暂时不采用;
* 小程序技术栈仅涉及miniprogram官方文档和nideshop-mini-program项目
* 前端技术栈仅涉及vue, vuex, vue-routeelement-ui技术和vue-element-admin项目
* 安全方面,仅采用最基本的代码,提供简单基本的安全服务;
* 性能方面没有涉及内存数据库缓存功能而是完全依赖MySQL;
* 对象存储服务(图片上传和下载)方面,没有采用云存储方案,而是实现自有的简单文件上传下载功能。对象只是简单存储在后台主机的一个文件夹中,从而解耦当前项目对对象存储云平台的依赖,同时加强对对象存储概念的理解。
总之,目前的系统只是为了学习技术和业务而开发的一个简单商场原型系统。虽然缺失很多企业级功能,但是是完整和合理的原型系统。
注意:
> 以上特点并不一定是优点。
## 1.4 开发方案
![](pic1/1-2.png)
如图所示,当前开发阶段的方案:
* MySQL数据访问地址`jdbc:mysql://localhost:3306/litemall`
* litemall-os-api对象存储服务地址`http://localhost:8081`
* litemall-wx-api后台服务地址`http://localhost:8082`数据则来自MySQL
* litemall-admin-api后台服务地址`http://localhost:8083`,数据则来自MySQL
* litemall-admin前端访问地址`http://localhost:9527`, 数据来自litemall-admin-api
* litemall-wx没有前端访问地址而是直接在微信小程序工具上编译测试开发最终会部署到微信官方平台即不需要自己部署web服务器而数据则来自litemall-wx-api
### 1.4.1 Spring Boot开发环境
1. 安装JDK8
2. 安装IDEA Community
3. 安装maven
4. 安装Git可选
5. IDEA导入本项目
6. 采用maven插件安装依赖库
7. 编译本项目
8. 运行litemall-os-api, 打开浏览器,输入
```
http://localhost:8081/storage/index/index
```
如果出现JSON数据则Spring Boot开发环境部署成功litemall-os-api模块运行正常。
9. 同上运行litemall-wx-api, 打开浏览器,输入
```
http://localhost:8082/wx/index/index
```
如果出现JSON数据则litemall-wx-api模块运行正常。
10. 同上运行litemall-admin-api, 打开浏览器,输入
```
http://localhost:8083/admin/index/index
```
如果出现JSON数据则litemall-admin-api模块运行正常。
注意:
> 由于设置了三个不同的端口因此开发时IDEA可以同时运行litemall-os-api、litemall-wx-api和litemall-admin-api三个Spring Boot程序。
### 1.4.2 微信小程序开发环境
1. 安装微信小程序开发工具
2. 导入本项目的litemall-wx模块文件夹
3. 编译前请确定litemall-wx-api模块已经运行而litemall-wx模块的config文件夹中的api.js已经设置正确对应的后台数据服务地址
4. 点击`编译`,如果出现数据和图片,则运行正常
### 1.4.3 Vue开发环境
1. 安装npm或者cnpm
2. 安装VSCVisual Studio Code
3. 导入本项目的litemall-admin模块文件夹
4. 安装依赖库
```
cnpm install
```
5. 编译并运行
```
cnpm run dev
```
然后,打开浏览器,输入`http://localhost:9527`。
如果出现管理后台登陆页面,则表明管理后台的前端运行正常;
6. 请确定litemall-admin-api模块已经运行然后点击`登陆`,如果能够成功登陆,则表明管理后台的前端和后端对接成功,运行正常。
## 1.5 部署方案
在1.4节中介绍的是开发阶段时一些关键性开发流程。本节将介绍代码开发成功以后开始部署项目时一些关键性流程。
首先需要明确的是开发时项目使用的服务地址是本地地址即localhost而部署时则应该根据具体情况设置合理的服务器地址和端口。
其次,需要明确的是各模块之间的关系:
* litemall-os-api模块会包含litemall-db模块部署在服务器中
* litemall-wx-api模块会包含litemall-db模块部署在服务器中
* litemall-admin-api模块会包含litemall-db模块部署在服务器中
* 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证书具体参见官方文档。
实际上,最终的部署方案是灵活的:
* 可以单一云主机中仅安装一个tomcat服务器并配置一个端口然后同时部署四个项目的模块从而提供四种服务
即litemall-admin静态页面litemall-os-api存储服务、litemall-amdin-api后台服务和litemall-wx-api后台服务
* 也可以是同一云主机中安装四个服务器分别配置四个端口,分别提供四种服务
* 也可以是四个云主机各自安装服务器配置端口,分别提供四种服务
* 当然,甚至多个服务器,并发提供服务。
注意
> 1. `本机`指的是是当前的开发机
> 2. `云主机`指的是用户购买并部署的远程主机
以下简单列举几种方案。
### 1.5.1 windows下本机测试部署方案
这里我们是把window作为开发环境进行本项目的开发工作。
而项目开发完毕以后,在正式部署之前,可以先进行一个简单的本机测试部署方案。
首先需要确保本地MySQL已经安装并且导入了litemall.sql数据
其次,项目打包
```
cd litemall
mvn clean
mvn package
```
最后,本机测试性部署三个应用
```
cd litemall
java -jar ./litemall-os-api/target/litemall-os-api-0.1.0.jar &
java -jar ./litemall-wx-api/target/litemall-wx-api-0.1.0.jar &
java -jar ./litemall-admin-api/target/litemall-admin-api-0.1.0.jar &
```
如果,能够访问以下链接的数据,则表明本地测试部署成功:
```
http://localhost:8081/storage/index/index
http://localhost:8082/wx/index/index
http://localhost:8083/admin/index/index
```
注意
> 由于这里使用`&`设置成后台运行因此测试结束以后用户需要自行通过任务管理器或其他软件关闭这三个后台Spring Boot应用。
### 1.5.2 简单局域网方案
局域网方案,面向的是最终服务器数据和部分应用程序部署在局域网内的场景。
### 1.5.3 基于ubuntu腾讯云的单机云部署方案
单机云部署方案,面向的是云主机单机同时部署演示型场景
创建云主机安装ubuntu操作系统按照JDK和MySQL应用运行环境部署三个Spring Boot微服务后台应用。
![](pic1/1-3.png)
#### 1.5.3.1 主机
腾讯云 ubuntu 16.04.1
1. 创建云主机虚拟机
2. 安装操作系统
3. 创建安全组
![](pic1/1-4.png)
4. 安装SSH密钥可选
5. 使用PuTTY远程登陆云主机
#### 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
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
sudo apt-get install oracle-java8-set-default
```
警告
> "ppa:webupd8team/java" 不是Oracle官方PPA可能存在安全隐患。
#### 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
sudo apt-get install mysql-server
sudo apt-get install mysql-client
```
下面是可选地设置root账号远程访问MySQL
首先MySQL默认不支持远程访问因此需要修改配置文件
```
sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf
```
添加'#'注释掉其中的`bind-address`,
```
#bind-address= 127.0.0.1`;
```
其次设置root账号远程访问权限
```
mysql -u root -p
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
FLUSH PRIVILEGES;
quit;
```
最后,登陆腾讯云,设置云主机的`安全组`,允许`3306`端口访问,然后重启云主机,使得这些配置生效。
警告
> 1. 因为安全的原因MySQL不应该设置远程访问
> 这里仅仅用于方便数据导入操作。
> 2. MySQL应该部署在专门的服务器中
> 这里仅仅用于演示远程部署MySQL。
#### 1.5.3.4 litemall数据
这里可以采用命令行式也可以采用MySQL自带的Workbench导入。
* 命令行导入
1. 采用FileZilla把本项目的litemall.sql上传到云主机
2. 使用PuTTY登陆云主机
3. 进入MySQL输入上节所设置的MySQL的root密码
4. 创建数据库、 创建用户并分配访问权限
5. 导入数据
6. 退出
* MySQL Workbench导入
1. 先确认已经在1.4.3节中设置了root可以远程访问
2. 创建一个新的连接,设置`Hostname` 、`Username` 和`Password`
然后点击``Test Connection`测试是否能够连接到云主机;
如果测试成功,则进入;
![](pic1/1-5.png)
3. 用户自行学习文档,完成`创建数据库`、`创建用户`和`分配权限`三个操作;
4. 利用Workbench的`Server`菜单下的`Data Import`完成数据导入。
#### 1.5.3.5 Tomcat
1. 本项目中采用二进制jar包方式来部署Spring Boot后端应用因此可以不需要部署在tomcat中。
但是litemall-admin前端项目最终会编译出静态文件需要部署在服务器中因此这里仍需安装tomcat。
```bash
sudo apt-get install tomcat8
```
2. 为了配置tomcat支持外部文件夹中修改tomcat的server文件
```bash
sudo vi /var/lib/tomcat8/conf/server.xml
```
在其中添加一行新的内容`<Context path="/" docBase="/home/ubuntu/deploy/litemall-admin/dist" reloadable="true" />`
3. 然后重启tomcat
```
sudo service tomcat8 restart
```
#### 1.5.3.5 项目打包
1. Spring Boot打包
通常项目打包方案存在两种:
* 一是打包war格式因此云主机需要专门安装tomcat
* 二是打包可执行jar格式此时内部包含嵌入式tomcat
这里仅采用第二种方案简化tomcat的安装配置过程。
采用如下命令进行项目打包
```
cd litemall
mvn clean
mvn package
```
2. Vue项目打包
采用如下命令进行项目打包
````bash
cnpm run build:prod
````
此时litemall-admin模块的dist文件夹中就是最终部署时的代码。
#### 1.5.3.6 项目部署运行
https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#deployment-service
1. 项目进一步打包到deploy文件夹中
* litemall-os-api模块编译得到的litemall-os-api-0.1.0.jar 保存到deploy的litemall-os-api文件夹中同时重命名成litemall-os-api.jar
* litemall-wx-api模块编译得到的litemall-wx-api-0.1.0.jar 保存到deploy的litemall-wx-api文件夹中同时重命名成litemall-wx-api.jar
* litemall-admin-api模块编译得到的litemall-admin-api-0.1.0.jar 保存到deploy的litemall-admin-api文件夹中同时重命名成litemall-admin-api.jar
* litemall-admin模块编译以后把dist文件夹压缩然后放到deploy的litemall-admin文件夹中。
2. 使用FileZilla把deploy整个文件夹上传到云主机的/home/ubuntu文件夹中
3. 使用PuTTY登陆云主机
4. 运行脚本部署运行
```bash
sudo ./deploy/bin/deploy.sh
```
![](pic1/1-6.png)
5. 测试部署是否成功
请确保litemall的Spring Boot应用模块所对应的端口已经打开
然后测试是否能够访问(xxx.xxx.xxx.xxx是云主机IP
> http://xxx.xxx.xxx.xxx:8081/storage/index/index
> http://xxx.xxx.xxx.xxx:8082/wx/index/index
> http://xxx.xxx.xxx.xxx:8083/admin/index/index

246
doc/2.md Normal file
View File

@@ -0,0 +1,246 @@
# 2 litemall基础系统
目前litemall基础系统主要由litemall数据库、litemall-db模块和litemall-os-api模块组成。
## 2.1 litemall数据库
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
* 表中的日期或时间字段采用DATE、DATETIME
* 字段的数据类型粗粒度化例如避免MEDIUMINT而是INT
* 表的数据做了清理、调整和补充(假数据)。
具体不同可以比较litemall-db模块下sql文件夹中nideshop.sql和litemall.sql。
以下讨论一些关键性设计
注意:
> 以下设计基于个人理解,很可能存在不合理或者与实际系统不符合的地方。
### 2.1.1 商品和货品设计
这里商品存在商品,商品属性,商品规格,货品四种表
商品表是一种商品的基本信息,主要包括商品介绍,商品图片,商品所属类目,商品品牌商等;
商品参数表其实也是商品的基本信息但是由于是一对多关系因此不能直接保存在商品表中虽然采用JSON也可以但是不合理
因此采用独立的商品参数表,通常是商品的一些公共基本商品参数;
商品规格表是商品进一步区分货品的标识,例如同样一款衣服,基本信息一致,基本属性一致,但是在尺寸这个属性上可以
把衣服区分成多个货品,而且造成对应的数量和价格不一致。
商品规格和规格值存在以下几种关系:
* 单一规格和单一规格值,最常见的,即当前商品存在一种货品;
* 单一规格和多个规格值,较常见,即当前商品基于某个规格存在多种货品,通常价格都是相同的,当然也可能不相同;
* 多个规格和单一规格值,可以简化成第一种情况,或者采用第四种情况,通常实际情况下不常见;
* 多个规格和多个规格值,通常是两种规格或者三种规格较为常见,而且对应的价格不完全相同。
货品则是最终面向用户购买的商品标识,存在数量和价格两种属性。
因此这里一个商品表项存在至少0个多个商品属性表项目存在至少一个多个商品规格表项
存在(至少一个)多个货品表项。
举例如下:
* 一个商品“2018春季衣服商品编号1111111”
* 存在两个商品参数,
* 属性名称“面向人群”,属性值“男士”
* 属性名称“面料”属性值“100%棉”
* 存在两种规格共八个商品规格项,
* 规格名称“尺寸”规则值“S”
* 规格名称“尺寸”规则值“M”
* 规格名称“尺寸”规则值“L”
* 规格名称“尺寸”规则值“XL”
* 规格名称“尺寸”规则值“XXL”
* 规格名称“颜色”,规格值“蓝色”
* 规格名称“颜色”,规格值“灰色”
* 规格名称“颜色”,规格值“黑色”
* 存在15个货品尺寸*颜色=15个货品)
* 货品“S蓝”数量 100 价格 100
* 货品“M蓝”数量 100 价格 100
* 货品“L蓝”数量 100 价格 100
* 货品“XL蓝”数量 100 价格 100
* 货品“XXL蓝”数量 100 价格 100
* 货品“S灰”数量 100 价格 100
* 货品“M灰”数量 100 价格 100
* 货品“L灰”数量 100 价格 100
* 货品“XL灰”数量 100 价格 100
* 货品“XXL灰”数量 100 价格 100
* 货品“S黑”数量 100 价格 100
* 货品“M黑”数量 100 价格 100
* 货品“L黑”数量 100 价格 100
* 货品“XL黑”数量 0 价格 100
* 货品“XXL黑”数量 0 价格 100
以下是一些细节的讨论:
* 商品表中可能存在数量和价格属性,而货品中也存在数量和价格属性,
但是商品表中的数量和价格应该仅用于展示,而不能用于最终的订单价格计算。
商品表的数量应该是所有货品数量的总和。
商品表的价格应该和某个货品的价格一样,通常应该是所有货品价格的最小值。
因此这里商品表的数量和价格属性可能可以采用自动计算。
* 商品规格可以存在规格图片,效果是规格名称前放置规格图片
* 货品也可以存在货品图片,效果是所有规格选定以后对应的货品有货,则在货品价格前放置货品图片
注意:
> 这里的设计可能与实际项目设计不一致,但是目前是可行的。
> 商品的中文用语“商品”和英语用语“goods”货品的中文用语“货品”和英语用语“product”可能是不正确的。
### 2.1.2 用户和微信用户设计
目前准备支持用户普通账号登陆和微信登陆两种方式两种登陆方式仅仅采用一个litemall-user表可能不是很合适。此外如果进一步支持其他多种第三方登陆那么这里需要重新设计。
### 2.1.3 行政区域设计
原nideship.sql中存在region数据但是litemall.sql的region数据则来自
[Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China)项目。从该项目中导入数据到litemall.sql的litemall-province、litemall-city、litemall-area和litemall-street四个表然后重新生成一个新的litemall-region表。
### 2.1.4 订单设计
订单信息主要由基本信息、商品信息、地址信息、费用信息、快递信息、支付信息和其他信息组成。
* 基本信息
订单创建时的一些基本信息。
* 商品信息
由于订单可以存在多个商品,因此订单的商品信息是由独立的订单商品表记录(可能更应该称为货品)。
* 费用信息
* 快递信息
目前快递信息仅仅记录快递公司、快递单号、快递发出时间、快递接收时间。而如果快递过程中如果存在一些异常例如物品丢失则目前系统难以处理。关于快递费的计算目前采取简单方式即满88元则免费否则10元。
* 支付信息
* 其他信息
#### 2.1.4.1 订单状态
![](pic2/2-1.png)
订单分成几种基本的状态:
* 下单
状态码101此时订单生成记录订单编号、收货地址信息、订单商品信息和订单相关费用信息
* 付款
状态码201此时用户微信支付付款系统记录微信支付订单号、支付时间、支付状态
* 发货
状态码301此时商场已经发货系统记录快递公司、快递单号、快递发送时间。
当快递公司反馈用户签收后,系统记录快递到达时间。
* 收货
状态码401当用户收到货以后点击确认收货系统记录确认时间。
此时,用户可以评价订单商品。
除了这几种正常状态以外,还存在一些非普通的状态:
* 订单取消
状态码102用户在生产订单以后未付款之前点击取消按钮系统记录结束时间
* 订单取消并退款
状态码202用户付款以后未发货前点击取消按钮系统记录结束时间和退款信息
* 系统自动确认收货
状态码402快递反馈商场用户已签收但是用户却不点击确认收货按钮
此时系统在快递到达时间的一段时间后,自动确认收货。
用户不能再点击确认收货按钮,但是可以评价订单商品
当然,以上的基本状态和非普通状态,和实际项目相比仍然相对简单。
此外当订单状态码是102、202、401、402时订单可以设置删除状态此时
用户查看自己订单信息时将看不到这些“已删除”的订单。
#### 2.1.4.2 状态码所支持的操作
不同的状态码下面,用户能够进行的操作是:
* 101
此时,用户可以“订单支付”、“订单取消”
* 102
此时,用户可以“订单删除”
* 201
此时,用户可以“订单取消”(并退款)
* 202
此时,用户可以“订单删除”
* 301
此时,用户可以“确认收货”
* 401
此时,用户可以“订单删除”、“评价”、“再次购买”
* 402
此时,用户可以“订单删除”、“评价”、“再次购买”
#### 2.1.4.3 售后处理
目前不支持售后或退货相关业务。
#### 2.1.4.4 黑名单
从一些资料看,如果用户订单多次取消,应该加入黑名单。
目前不支持。
## 2.2 litemall-db
![](./pic2/2-2.png)
这里litemall-db模块可以分成以下几种代码
* mybatis generator自动化代码
* 业务代码
* 安全代码
* JSON支持代码
* 配置代码
### 2.2.1 自动化代码
通过mybatis generator插件可以自动生成三种代码:
* src文件夹`domain` Java代码
* src文件夹`dao` Java代码
* resources文件夹`dao` Mapper代码
这里的代码封装了对数据库的操作因此用户不需要直接操作sql代码而是直接操作Java代码即可完成对数据库的访问处理。
当然为了达到数据库访问效率用户也可以自定义mapper文件和对应的Java代码但是至少目前这里不采用。例如当需要访问两个表的数据时这里是在业务层通过Java代码遍历的形式来访问两个表。
### 2.2.2 业务代码
基于2.2.1的代码,业务代码处理一些具体业务相关的操作,对其他模块提供具体的服务。
### 2.2.3 安全代码
### 2.2.4 JSON支持代码
### 2.2.5 配置代码
采用Java注解的方式来完成一些特定的配置操作。
## 2.3 litemall-os-api
对象存储服务目前的目标是支持图片的上传下载。
### 2.3.1 业务
支持服务:
* 列表
* 创建
* 修改
* 读取
* 删除
* 下载,即下载对象数据文件
* 访问,即直接访问对象数据
### 2.3.2 安全
警告
> 目前这里没有任何安全机制,这意味着任何人如果知道对象存储服务的地址,都可以直接存储访问对象数据。
这样简化的目的是对象存储服务建议最终采用云服务,因此这里仅仅实现一个简单的服务面向测试开发。
如果用户需要局域网部署,那么这里需要加入一定的安全机制。

47
doc/3.md Normal file
View File

@@ -0,0 +1,47 @@
# 3 litemall小商城
技术:
* 小商城前端即litemall-wx模块
* 微信小程序
* 小商城后端即litemall-wx-api模块
* Spring Boot 1.5.10
* Spring MVC
* [weixin-java-tools](https://gitee.com/binary/weixin-java-tools)
目前发现需要完善的:
* 支付功能
* 运费计算
* 优惠券功能
* 商品搜索
* 进一步区分商品和货品的关系
* 地址优化,目前每一次点击都会请求后台,应该缓存已有的数据
* 商品数量和规格中,如果货品数量不足,则显示不能点击的效果
* 登陆逻辑重新设计,如果用户没有登陆,则相关页面显示登陆的效果
## 3.1 litemall-wx-api
### 3.1.1 业务
### 3.1.2 安全
### 3.1.3 支付
准备采用weixin-java-tools工具简化微信支付代码的开发。
由于需要商户相关信息,目前没有开发。
## 3.2 litemall-wx
这里的代码基于[nideshop-mini-program](https://gitee.com/tumobi/nideshop-mini-program),但是做了一定的修改:
* 数据属性名称调整原项目中数据属性名称是下划线法命名例如goods_id而这里采用骆驼式命名法例如goodsId因此代码中需要进行相应调整
* 代码清理重构,删除了一些目前不必要的文件,梳理一些逻辑功能;
* BUG修补修改了一些错误
* 功能完善拓展,例如商品立即购买功能、商品评价功能;
具体变化可以采用工具进行对比。
注意
> 目前litemall-wx项目代码基于nideshop-mini-program的commit版本[acbf6276eb27abc6a48887cddd223d7261f0088e](https://github.com/tumobi/nideshop-mini-program/commit/acbf6276eb27abc6a48887cddd223d7261f0088e)。由于改动变化较大因此之后litemall-wx将独立开发nideshop-mini-program的跟新不一定会合并到litemall-wx中。

47
doc/4.md Normal file
View File

@@ -0,0 +1,47 @@
# 4 litemall后台管理
这里的后台管理业务参考了[platform](https://gitee.com/fuyang_lipengjun/platform).
技术架构:
* 后台管理前端即litemall-admin模块
* vue
* vuex
* vue-router
* axios
* element-ui
* vue-element-admin
* 其他见package.json
* 后台管理后端, 即litemall-admin-api模块
* Spring Boot 1.5.10
* Spring MVC
目前存在的问题
* 大部分页面仅仅是一个表CRUD的效果交互性一般。
例如显示商品的时候只是简单显示表中保存的类目ID和品牌商ID更好的效果可能是显示对应的类目名称和品牌商名称同时能够显示更详细的类目信息和品牌商信息。
* 地址优化,目前每一次点击都会请求后台,应该缓存已有的数据
* 管理员角色和权限设计
* 首页中实现一些小组件,同时点击能够跳转相应页面
* 查询时排序功能
* 业务功能重新设计,例如即使是管理员也不能删除修改用户的相关数据
* 用户密码加密存储
## 4.1 litemall-admin-api
### 4.1.1 业务
### 4.1.2 安全配置
### 4.1.3 CROS配置
## 4.2 litemall-admin
litemall-admin模块的代码基于[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
## 4.3 开发新组件
这里介绍开发一个新的组件的流程。

8
doc/5.md Normal file
View File

@@ -0,0 +1,8 @@
# 5 litemall商场网站
目前不开发
## 5.1 litemall-web-api
## 5.2 litemall-web

109
doc/6.md Normal file
View File

@@ -0,0 +1,109 @@
# 6 下一步计划
6.1节涉及到技术层面需要改进的部分而6.2节则是业务方面未实现的部分这两个部分的代码都会在本项目中实现。而6.3节会进一步完善本项目的安全和性能,但是不一定会在本项目中实现,因为会增加相当大的复杂性。
## 6.1 技术
### 6.1.1 ENUM
数据库中涉及到枚举类型的字段目前设置成VARCHAR。
下一步应该设计不同的业务enum类型然后mybatis自定义BaseTypeHandler来处理不同的枚举类型。
### 6.1.2 litemall-db AutoConig
目前litemall-os-api、litemall-admin-api和litemall-wx-api引入litemall-db的时候需要在Application类中显式注解查找包和MapperScan来对litemall-db中的mapper查找此外需要在application.properties配置文件中完成对数据库、数据池等配置。
例如
```
@SpringBootApplication(scanBasePackages={"org.linlinjava.litemall.admin","org.linlinjava.litemall.db"})
@MapperScan("org.linlinjava.litemall.db.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
下一步应该自动部署即引入litemall-db则会自动引入对mapper的查找
同时自动部署对数据库、PageHelper和Druid的配置。
### 6.1.3 统一对日期时间域的处理
目前数据库的日期时间域有的采用DATE,有的是DATETIME而对应Java用LocalDate和LocalDateTime。
下一步应该根据具体业务功能采用合适的。
### 6.1.4 vue-element-admin跟新
目前的vue-element-admin基于element 2.0.8, 因此element的很多修复没有跟新。
### 6.1.5 事务管理
目前没有事务管理,因此如果直接把项目用于正式运行中,可能会存在数据不一致等问题。
### 6.1.6 小程序登陆设计
个人觉得目前nideshop-mini-program里的登陆设计内部实现不是很合理。
### 6.1.n 代码重构
技术不断迭代开发中,应该在业务基本完成和功能基本完善以后,
重新审视代码架构和技术,或者重构代码,或者采用更为合理的技术。
## 6.2 业务
### 6.2.1 支付模块
目前微信支付模块因缺乏支付权限而不能开发。
### 6.2.2 任务日程模块
部分业务需要引入任务管理服务,例如订单下单以后一个小时未支付则自动失效关闭。
### 6.2.3 监控管理
项目运行的整个运行过程应该需要监控管理
### 6.2.4 权限管理
目前安全实现非常粗糙,仅仅依赖管理员的用户名和密码。
更好的做法是引入角色权限机制。
## 6.3 企业级
### 6.3.1 安全(必须)
尽在系统所有业务功能完整实现以后。
### 6.3.2 性能(建议)
仅在系统所有业务功能完整实现以后。
性能的提升存在多种方案。
目前考虑到的技术方案:
* 采用内存数据库如redis缓存一些改动较少的数据例如行政区域数据。
* 数据库方面可以引入冗余,例如首页的数据可以先从其他表更新到一个独立的表。
### 6.3.3 对象存储云服务(建议)
仅在系统所有业务功能完整实现以后。
对象存储云服务不一定是必须的:
* 局域网中只能采用内部对象存储服务
* 对象存储云服务也是一笔开销
* 引入对象存储云服务也增加了一定的复杂性
* 导致对具体云平台的耦合
当然,对象存储云服务的益处也是毋庸置疑的,因此建议部署使用。
### 6.3.4 云数据库(必须)
同上,如果仅在局域网中部署项目,那么数据库的部署也只能是在局域网中,但是在互联网中部署应用,数据的重要性和优先级是最高的,采用云数据库可以方便带来其提供的安全和性能服务。
### 6.3.5 短信服务(必须)
真正的项目里面肯定需要短信功能。
### 6.3.6 推荐系统(可选)
目前的关键字是管理员设置,然后用户的搜索时匹配关键字,因此需要专业的推荐系统。
### 6.3.6 Spring Boot 2.0迁移(可选)

BIN
doc/pic/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
doc/pic/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
doc/pic/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

BIN
doc/pic/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
doc/pic/5.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 MiB

BIN
doc/pic/litemall.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
doc/pic/litemall.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
doc/pic1/1-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
doc/pic1/1-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
doc/pic1/1-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
doc/pic1/1-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
doc/pic1/1-5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

BIN
doc/pic1/1-6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
doc/pic2/2-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
doc/pic2/2-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

2
litemall-admin-api/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/target/

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="litemall-db" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.1.11" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.1.11" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:log4j-over-slf4j:1.7.25" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:4.3.14.RELEASE" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.17" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-jdbc:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-juli:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-tx:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.mybatis.spring.boot:mybatis-spring-boot-autoconfigure:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.4.6" level="project" />
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:1.3.2" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-starter:1.2.3" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper-spring-boot-autoconfigure:1.2.3" level="project" />
<orderEntry type="library" name="Maven: com.github.pagehelper:pagehelper:5.1.2" level="project" />
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:1.0" level="project" />
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:5.1.45" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.6" level="project" />
<orderEntry type="library" name="Maven: com.alibaba:druid:1.1.6" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.8.10" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat:tomcat-annotations-api:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:8.5.27" level="project" />
<orderEntry type="library" name="Maven: org.hibernate:hibernate-validator:5.3.6.Final" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:1.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.1.Final" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.3.4" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:4.3.14.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.10" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.8.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.8.10" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-devtools:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:1.5.10.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:1.5.10.RELEASE" level="project" />
</component>
</module>

View File

@@ -0,0 +1,71 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.linlinjava</groupId>
<artifactId>litemall-admin-api</artifactId>
<version>0.1.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath></relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.test.skip>true</maven.test.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.linlinjava</groupId>
<artifactId>litemall-db</artifactId>
<version>0.1.0</version>
</dependency>
<!-- Spring Boot Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.8.10</version>
</dependency>
<!-- Spring Boot Shiro 依赖 -->
<!--<dependency>-->
<!--<groupId>org.apache.shiro</groupId>-->
<!--<artifactId>shiro-spring-boot-web-starter</artifactId>-->
<!--<version>1.4.0</version>-->
<!--</dependency>-->
<!-- 热部署模块 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,15 @@
package org.linlinjava.litemall.admin;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages={"org.linlinjava.litemall.admin","org.linlinjava.litemall.db"})
@MapperScan("org.linlinjava.litemall.db.dao")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@@ -0,0 +1,13 @@
package org.linlinjava.litemall.admin.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginAdmin {
}

View File

@@ -0,0 +1,31 @@
package org.linlinjava.litemall.admin.annotation.support;
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
import org.linlinjava.litemall.admin.service.AdminTokenManager;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
public class LoginAdminHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
public static final String LOGIN_TOKEN_KEY = "X-Token";
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(Integer.class)&&parameter.hasParameterAnnotation(LoginAdmin.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer container,
NativeWebRequest request, WebDataBinderFactory factory) throws Exception {
// return new Integer(1);
String token = request.getHeader(LOGIN_TOKEN_KEY);
if(token == null || token.isEmpty()){
return null;
}
return AdminTokenManager.getUserId(token);
}
}

View File

@@ -0,0 +1,16 @@
package org.linlinjava.litemall.admin.config;
import org.linlinjava.litemall.admin.annotation.support.LoginAdminHandlerMethodArgumentResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
public class AdminConfig extends WebMvcConfigurerAdapter {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new LoginAdminHandlerMethodArgumentResolver());
}
}

View File

@@ -0,0 +1,25 @@
package org.linlinjava.litemall.admin.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}

View File

@@ -0,0 +1,27 @@
package org.linlinjava.litemall.admin.config;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
public Object argumentHandler(MethodArgumentTypeMismatchException e){
e.printStackTrace();
return ResponseUtil.badArgumentValue();
}
@ExceptionHandler(Exception.class)
@ResponseBody
public Object exceptionHandler(Exception e){
e.printStackTrace();
return ResponseUtil.serious();
}
}

View File

@@ -0,0 +1,36 @@
package org.linlinjava.litemall.admin.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.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
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;
}
}

View File

@@ -0,0 +1,42 @@
package org.linlinjava.litemall.admin.dao;
import java.time.LocalDateTime;
public class AdminToken {
private Integer userId;
private String token;
private LocalDateTime expireTime;
private LocalDateTime updateTime;
public void setUserId(Integer userId) {
this.userId = userId;
}
public void setToken(String token) {
this.token = token;
}
public void setExpireTime(LocalDateTime expireTime) {
this.expireTime = expireTime;
}
public void setUpdateTime(LocalDateTime updateTime) {
this.updateTime = updateTime;
}
public Integer getUserId() {
return userId;
}
public String getToken() {
return token;
}
public LocalDateTime getExpireTime() {
return expireTime;
}
public LocalDateTime getUpdateTime() {
return updateTime;
}
}

View File

@@ -0,0 +1,56 @@
package org.linlinjava.litemall.admin.service;
import org.linlinjava.litemall.admin.dao.AdminToken;
import org.linlinjava.litemall.db.util.CharUtil;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
public class AdminTokenManager {
private static Map<String, AdminToken> tokenMap = new HashMap<>();
private static Map<Integer, AdminToken> idMap = new HashMap<>();
public static Integer getUserId(String token) {
AdminToken userToken = tokenMap.get(token);
if(userToken == null){
return null;
}
if(userToken.getExpireTime().isBefore(LocalDateTime.now())){
tokenMap.remove(token);
idMap.remove(userToken.getUserId());
return null;
}
return userToken.getUserId();
}
public static AdminToken generateToken(Integer id){
AdminToken userToken = idMap.get(id);
if(userToken != null) {
tokenMap.remove(userToken.getToken());
idMap.remove(id);
}
String token = CharUtil.getRandomString(32);
while (tokenMap.containsKey(token)) {
token = CharUtil.getRandomString(32);
}
LocalDateTime update = LocalDateTime.now();
LocalDateTime expire = update.plusDays(1);
userToken = new AdminToken();
userToken.setToken(token);
userToken.setUpdateTime(update);
userToken.setExpireTime(expire);
userToken.setUserId(id);
tokenMap.put(token, userToken);
idMap.put(id, userToken);
return userToken;
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallAd;
import org.linlinjava.litemall.db.service.LitemallAdService;
import org.linlinjava.litemall.db.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/ad")
public class AdController {
private final Log logger = LogFactory.getLog(AdController.class);
@Autowired
private LitemallAdService adService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String name, String content,
@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<LitemallAd> adList = adService.querySelective(name, content, page, limit, sort, order);
int total = adService.countSelective(name, content, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", adList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallAd ad){
if(adminId == null){
return ResponseUtil.unlogin();
}
adService.add(ad);
return ResponseUtil.ok(ad);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallAd brand = adService.findById(id);
return ResponseUtil.ok(brand);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallAd ad){
if(adminId == null){
return ResponseUtil.unlogin();
}
adService.updateById(ad);
return ResponseUtil.ok(ad);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallAd ad){
if(adminId == null){
return ResponseUtil.unlogin();
}
adService.deleteById(ad.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,116 @@
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.LitemallAddress;
import org.linlinjava.litemall.db.service.LitemallAddressService;
import org.linlinjava.litemall.db.service.LitemallRegionService;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/admin/address")
public class AddressController {
private final Log logger = LogFactory.getLog(AddressController.class);
@Autowired
private LitemallAddressService addressService;
@Autowired
private LitemallRegionService regionService;
private Map<String, Object> toVo (LitemallAddress address){
Map<String, Object> addressVo = new HashMap<>();
addressVo.put("id", address.getId());
addressVo.put("userId", address.getUserId());
addressVo.put("name", address.getName());
addressVo.put("mobile", address.getMobile());
addressVo.put("isDefault", address.getIsDefault());
addressVo.put("provinceId", address.getProvinceId());
addressVo.put("cityId", address.getCityId());
addressVo.put("areaId", address.getAreaId());
addressVo.put("address", address.getAddress());
String province = regionService.findById(address.getProvinceId()).getName();
String city = regionService.findById(address.getCityId()).getName();
String area = regionService.findById(address.getAreaId()).getName();
addressVo.put("province", province);
addressVo.put("city", city);
addressVo.put("area", area);
return addressVo;
}
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
Integer userId, String name,
@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<LitemallAddress> addressList = addressService.querySelective(userId, name, page, limit, sort, order);
int total = addressService.countSelective(userId, name, page, limit, sort, order);
List<Map<String, Object>> addressVoList = new ArrayList<>(addressList.size());
for(LitemallAddress address : addressList){
Map<String, Object> addressVo = toVo(address);
addressVoList.add(addressVo);
}
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", addressVoList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
if(adminId == null){
return ResponseUtil.fail401();
}
addressService.add(address);
Map<String, Object> addressVo = toVo(address);
return ResponseUtil.ok(addressVo);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer addressId){
if(adminId == null){
return ResponseUtil.fail401();
}
LitemallAddress address = addressService.findById(addressId);
Map<String, Object> addressVo = toVo(address);
return ResponseUtil.ok(addressVo);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
if(adminId == null){
return ResponseUtil.fail401();
}
addressService.updateById(address);
Map<String, Object> addressVo = toVo(address);
return ResponseUtil.ok(addressVo);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallAddress address){
if(adminId == null){
return ResponseUtil.fail401();
}
addressService.delete(address.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,109 @@
package org.linlinjava.litemall.admin.web;
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
import org.linlinjava.litemall.admin.service.AdminTokenManager;
import org.linlinjava.litemall.db.domain.LitemallAdmin;
import org.linlinjava.litemall.db.service.LitemallAdminService;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/admin/admin")
public class AdminController {
@Autowired
private LitemallAdminService adminService;
@GetMapping("/info")
public Object info(String token){
Integer adminId = AdminTokenManager.getUserId(token);
if(adminId == null){
return ResponseUtil.badArgumentValue();
}
LitemallAdmin admin = adminService.findById(adminId);
if(admin == null){
return ResponseUtil.badArgumentValue();
}
Map<String, Object> data = new HashMap<>();
data.put("name", admin.getUsername());
data.put("avatar", admin.getAvatar());
// 目前roles不支持这里简单设置admin
List<String> roles = new ArrayList<>();
roles.add("admin");
data.put("roles", roles);
data.put("introduction", "admin introduction");
return ResponseUtil.ok(data);
}
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String username,
@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<LitemallAdmin> adminList = adminService.querySelective(username, page, limit, sort, order);
int total = adminService.countSelective(username, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", adminList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallAdmin admin){
if(adminId == null){
return ResponseUtil.unlogin();
}
adminService.add(admin);
return ResponseUtil.ok(admin);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallAdmin admin = adminService.findById(id);
return ResponseUtil.ok(admin);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallAdmin admin){
if(adminId == null){
return ResponseUtil.unlogin();
}
adminService.updateById(admin);
return ResponseUtil.ok(admin);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallAdmin admin){
if(adminId == null){
return ResponseUtil.unlogin();
}
Integer anotherAdminId = admin.getId();
if(anotherAdminId.intValue() == 1){
return ResponseUtil.fail(403, "超级用户不能删除");
}
adminService.deleteById(anotherAdminId);
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,67 @@
package org.linlinjava.litemall.admin.web;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.admin.dao.AdminToken;
import org.linlinjava.litemall.admin.annotation.LoginAdmin;
import org.linlinjava.litemall.admin.service.AdminTokenManager;
import org.linlinjava.litemall.db.domain.LitemallAdmin;
import org.linlinjava.litemall.db.service.LitemallAdminService;
import org.linlinjava.litemall.db.util.JacksonUtil;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/admin/login")
public class AuthController {
private final Log logger = LogFactory.getLog(AuthController.class);
@Autowired
private LitemallAdminService adminService;
/*
* { username : value, password : value }
*/
@PostMapping("/login")
public Object login(@RequestBody String body){
String username = JacksonUtil.parseString(body, "username");
String password = JacksonUtil.parseString(body, "password");
if(StringUtils.isEmpty(username) || StringUtils.isEmpty(password)){
return ResponseUtil.badArgument();
}
List<LitemallAdmin> adminList = adminService.findAdmin(username, password);
Assert.state(adminList.size() < 2, "同一个用户名存在两个账户");
if(adminList.size() == 0){
return ResponseUtil.badArgumentValue();
}
LitemallAdmin admin = adminList.get(0);
Integer adminId = admin.getId();
// token
AdminToken adminToken = AdminTokenManager.generateToken(adminId);
return ResponseUtil.ok(adminToken.getToken());
}
/*
*
*/
@PostMapping("/logout")
public Object login(@LoginAdmin Integer adminId){
if(adminId == null){
return ResponseUtil.unlogin();
}
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallBrand;
import org.linlinjava.litemall.db.service.LitemallBrandService;
import org.linlinjava.litemall.db.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/brand")
public class BrandController {
private final Log logger = LogFactory.getLog(BrandController.class);
@Autowired
private LitemallBrandService brandService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String id, String name,
@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<LitemallBrand> brandList = brandService.querySelective(id, name, page, limit, sort, order);
int total = brandService.countSelective(id, name, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", brandList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallBrand brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
brandService.add(brand);
return ResponseUtil.ok(brand);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallBrand brand = brandService.findById(id);
return ResponseUtil.ok(brand);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallBrand brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
brandService.updateById(brand);
return ResponseUtil.ok(brand);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallBrand brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
brandService.deleteById(brand.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,94 @@
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.db.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 CartController {
private final Log logger = LogFactory.getLog(CartController.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();
}
}

View File

@@ -0,0 +1,99 @@
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.LitemallCategory;
import org.linlinjava.litemall.db.service.LitemallCategoryService;
import org.linlinjava.litemall.db.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/category")
public class CategoryController {
private final Log logger = LogFactory.getLog(CategoryController.class);
@Autowired
private LitemallCategoryService categoryService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String id, String name,
@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<LitemallCategory> collectList = categoryService.querySelective(id, name, page, limit, sort, order);
int total = categoryService.countSelective(id, name, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", collectList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallCategory category){
if(adminId == null){
return ResponseUtil.unlogin();
}
categoryService.add(category);
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();
}
LitemallCategory category = categoryService.findById(id);
return ResponseUtil.ok(category);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallCategory category){
if(adminId == null){
return ResponseUtil.unlogin();
}
categoryService.updateById(category);
return ResponseUtil.ok();
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallCategory category){
if(adminId == null){
return ResponseUtil.unlogin();
}
categoryService.deleteById(category.getId());
return ResponseUtil.ok();
}
@GetMapping("/l1")
public Object catL1(@LoginAdmin Integer adminId) {
if (adminId == null) {
return ResponseUtil.unlogin();
}
// 所有一级分类目录
List<LitemallCategory> l1CatList = categoryService.queryL1();
HashMap<Integer, String> data = new HashMap<>(l1CatList.size());
for(LitemallCategory category : l1CatList){
data.put(category.getId(), category.getName());
}
return ResponseUtil.ok(data);
}
}

View File

@@ -0,0 +1,83 @@
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.LitemallCollect;
import org.linlinjava.litemall.db.service.LitemallCollectService;
import org.linlinjava.litemall.db.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/collect")
public class CollectController {
private final Log logger = LogFactory.getLog(CollectController.class);
@Autowired
private LitemallCollectService collectService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String userId, String valueId,
@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<LitemallCollect> collectList = collectService.querySelective(userId, valueId, page, limit, sort, order);
int total = collectService.countSelective(userId, valueId, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", collectList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallCollect collect){
if(adminId == null){
return ResponseUtil.unlogin();
}
return ResponseUtil.unsupport();
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallCollect collect = collectService.findById(id);
return ResponseUtil.ok(collect);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallCollect collect){
if(adminId == null){
return ResponseUtil.unlogin();
}
collectService.updateById(collect);
return ResponseUtil.ok();
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallCollect collect){
if(adminId == null){
return ResponseUtil.unlogin();
}
collectService.deleteById(collect.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallComment;
import org.linlinjava.litemall.db.service.LitemallCommentService;
import org.linlinjava.litemall.db.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/comment")
public class CommentController {
private final Log logger = LogFactory.getLog(CommentController.class);
@Autowired
private LitemallCommentService commentService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String userId, String valueId,
@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<LitemallComment> brandList = commentService.querySelective(userId, valueId, page, limit, sort, order);
int total = commentService.countSelective(userId, valueId, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", brandList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallComment comment){
if(adminId == null){
return ResponseUtil.unlogin();
}
commentService.add(comment);
return ResponseUtil.ok(comment);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallComment comment = commentService.findById(id);
return ResponseUtil.ok(comment);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallComment comment){
if(adminId == null){
return ResponseUtil.unlogin();
}
commentService.updateById(comment);
return ResponseUtil.ok(comment);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallComment comment){
if(adminId == null){
return ResponseUtil.unlogin();
}
commentService.deleteById(comment.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,50 @@
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.service.LitemallGoodsService;
import org.linlinjava.litemall.db.service.LitemallOrderService;
import org.linlinjava.litemall.db.service.LitemallProductService;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/admin/dashboard")
public class DashbordController {
private final Log logger = LogFactory.getLog(DashbordController.class);
@Autowired
private LitemallUserService userService;
@Autowired
private LitemallGoodsService goodsService;
@Autowired
private LitemallProductService productService;
@Autowired
private LitemallOrderService orderService;
@GetMapping("")
public Object info(@LoginAdmin Integer adminId){
if(adminId == null){
return ResponseUtil.unlogin();
}
int userTotal = userService.count();
int goodsTotal = goodsService.count();
int productTotal = productService.count();
int orderTotal = orderService.count();
Map<String, Integer> data = new HashMap<>();
data.put("userTotal", userTotal);
data.put("goodsTotal", goodsTotal);
data.put("productTotal", productTotal);
data.put("orderTotal", orderTotal);
return ResponseUtil.ok(data);
}
}

View File

@@ -0,0 +1,83 @@
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.LitemallFootprint;
import org.linlinjava.litemall.db.service.LitemallFootprintService;
import org.linlinjava.litemall.db.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/footprint")
public class FootprintController {
private final Log logger = LogFactory.getLog(FootprintController.class);
@Autowired
private LitemallFootprintService footprintService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String userId, String 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<LitemallFootprint> footprintList = footprintService.querySelective(userId, goodsId, page, limit, sort, order);
int total = footprintService.countSelective(userId, goodsId, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", footprintList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallFootprint footprint){
if(adminId == null){
return ResponseUtil.unlogin();
}
return ResponseUtil.unsupport();
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallFootprint footprint = footprintService.findById(id);
return ResponseUtil.ok(footprint);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallFootprint footprint){
if(adminId == null){
return ResponseUtil.unlogin();
}
footprintService.updateById(footprint);
return ResponseUtil.ok();
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallFootprint footprint){
if(adminId == null){
return ResponseUtil.unlogin();
}
footprintService.deleteById(footprint.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,84 @@
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.db.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 GoodsAttributeController {
private final Log logger = LogFactory.getLog(GoodsAttributeController.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();
}
}

View File

@@ -0,0 +1,84 @@
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.service.LitemallGoodsService;
import org.linlinjava.litemall.db.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")
public class GoodsController {
private final Log logger = LogFactory.getLog(GoodsController.class);
@Autowired
private LitemallGoodsService goodsService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String goodsSn, String name,
@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<LitemallGoods> goodsList = goodsService.querySelective(goodsSn, name, page, limit, sort, order);
int total = goodsService.countSelective(goodsSn, name, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", goodsList);
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);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallGoods goods){
if(adminId == null){
return ResponseUtil.unlogin();
}
goodsService.updateById(goods);
return ResponseUtil.ok(goods);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallGoods goods){
if(adminId == null){
return ResponseUtil.unlogin();
}
goodsService.deleteById(goods.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,98 @@
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.db.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 GoodsSpecificationController {
private final Log logger = LogFactory.getLog(GoodsSpecificationController.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);
}
}

View File

@@ -0,0 +1,83 @@
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.LitemallSearchHistory;
import org.linlinjava.litemall.db.service.LitemallSearchHistoryService;
import org.linlinjava.litemall.db.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/history")
public class HistoryController {
private final Log logger = LogFactory.getLog(HistoryController.class);
@Autowired
private LitemallSearchHistoryService searchHistoryService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String userId, String keyword,
@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<LitemallSearchHistory> footprintList = searchHistoryService.querySelective(userId, keyword, page, limit, sort, order);
int total = searchHistoryService.countSelective(userId, keyword, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", footprintList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallSearchHistory history){
if(adminId == null){
return ResponseUtil.fail401();
}
return ResponseUtil.fail501();
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallSearchHistory history = searchHistoryService.findById(id);
return ResponseUtil.ok(history);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallSearchHistory history){
if(adminId == null){
return ResponseUtil.unlogin();
}
searchHistoryService.updateById(history);
return ResponseUtil.ok();
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallSearchHistory history){
if(adminId == null){
return ResponseUtil.unlogin();
}
searchHistoryService.deleteById(history.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,20 @@
package org.linlinjava.litemall.admin.web;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin/index")
public class IndexController {
private final Log logger = LogFactory.getLog(IndexController.class);
@RequestMapping("/index")
public Object index(){
return ResponseUtil.ok("hello world");
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallIssue;
import org.linlinjava.litemall.db.service.LitemallIssueService;
import org.linlinjava.litemall.db.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/issue")
public class IssueController {
private final Log logger = LogFactory.getLog(IssueController.class);
@Autowired
private LitemallIssueService issueService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String question,
@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<LitemallIssue> issueList = issueService.querySelective(question, page, limit, sort, order);
int total = issueService.countSelective(question, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", issueList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
issueService.add(brand);
return ResponseUtil.ok(brand);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallIssue brand = issueService.findById(id);
return ResponseUtil.ok(brand);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
issueService.updateById(brand);
return ResponseUtil.ok(brand);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallIssue brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
issueService.deleteById(brand.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallKeyword;
import org.linlinjava.litemall.db.service.LitemallKeywordService;
import org.linlinjava.litemall.db.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/keyword")
public class KeywordController {
private final Log logger = LogFactory.getLog(KeywordController.class);
@Autowired
private LitemallKeywordService keywordService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String keyword, String url,
@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<LitemallKeyword> brandList = keywordService.querySelective(keyword, url, page, limit, sort, order);
int total = keywordService.countSelective(keyword, url, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", brandList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallKeyword keywords){
if(adminId == null){
return ResponseUtil.unlogin();
}
keywordService.add(keywords);
return ResponseUtil.ok(keywords);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallKeyword brand = keywordService.findById(id);
return ResponseUtil.ok(brand);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallKeyword keywords){
if(adminId == null){
return ResponseUtil.unlogin();
}
keywordService.updateById(keywords);
return ResponseUtil.ok(keywords);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallKeyword brand){
if(adminId == null){
return ResponseUtil.unlogin();
}
keywordService.deleteById(brand.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,110 @@
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.LitemallOrder;
import org.linlinjava.litemall.db.service.LitemallOrderService;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.linlinjava.litemall.db.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/order")
public class OrderController {
private final Log logger = LogFactory.getLog(OrderController.class);
@Autowired
private LitemallOrderService orderService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
Integer userId, String orderSn,
@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<LitemallOrder> orderList = orderService.querySelective(userId, orderSn, page, limit, sort, order);
int total = orderService.countSelective(userId, orderSn, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", orderList);
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 zmallOrder = orderService.findById(orderId);
if(zmallOrder == null){
return ResponseUtil.badArgumentValue();
}
if(OrderUtil.isPayStatus(zmallOrder) || OrderUtil.isShipStatus(zmallOrder)){
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();
}
zmallOrder = orderService.findById(orderId);
return ResponseUtil.ok(zmallOrder);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallOrder order){
if(adminId == null){
return ResponseUtil.unlogin();
}
return ResponseUtil.unsupport();
}
}

View File

@@ -0,0 +1,125 @@
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.db.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 ProductController {
private final Log logger = LogFactory.getLog(ProductController.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();
}
}

View File

@@ -0,0 +1,56 @@
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.LitemallRegion;
import org.linlinjava.litemall.db.service.LitemallRegionService;
import org.linlinjava.litemall.db.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/admin/region")
public class RegionController {
private final Log logger = LogFactory.getLog(RegionController.class);
@Autowired
private LitemallRegionService regionService;
@GetMapping("/clist")
public Object clist(@LoginAdmin Integer adminId, Integer id) {
if (id == null) {
return ResponseUtil.badArgument();
}
List<LitemallRegion> regionList = regionService.queryByPid(id);
return ResponseUtil.ok(regionList);
}
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String name, Integer code,
@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<LitemallRegion> regionList = regionService.querySelective(name, code, page, limit, sort, order);
int total = regionService.countSelective(name, code, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", regionList);
return ResponseUtil.ok(data);
}
}

View File

@@ -0,0 +1,84 @@
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.LitemallTopic;
import org.linlinjava.litemall.db.service.LitemallTopicService;
import org.linlinjava.litemall.db.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/topic")
public class TopicController {
private final Log logger = LogFactory.getLog(TopicController.class);
@Autowired
private LitemallTopicService topicService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String title, String subtitle,
@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<LitemallTopic> topicList = topicService.querySelective(title, subtitle, page, limit, sort, order);
int total = topicService.countSelective(title, subtitle, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", topicList);
return ResponseUtil.ok(data);
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallTopic topic){
if(adminId == null){
return ResponseUtil.unlogin();
}
topicService.add(topic);
return ResponseUtil.ok(topic);
}
@GetMapping("/read")
public Object read(@LoginAdmin Integer adminId, Integer id){
if(adminId == null){
return ResponseUtil.unlogin();
}
if(id == null){
return ResponseUtil.badArgument();
}
LitemallTopic brand = topicService.findById(id);
return ResponseUtil.ok(brand);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallTopic topic){
if(adminId == null){
return ResponseUtil.unlogin();
}
topicService.updateById(topic);
return ResponseUtil.ok(topic);
}
@PostMapping("/delete")
public Object delete(@LoginAdmin Integer adminId, @RequestBody LitemallTopic topic){
if(adminId == null){
return ResponseUtil.unlogin();
}
topicService.deleteById(topic.getId());
return ResponseUtil.ok();
}
}

View File

@@ -0,0 +1,72 @@
package org.linlinjava.litemall.admin.web;
import com.github.pagehelper.util.StringUtil;
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.LitemallUser;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.db.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/user")
public class UserController {
private final Log logger = LogFactory.getLog(UserController.class);
@Autowired
private LitemallUserService userService;
@GetMapping("/list")
public Object list(@LoginAdmin Integer adminId,
String username, String mobile,
@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<LitemallUser> userList = userService.querySelective(username, mobile, page, limit, sort, order);
int total = userService.countSeletive(username, mobile, page, limit, sort, order);
Map<String, Object> data = new HashMap<>();
data.put("total", total);
data.put("items", userList);
return ResponseUtil.ok(data);
}
@GetMapping("/username")
public Object username(String username){
if(StringUtil.isEmpty(username)){
return ResponseUtil.fail402();
}
int total = userService.countSeletive(username, null, null, null, null, null);
if(total == 0){
return ResponseUtil.ok("不存在");
}
return ResponseUtil.ok("已存在");
}
@PostMapping("/create")
public Object create(@LoginAdmin Integer adminId, @RequestBody LitemallUser user){
logger.debug(user);
userService.add(user);
return ResponseUtil.ok(user);
}
@PostMapping("/update")
public Object update(@LoginAdmin Integer adminId, @RequestBody LitemallUser user){
logger.debug(user);
userService.update(user);
return ResponseUtil.ok(user);
}
}

View File

@@ -0,0 +1,28 @@
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false
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.max-wait=60000
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
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.db=ERROR
logging.level.org.linlinjava.litemall=DEBUG

View File

@@ -0,0 +1,27 @@
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false
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.max-wait=60000
spring.datasource.druid.pool-prepared-statements=true
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.validation-query=SELECT 1 FROM DUAL
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
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.db=ERROR
logging.level.org.linlinjava.litemall=DEBUG

View File

@@ -0,0 +1,3 @@
spring.profiles.active=dev
server.port=8083
logging.level.org.linlinjava.litemall.admin.Application=DEBUG

12
litemall-admin/.babelrc Normal file
View File

@@ -0,0 +1,12 @@
{
"presets": [
["env", {
"modules": false,
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"stage-2"
],
"plugins": ["transform-vue-jsx", "transform-runtime"]
}

View File

@@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

View File

@@ -0,0 +1,3 @@
build/*.js
config/*.js
src/assets

199
litemall-admin/.eslintrc.js Normal file
View File

@@ -0,0 +1,199 @@
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: 'eslint:recommended',
// required to lint *.vue files
plugins: [
'html'
],
// check if imports actually resolve
'settings': {
'import/resolver': {
'webpack': {
'config': 'build/webpack.base.conf.js'
}
}
},
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
'rules': {
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': [2, 'allow-null'],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

19
litemall-admin/.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
test/unit/coverage
test/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln

View File

@@ -0,0 +1,10 @@
// https://github.com/michael-ciniawsky/postcss-load-config
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {}
}
}

View File

@@ -0,0 +1,5 @@
language: node_js
node_js: stable
script: npm run test
notifications:
email: false

View File

@@ -0,0 +1,48 @@
'use strict'
require('./check-versions')()
const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')
const server = require('pushstate-server')
var spinner = ora('building for '+ process.env.env_config+ ' environment...' )
spinner.start()
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
if (err) throw err
webpack(webpackConfig, (err, stats) => {
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n\n')
if (stats.hasErrors()) {
console.log(chalk.red(' Build failed with errors.\n'))
process.exit(1)
}
console.log(chalk.cyan(' Build complete.\n'))
console.log(chalk.yellow(
' Tip: built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
))
if(process.env.npm_config_preview){
server.start({
port: 9526,
directory: './dist',
file: '/index.html'
});
console.log('> Listening at ' + 'http://localhost:9526' + '\n')
}
})
})

View File

@@ -0,0 +1,54 @@
'use strict'
const chalk = require('chalk')
const semver = require('semver')
const packageConfig = require('../package.json')
const shell = require('shelljs')
function exec (cmd) {
return require('child_process').execSync(cmd).toString().trim()
}
const versionRequirements = [
{
name: 'node',
currentVersion: semver.clean(process.version),
versionRequirement: packageConfig.engines.node
}
]
if (shell.which('npm')) {
versionRequirements.push({
name: 'npm',
currentVersion: exec('npm --version'),
versionRequirement: packageConfig.engines.npm
})
}
module.exports = function () {
const warnings = []
for (let i = 0; i < versionRequirements.length; i++) {
const mod = versionRequirements[i]
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
warnings.push(mod.name + ': ' +
chalk.red(mod.currentVersion) + ' should be ' +
chalk.green(mod.versionRequirement)
)
}
}
if (warnings.length) {
console.log('')
console.log(chalk.yellow('To use this template, you must update following to modules:'))
console.log()
for (let i = 0; i < warnings.length; i++) {
const warning = warnings[i]
console.log(' ' + warning)
}
console.log()
process.exit(1)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,101 @@
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}

View File

@@ -0,0 +1,22 @@
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}

View File

@@ -0,0 +1,101 @@
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const createLintingRule = () => ({
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [resolve('src'), resolve('test')],
options: {
formatter: require('eslint-friendly-formatter'),
emitWarning: !config.dev.showEslintErrorsInOverlay
}
})
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/icons')],
options: {
symbolId: 'icon-[name]'
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
exclude: [resolve('src/icons')],
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}

View File

@@ -0,0 +1,88 @@
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
const portfinder = require('portfinder')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const HOST = process.env.HOST
const PORT = process.env.PORT && Number(process.env.PORT)
const devWebpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
// these devServer options should be customized in /config/index.js
devServer: {
clientLogLevel: 'warning',
historyApiFallback: true,
hot: true,
compress: true,
host: HOST || config.dev.host,
port: PORT || config.dev.port,
open: config.dev.autoOpenBrowser,
overlay: config.dev.errorOverlay
? { warnings: false, errors: true }
: false,
publicPath: config.dev.assetsPublicPath,
proxy: config.dev.proxyTable,
quiet: true, // necessary for FriendlyErrorsPlugin
watchOptions: {
poll: config.dev.poll,
}
},
plugins: [
new webpack.DefinePlugin({
'process.env': require('../config/dev.env')
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
new webpack.NoEmitOnErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'zmall-admin',
path: config.dev.assetsPublicPath + config.dev.assetsSubDirectory
}),
]
})
module.exports = new Promise((resolve, reject) => {
portfinder.basePort = process.env.PORT || config.dev.port
portfinder.getPort((err, port) => {
if (err) {
reject(err)
} else {
// publish the new Port, necessary for e2e tests
process.env.PORT = port
// add port to devServer config
devWebpackConfig.devServer.port = port
// Add FriendlyErrorsPlugin
devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({
compilationSuccessInfo: {
messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`],
},
onErrors: config.dev.notifyOnErrors
? utils.createNotifierCallback()
: undefined
}))
resolve(devWebpackConfig)
}
})
})

View File

@@ -0,0 +1,175 @@
'use strict'
const path = require('path')
const utils = require('./utils')
const webpack = require('webpack')
const config = require('../config')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.conf')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
const env = require('../config/'+process.env.env_config+'.env')
const webpackConfig = merge(baseWebpackConfig, {
module: {
rules: utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
plugins: [
// http://vuejs.github.io/vue-loader/en/workflow/production.html
new webpack.DefinePlugin({
'process.env': env
}),
new UglifyJsPlugin({
uglifyOptions: {
compress: {
warnings: false
}
},
sourceMap: config.build.productionSourceMap,
parallel: true
}),
// extract css into its own file
new ExtractTextPlugin({
filename: utils.assetsPath('css/[name].[contenthash].css'),
// Setting the following option to `false` will not extract CSS from codesplit chunks.
// Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack.
// increasing file size: https://github.com/vuejs-templates/webpack/issues/1110
allChunks: false,
}),
// Compress extracted CSS. We are using this plugin so that possible
// duplicated CSS from different components can be deduped.
new OptimizeCSSPlugin({
cssProcessorOptions: config.build.productionSourceMap
? { safe: true, map: { inline: false } }
: { safe: true }
}),
// generate dist index.html with correct asset hash for caching.
// you can customize output by editing /index.html
// see https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'index.html',
inject: true,
favicon: resolve('favicon.ico'),
title: 'vue-element-admin',
path: config.build.assetsPublicPath + config.build.assetsSubDirectory,
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
// more options:
// https://github.com/kangax/html-minifier#options-quick-reference
},
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
chunksSortMode: 'dependency'
}),
// keep module.id stable when vender modules does not change
new webpack.HashedModuleIdsPlugin(),
// enable scope hoisting
new webpack.optimize.ModuleConcatenationPlugin(),
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
new webpack.optimize.CommonsChunkPlugin({
name: 'app',
async: 'vendor-async',
children: true,
minChunks: 3
}),
// split echarts into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'echarts',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('echarts') >= 0 || context.indexOf('zrender') >= 0);
}
}),
// split xlsx into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'xlsx',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('xlsx') >= 0);
}
}),
// split codemirror into its own file
new webpack.optimize.CommonsChunkPlugin({
async: 'codemirror',
minChunks(module) {
var context = module.context;
return context && (context.indexOf('codemirror') >= 0);
}
}),
// copy custom static assets
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../static'),
to: config.build.assetsSubDirectory,
ignore: ['.*']
}
])
]
})
if (config.build.productionGzip) {
const CompressionWebpackPlugin = require('compression-webpack-plugin')
webpackConfig.plugins.push(
new CompressionWebpackPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\\.(' +
config.build.productionGzipExtensions.join('|') +
')$'
),
threshold: 10240,
minRatio: 0.8
})
)
}
if (config.build.bundleAnalyzerReport) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig

View File

@@ -0,0 +1,6 @@
module.exports = {
NODE_ENV: '"development"',
ENV_CONFIG: '"dev"',
BASE_API: '"http://localhost:8083/admin"',
OS_API: '"http://localhost:8081/storage"'
}

View File

@@ -0,0 +1,83 @@
'use strict'
// Template version: 1.2.6
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
dev: {
// Paths
assetsSubDirectory: 'static',
assetsPublicPath: '/',
proxyTable: {},
// Various Dev Server settings
host: 'localhost', // can be overwritten by process.env.HOST
port: 9527, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
autoOpenBrowser: true,
errorOverlay: true,
notifyOnErrors: false,
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
// Use Eslint Loader?
// If true, your code will be linted during bundling and
// linting errors and warnings will be shown in the console.
useEslint: true,
// If true, eslint errors and warnings will also be shown in the error overlay
// in the browser.
showEslintErrorsInOverlay: false,
/**
* Source Maps
*/
// https://webpack.js.org/configuration/devtool/#development
devtool: '#cheap-source-map',
// If you have problems debugging vue-files in devtools,
// set this to false - it *may* help
// https://vue-loader.vuejs.org/en/options.html#cachebusting
cacheBusting: true,
// CSS Sourcemaps off by default because relative paths are "buggy"
// with this option, according to the CSS-Loader README
// (https://github.com/webpack/css-loader#sourcemaps)
// In our experience, they generally work as expected,
// just be aware of this issue when enabling this option.
cssSourceMap: false,
},
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
// you can set by youself according to actual condition
assetsPublicPath: './',
/**
* Source Maps
*/
productionSourceMap: false,
// https://webpack.js.org/configuration/devtool/#production
devtool: '#source-map',
// Gzip off by default as many popular static hosts such as
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
// `npm run build --report`
// Set to `true` or `false` to always turn it on or off
bundleAnalyzerReport: process.env.npm_config_report
}
}

View File

@@ -0,0 +1,6 @@
module.exports = {
NODE_ENV: '"production"',
ENV_CONFIG: '"prod"',
BASE_API: '"http://122.152.206.172:8083/admin"',
OS_API: '"http://122.152.206.172:8081/storage"'
}

BIN
litemall-admin/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

15
litemall-admin/index.html Normal file
View File

@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>zmall-admin</title>
</head>
<script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -0,0 +1,90 @@
{
"name": "litemall-admin",
"version": "0.1.0",
"description": "litemall-admin basing on vue-element-admin 3.6.2",
"author": "linlinjava <linlinjava@163.com>",
"license": "MIT",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"build:prod": "cross-env NODE_ENV=production env_config=prod node build/build.js",
"lint": "eslint --ext .js,.vue src",
"test": "npm run lint"
},
"dependencies": {
"axios": "0.17.1",
"clipboard": "1.7.1",
"echarts": "3.8.5",
"element-ui": "2.0.8",
"file-saver": "1.3.3",
"font-awesome": "4.7.0",
"js-cookie": "2.2.0",
"mockjs": "1.0.1-beta3",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"screenfull": "3.3.2",
"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"
},
"devDependencies": {
"autoprefixer": "7.2.3",
"babel-core": "6.26.0",
"babel-eslint": "8.0.3",
"babel-helper-vue-jsx-merge-props": "2.0.3",
"babel-loader": "7.1.2",
"babel-plugin-syntax-jsx": "6.18.0",
"babel-plugin-transform-runtime": "6.23.0",
"babel-plugin-transform-vue-jsx": "3.5.0",
"babel-preset-env": "1.6.1",
"babel-preset-stage-2": "6.24.1",
"chalk": "2.3.0",
"copy-webpack-plugin": "4.3.0",
"cross-env": "5.1.1",
"css-loader": "0.28.7",
"eslint": "4.13.1",
"eslint-friendly-formatter": "3.0.0",
"eslint-loader": "1.9.0",
"eslint-plugin-html": "4.0.1",
"extract-text-webpack-plugin": "3.0.2",
"file-loader": "1.1.5",
"friendly-errors-webpack-plugin": "1.6.1",
"html-webpack-plugin": "2.30.1",
"node-notifier": "5.1.2",
"node-sass": "^4.7.2",
"optimize-css-assets-webpack-plugin": "3.2.0",
"ora": "1.3.0",
"portfinder": "1.0.13",
"postcss-import": "11.0.0",
"postcss-loader": "2.0.9",
"postcss-url": "7.3.0",
"pushstate-server": "3.0.1",
"rimraf": "2.6.2",
"sass-loader": "6.0.6",
"script-loader": "0.7.2",
"semver": "5.4.1",
"shelljs": "0.7.8",
"svg-sprite-loader": "3.5.2",
"uglifyjs-webpack-plugin": "1.1.3",
"url-loader": "0.6.2",
"vue-loader": "13.5.0",
"vue-style-loader": "3.0.3",
"vue-template-compiler": "2.5.10",
"webpack": "3.10.0",
"webpack-bundle-analyzer": "2.9.1",
"webpack-dev-server": "2.9.7",
"webpack-merge": "4.1.1"
},
"engines": {
"node": ">= 4.0.0",
"npm": ">= 3.0.0"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

View File

@@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
<script>
export default{
name: 'APP'
}
</script>

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listAd(query) {
return request({
url: '/ad/list',
method: 'get',
params: query
})
}
export function createAd(data) {
return request({
url: '/ad/create',
method: 'post',
data
})
}
export function readAd(data) {
return request({
url: '/ad/read',
method: 'get',
data
})
}
export function updateAd(data) {
return request({
url: '/ad/update',
method: 'post',
data
})
}
export function deleteAd(data) {
return request({
url: '/ad/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listAddress(query) {
return request({
url: '/address/list',
method: 'get',
params: query
})
}
export function createAddress(data) {
return request({
url: '/address/create',
method: 'post',
data
})
}
export function readAddress(data) {
return request({
url: '/address/read',
method: 'get',
data
})
}
export function updateAddress(data) {
return request({
url: '/address/update',
method: 'post',
data
})
}
export function deleteAddress(data) {
return request({
url: '/address/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listAdmin(query) {
return request({
url: '/admin/list',
method: 'get',
params: query
})
}
export function createAdmin(data) {
return request({
url: '/admin/create',
method: 'post',
data
})
}
export function readminAdmin(data) {
return request({
url: '/admin/readmin',
method: 'get',
data
})
}
export function updateAdmin(data) {
return request({
url: '/admin/update',
method: 'post',
data
})
}
export function deleteAdmin(data) {
return request({
url: '/admin/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listBrand(query) {
return request({
url: '/brand/list',
method: 'get',
params: query
})
}
export function createBrand(data) {
return request({
url: '/brand/create',
method: 'post',
data
})
}
export function readBrand(data) {
return request({
url: '/brand/read',
method: 'get',
data
})
}
export function updateBrand(data) {
return request({
url: '/brand/update',
method: 'post',
data
})
}
export function deleteBrand(data) {
return request({
url: '/brand/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
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
})
}

View File

@@ -0,0 +1,48 @@
import request from '@/utils/request'
export function listCategory(query) {
return request({
url: '/category/list',
method: 'get',
params: query
})
}
export function listCatL1() {
return request({
url: '/category/l1',
method: 'get'
})
}
export function createCategory(data) {
return request({
url: '/category/create',
method: 'post',
data
})
}
export function readCategory(data) {
return request({
url: '/category/read',
method: 'get',
data
})
}
export function updateCategory(data) {
return request({
url: '/category/update',
method: 'post',
data
})
}
export function deleteCategory(data) {
return request({
url: '/category/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listCollect(query) {
return request({
url: '/collect/list',
method: 'get',
params: query
})
}
export function createCollect(data) {
return request({
url: '/collect/create',
method: 'post',
data
})
}
export function readCollect(data) {
return request({
url: '/collect/read',
method: 'get',
data
})
}
export function updateCollect(data) {
return request({
url: '/collect/update',
method: 'post',
data
})
}
export function deleteCollect(data) {
return request({
url: '/collect/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listComment(query) {
return request({
url: '/comment/list',
method: 'get',
params: query
})
}
export function createComment(data) {
return request({
url: '/comment/create',
method: 'post',
data
})
}
export function readComment(data) {
return request({
url: '/comment/read',
method: 'get',
data
})
}
export function updateComment(data) {
return request({
url: '/comment/update',
method: 'post',
data
})
}
export function deleteComment(data) {
return request({
url: '/comment/delete',
method: 'post',
data
})
}

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request'
export function info(query) {
return request({
url: '/dashboard',
method: 'get',
params: query
})
}

View File

@@ -0,0 +1,41 @@
import request from '@/utils/request'
export function listFootprint(query) {
return request({
url: '/footprint/list',
method: 'get',
params: query
})
}
export function createFootprint(data) {
return request({
url: '/footprint/create',
method: 'post',
data
})
}
export function readFootprint(data) {
return request({
url: '/footprint/read',
method: 'get',
data
})
}
export function updateFootprint(data) {
return request({
url: '/footprint/update',
method: 'post',
data
})
}
export function deleteFootprint(data) {
return request({
url: '/footprint/delete',
method: 'post',
data
})
}

Some files were not shown because too many files have changed in this diff Show More