Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Litemall
Commits
7023b205
Unverified
Commit
7023b205
authored
Nov 17, 2019
by
staney
Committed by
GitHub
Nov 17, 2019
Browse files
Merge pull request #1 from linlinjava/master
同步更新代码
parents
c6ab92f9
506a8c01
Changes
66
Show whitespace changes
Inline
Side-by-side
CHANGELOG.md
View file @
7023b205
# 更新日志
# 更新日志
## V 1.5.0
*2019-11-15*
, 持续优化轻商城模块,以及推荐项目Flutter_Mall
#### Bug 修复
*
`小商城`
优惠券绑定绑定优惠券ID(#157 by @pkwenda)
*
`小商城`
评论列表不能正确显示
*
`轻商城`
修正取消订单接口 (#256 by @1037621594)
#### 优化
*
`小商城`
采用延迟队列实现支付超时取消订单功能(参考#275 by @alexzhu0592)
*
`小商城`
分享按钮可选配置 (#239 by @galenzhao)
#### 新特性
*
`基础系统`
支持阿里云短信
*
`轻商城`
接入微信支付H5支付 (#291 by @pkwenda)
*
`小商城`
团购拼团超期取消 (#284 by @pkwenda)
*
`管理后台`
订单详情新增打印 (#274 by @fanchenggang )
*
README文档推荐项目Flutter_Mall
## V 1.4.0
## V 1.4.0
*2019-05-16*
,支持移动端轻商城
*2019-05-16*
,支持移动端轻商城
...
...
README.md
View file @
7023b205
...
@@ -31,7 +31,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
...
@@ -31,7 +31,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端


或者浏览器采用手机模式访问以下网址:
[
http://1
18.24.0.153
:8080/vue/index.html#/
](
http://1
18.24.0.153
:8080/vue/index.html#/
)
或者浏览器采用手机模式访问以下网址:
[
http://1
22.51.199.160
:8080/vue/index.html#/
](
http://1
22.51.199.160
:8080/vue/index.html#/
)
注意:
注意:
> 1. 由于第一次加载数据量较大,建议wifi网络访问,且耐心等待数秒。
> 1. 由于第一次加载数据量较大,建议wifi网络访问,且耐心等待数秒。
...
@@ -41,7 +41,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
...
@@ -41,7 +41,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端


1.
浏览器打开,输入以下网址:
[
http://1
18.24.0.153
:8080/#/login
](
http://1
18.24.0.153
:8080/#/login
)
1.
浏览器打开,输入以下网址:
[
http://1
22.51.199.160
:8080/#/login
](
http://1
22.51.199.160
:8080/#/login
)
2.
管理员用户名
`admin123`
,管理员密码
`admin123`
2.
管理员用户名
`admin123`
,管理员密码
`admin123`
> 注意:此实例只是测试管理后台,不是前两个小商城的管理后台。
> 注意:此实例只是测试管理后台,不是前两个小商城的管理后台。
...
@@ -154,7 +154,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
...
@@ -154,7 +154,7 @@ litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端
## 开发计划
## 开发计划
当前版本
[
v1.
4
.0
](
https://linlinjava.gitbook.io/litemall/changelog
)
当前版本
[
v1.
5
.0
](
https://linlinjava.gitbook.io/litemall/changelog
)
目前项目开发中,存在诸多不足,以下是目前规划的开发计划。
目前项目开发中,存在诸多不足,以下是目前规划的开发计划。
...
@@ -220,6 +220,12 @@ V 3.0.0 完成以下目标:
...
@@ -220,6 +220,12 @@ V 3.0.0 完成以下目标:
项目参考:litemall项目的litemall-vue模块基于vant--mobile-mall项目开发。
项目参考:litemall项目的litemall-vue模块基于vant--mobile-mall项目开发。
## 推荐
1.
[
Flutter_Mall
](
https://github.com/youxinLu/mall
)
项目介绍:Flutter_Mall是一款Flutter开源在线商城应用程序。
## 问题
## 问题


...
...
deploy/README.md
View file @
7023b205
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
### 项目打包
### 项目打包
1.
在
主机
或者开发机打包项目到deploy;
1.
在
服务器
或者开发机打包项目到deploy;
```
```
cd litemall
cd litemall
cat ./litemall-db/sql/litemall_schema.sql > ./deploy/db/litemall.sql
cat ./litemall-db/sql/litemall_schema.sql > ./deploy/db/litemall.sql
...
@@ -25,13 +25,13 @@
...
@@ -25,13 +25,13 @@
2.
修改litemall文件夹下面的
*
.yml外部配置文件,当litemall-all模块启动时会
2.
修改litemall文件夹下面的
*
.yml外部配置文件,当litemall-all模块启动时会
加载外部配置文件,而覆盖默认jar包内部的配置文件。
加载外部配置文件,而覆盖默认jar包内部的配置文件。
例如,配置文件中一些地方需要设置成远程
主机
的IP地址
例如,配置文件中一些地方需要设置成远程
服务器
的IP地址
此时deploy部署包结构如下:
此时deploy部署包结构如下:
*
bin
*
bin
存放远程
主机
运行的脚本,包括deploy.sh脚本和reset.sh脚本
存放远程
服务器
运行的脚本,包括deploy.sh脚本和reset.sh脚本
*
db
*
db
...
@@ -39,15 +39,15 @@
...
@@ -39,15 +39,15 @@
*
litemall
*
litemall
存放远程
主机
运行的代码,包括litemall-all二进制可执行包和litemall外部配置文件
存放远程
服务器
运行的代码,包括litemall-all二进制可执行包和litemall外部配置文件
*
util
*
util
存放开发
主机
运行的脚本,包括package.sh脚本和lazy.sh脚本。
存放开发
服务器
运行的脚本,包括package.sh脚本和lazy.sh脚本。
由于是本地开发
主机
运行,因此开发者可以不用上传到远程
主机
。
由于是本地开发
服务器
运行,因此开发者可以不用上传到远程
服务器
。
### 项目部署
### 项目部署
1.
远程
主机
环境(MySQL和JDK1.8)已经安装好,请确保云
主机
的安全组已经允许相应的端口。
1.
远程
服务器
环境(MySQL和JDK1.8)已经安装好,请确保云
服务器
的安全组已经允许相应的端口。
2.
导入db/litemall.sql
2.
导入db/litemall.sql
```
bash
```
bash
cd
/home/ubuntu/deploy/db
cd
/home/ubuntu/deploy/db
...
@@ -59,7 +59,7 @@
...
@@ -59,7 +59,7 @@
sudo ln
-f
-s
/home/ubuntu/deploy/litemall/litemall.jar /etc/init.d/litemall
sudo ln
-f
-s
/home/ubuntu/deploy/litemall/litemall.jar /etc/init.d/litemall
sudo
service litemall start
sudo
service litemall start
```
```
4.
测试是否部署成功(xxx.xxx.xxx.xxx是云
主机
IP):
4.
测试是否部署成功(xxx.xxx.xxx.xxx是云
服务器
IP):
```
```
http://xxx.xxx.xxx.xxx:8080/wx/index/index
http://xxx.xxx.xxx.xxx:8080/wx/index/index
http://xxx.xxx.xxx.xxx:8080/admin/index/index
http://xxx.xxx.xxx.xxx:8080/admin/index/index
...
@@ -73,26 +73,26 @@
...
@@ -73,26 +73,26 @@
*
util/packet.sh
*
util/packet.sh
在开发
主机
运行可以自动项目打包
在开发
服务器
运行可以自动项目打包
*
util/lazy.sh
*
util/lazy.sh
在开发
主机
运行可以自动项目打包、项目上传远程
主机
、自动登录系统执行项目部署脚本。
在开发
服务器
运行可以自动项目打包、项目上传远程
服务器
、自动登录系统执行项目部署脚本。
注意:
注意:
> 1. 开发者需要在util/lazy.sh中设置相应的远程
主机
登录账号和密钥文件路径。
> 1. 开发者需要在util/lazy.sh中设置相应的远程
服务器
登录账号和密钥文件路径。
> 2. 开发者需要在bin/reset.sh设置远程
主机
的MySQL的root登录账户。
> 2. 开发者需要在bin/reset.sh设置远程
服务器
的MySQL的root登录账户。
*
bin/deploy.sh
*
bin/deploy.sh
在远程
主机
运行可以自动部署服务
在远程
服务器
运行可以自动部署服务
*
bin/reset.sh
*
bin/reset.sh
在远程
主机
运行可以自动项目导入数据、删除本地上传图片、再执行bin/deploy.sh部署服务。
在远程
服务器
运行可以自动项目导入数据、删除本地上传图片、再执行bin/deploy.sh部署服务。
注意:
注意:
> 开发者需要在bin/reset.sh设置远程
主机
的MySQL的root登录账户。
> 开发者需要在bin/reset.sh设置远程
服务器
的MySQL的root登录账户。
总结,当开发者设置好配置信息以后,可以在本地运行lazy.sh脚本自动一键部署:
总结,当开发者设置好配置信息以后,可以在本地运行lazy.sh脚本自动一键部署:
```
bash
```
bash
...
...
deploy/bin/reset.sh
View file @
7023b205
...
@@ -14,7 +14,7 @@ PASSWORD=
...
@@ -14,7 +14,7 @@ PASSWORD=
if
test
-z
"
$PASSWORD
"
if
test
-z
"
$PASSWORD
"
then
then
echo
"请设置云
主机
MySQL的root账号密码"
echo
"请设置云
服务器
MySQL的root账号密码"
exit
1
exit
1
fi
fi
...
...
deploy/litemall/application.yml
View file @
7023b205
...
@@ -41,7 +41,7 @@ litemall:
...
@@ -41,7 +41,7 @@ litemall:
app-secret
:
e04004829d4c383b4db7769d88dfbca1
app-secret
:
e04004829d4c383b4db7769d88dfbca1
mch-id
:
111111
mch-id
:
111111
mch-key
:
xxxxxx
mch-key
:
xxxxxx
notify-url
:
http://1
18.24.0.153
:8080/wx/order/pay-notify
notify-url
:
http://1
22.51.199.160
:8080/wx/order/pay-notify
# 商户证书文件路径
# 商户证书文件路径
# 请参考“商户证书”一节 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3
# 请参考“商户证书”一节 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3
key-path
:
xxxxx
key-path
:
xxxxx
...
@@ -61,8 +61,10 @@ litemall:
...
@@ -61,8 +61,10 @@ litemall:
# 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
# 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
sms
:
sms
:
enable
:
false
enable
:
false
appid
:
111111111
# 如果是腾讯云短信,则设置active的值tencent
appkey
:
xxxxxxxxxxxxxx
# 如果是阿里云短信,则设置active的值aliyun
active
:
tencent
sign
:
litemall
template
:
template
:
-
name
:
paySucceed
-
name
:
paySucceed
templateId
:
156349
templateId
:
156349
...
@@ -72,6 +74,13 @@ litemall:
...
@@ -72,6 +74,13 @@ litemall:
templateId
:
158002
templateId
:
158002
-
name
:
refund
-
name
:
refund
templateId
:
159447
templateId
:
159447
tencent
:
appid
:
111111111
appkey
:
xxxxxxxxxxxxxx
aliyun
:
regionId
:
xxx
accessKeyId
:
xxx
accessKeySecret
:
xxx
# 微信模版通知配置
# 微信模版通知配置
# 微信模版用于通知客户或者运营者,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
# 微信模版用于通知客户或者运营者,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
...
@@ -127,7 +136,7 @@ litemall:
...
@@ -127,7 +136,7 @@ litemall:
# 本地对象存储配置信息
# 本地对象存储配置信息
local
:
local
:
storagePath
:
storage
storagePath
:
storage
address
:
http://1
18.24.0.153
:8080/wx/storage/fetch/
address
:
http://1
22.51.199.160
:8080/wx/storage/fetch/
# 阿里云对象存储配置信息
# 阿里云对象存储配置信息
aliyun
:
aliyun
:
endpoint
:
oss-cn-shenzhen.aliyuncs.com
endpoint
:
oss-cn-shenzhen.aliyuncs.com
...
...
deploy/util/lazy.sh
View file @
7023b205
...
@@ -2,11 +2,11 @@
...
@@ -2,11 +2,11 @@
# 本脚本的作用是
# 本脚本的作用是
# 1. 项目打包
# 1. 项目打包
# 2. 上传云
主机
# 2. 上传云
服务器
# 3. 远程登录云
主机
并执行reset脚本
# 3. 远程登录云
服务器
并执行reset脚本
# 请设置云
主机
的IP地址和账户
# 请设置云
服务器
的IP地址和账户
# 例如 ubuntu@1
18.24.0.153
# 例如 ubuntu@1
22.51.199.160
REMOTE
=
REMOTE
=
# 请设置本地SSH私钥文件id_rsa路径
# 请设置本地SSH私钥文件id_rsa路径
# 例如 /home/litemall/id_rsa
# 例如 /home/litemall/id_rsa
...
@@ -14,13 +14,13 @@ ID_RSA=
...
@@ -14,13 +14,13 @@ ID_RSA=
if
test
-z
"
$REMOTE
"
if
test
-z
"
$REMOTE
"
then
then
echo
"请设置云
主机
登录IP地址和账户"
echo
"请设置云
服务器
登录IP地址和账户"
exit
1
exit
1
fi
fi
if
test
-z
"
$ID_RSA
"
if
test
-z
"
$ID_RSA
"
then
then
echo
"请设置云
主机
登录IP地址和账户"
echo
"请设置云
服务器
登录IP地址和账户"
exit
1
exit
1
fi
fi
...
@@ -33,11 +33,11 @@ echo "LITEMALL_HOME $LITEMALL_HOME"
...
@@ -33,11 +33,11 @@ echo "LITEMALL_HOME $LITEMALL_HOME"
cd
$LITEMALL_HOME
||
exit
2
cd
$LITEMALL_HOME
||
exit
2
./deploy/util/package.sh
./deploy/util/package.sh
# 上传云
主机
# 上传云
服务器
cd
$LITEMALL_HOME
||
exit
2
cd
$LITEMALL_HOME
||
exit
2
scp
-i
$ID_RSA
-r
./deploy
$REMOTE
:/home/ubuntu/
scp
-i
$ID_RSA
-r
./deploy
$REMOTE
:/home/ubuntu/
# 远程登录云
主机
并执行reset脚本
# 远程登录云
服务器
并执行reset脚本
ssh
$REMOTE
-i
$ID_RSA
<<
eeooff
ssh
$REMOTE
-i
$ID_RSA
<<
eeooff
cd /home/ubuntu
cd /home/ubuntu
sudo ./deploy/bin/reset.sh
sudo ./deploy/bin/reset.sh
...
...
doc/platform.md
View file @
7023b205
...
@@ -1153,7 +1153,7 @@ public interface Storage {
...
@@ -1153,7 +1153,7 @@ public interface Storage {
## 2.4 litemall-all
## 2.4 litemall-all
在章节1.5中讨论的部署方案中设计了一种单
主机
单服务方案,
在章节1.5中讨论的部署方案中设计了一种单
服务器
单服务方案,
也就是说两个后台服务和静态文件都部署在一个Spring Boot可执行jar包中。
也就是说两个后台服务和静态文件都部署在一个Spring Boot可执行jar包中。
查看litemall-all模块,代码仅仅只有一个Application类。
查看litemall-all模块,代码仅仅只有一个Application类。
...
...
doc/project.md
View file @
7023b205
...
@@ -243,7 +243,7 @@ Spring Boot技术栈参考以下文档或者项目:
...
@@ -243,7 +243,7 @@ Spring Boot技术栈参考以下文档或者项目:
*
dep
*
dep
即deploy或者deployment,这里指部署(测试阶段),通常代码已经编译打包运行在远程
主机
中,
即deploy或者deployment,这里指部署(测试阶段),通常代码已经编译打包运行在远程
服务器
中,
可以对外服务。此外,这里服务访问地址通常是IP地址。如果IP是公网IP,那么
可以对外服务。此外,这里服务访问地址通常是IP地址。如果IP是公网IP,那么
部署以后就可以对外服务;如果是内网地址,那么只能内网访问。这里的“用户”主要是
部署以后就可以对外服务;如果是内网地址,那么只能内网访问。这里的“用户”主要是
指开发者本身、测试者;当然,如果是局域网或者不介意IP访问的,那么这里的“用户”
指开发者本身、测试者;当然,如果是局域网或者不介意IP访问的,那么这里的“用户”
...
@@ -251,7 +251,7 @@ Spring Boot技术栈参考以下文档或者项目:
...
@@ -251,7 +251,7 @@ Spring Boot技术栈参考以下文档或者项目:
*
prod
*
prod
即product或者production,这里指上线阶段,通常也是代码编译打包运行在远处
主机
中可以对外服务。
即product或者production,这里指上线阶段,通常也是代码编译打包运行在远处
服务器
中可以对外服务。
此外,这里服务访问地址通常是域名地址,同时端口是80web端口。上线以后直接面向的是最终用户。
此外,这里服务访问地址通常是域名地址,同时端口是80web端口。上线以后直接面向的是最终用户。
虽然服务的代码本身和dep是完全一样的,但是考虑到场景的不同,上线阶段可能在运行环境方面需要做
虽然服务的代码本身和dep是完全一样的,但是考虑到场景的不同,上线阶段可能在运行环境方面需要做
调整,例如采用反向代理屏蔽内部实际项目结构。此外,最大的不同应该是上线环境下要使用域名和80端口,
调整,例如采用反向代理屏蔽内部实际项目结构。此外,最大的不同应该是上线环境下要使用域名和80端口,
...
@@ -435,7 +435,7 @@ flush privilege
...
@@ -435,7 +435,7 @@ flush privilege
// 局域网测试使用
// 局域网测试使用
// var WxApiRoot = 'http://192.168.0.101:8080/wx/';
// var WxApiRoot = 'http://192.168.0.101:8080/wx/';
// 云平台部署时使用
// 云平台部署时使用
// var WxApiRoot = 'http://1
18.24.0.153
:8080/wx/';
// var WxApiRoot = 'http://1
22.51.199.160
:8080/wx/';
// 云平台上线时使用
// 云平台上线时使用
// var WxApiRoot = 'https://www.menethil.com.cn/wx/';
// var WxApiRoot = 'https://www.menethil.com.cn/wx/';
...
@@ -589,8 +589,10 @@ litemall:
...
@@ -589,8 +589,10 @@ litemall:
# 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
# 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
sms:
sms:
enable: false
enable: false
appid: 111111111
# 如果是腾讯云短信,则设置active的值tencent
appkey: xxxxxxxxxxxxxx
# 如果是阿里云短信,则设置active的值aliyun
active: tencent
sign: litemall
template:
template:
- name: paySucceed
- name: paySucceed
templateId: 156349
templateId: 156349
...
@@ -600,13 +602,20 @@ litemall:
...
@@ -600,13 +602,20 @@ litemall:
templateId: 158002
templateId: 158002
- name: refund
- name: refund
templateId: 159447
templateId: 159447
tencent:
appid: 111111111
appkey: xxxxxxxxxxxxxx
aliyun:
regionId: xxx
accessKeyId: xxx
accessKeySecret: xxx
```
```
配置方式:
配置方式:
1. 腾讯云短信平台申请,然后设置四个场景的短信模板;
1. 腾讯云短信平台
或者阿里云短信平台
申请,然后设置四个场景的短信模板;
2. 开发者在配置文件设置`enable`的值`true`,
然后其他信息设置
2. 开发者在配置文件设置`enable`的值`true`,
设置`active`的值`tencent`或`aliyun`
腾讯云短信平台申请的appid等值。
3. 然后配置其他信息,例如
腾讯云短信平台申请的appid等值。
这里只测试过腾讯云短信平台,开发者需要自行测试其他短信云平台。
这里只测试过腾讯云短信平台
和阿里云短信平台
,开发者需要自行测试其他短信云平台。
应用场景:
应用场景:
目前短信通知场景只支持支付成功、验证码、订单发送、退款成功四种情况。
目前短信通知场景只支持支付成功、验证码、订单发送、退款成功四种情况。
...
@@ -616,6 +625,17 @@ litemall:
...
@@ -616,6 +625,17 @@ litemall:
当配置好信息以后,开发者可以litemall-core模块的`SmsTest`测试类中设置手机号和
当配置好信息以后,开发者可以litemall-core模块的`SmsTest`测试类中设置手机号和
模板所需要的参数值,独立启动`SmsTest`测试类发送短信,然后查看手机是否成功接收短信。
模板所需要的参数值,独立启动`SmsTest`测试类发送短信,然后查看手机是否成功接收短信。
短信模板参数命名:
这里存在一个问题,即腾讯云短信的官方平台中申请短信模板格式的模板参数是数组,
例如“你好,验证码是{0},时间是{1}";
而阿里云短信的官方平台中申请短信模板的模板参数是JSON,
例如“你好,验证码是{param1},时间是{param2}"。
为了保持当前代码的通用性,本项目采用数组传递参数,而对阿里云申请模板的参数做了一定的假设:
1. 腾讯云模块参数,申请模板时按照官方设置即可,例如“你好,验证码是{0},时间是{1}";
2. 阿里云模板参数,本项目假定开发者在官方申请的参数格式应该采用"{ code: xxx, code1: xxx, code2: xxx }",
例如“你好,验证码是{code},时间是{code1}"。开发者可以查看`AliyunSmsSender`类的`sendWithTemplate`方法的
源代码即可理解。如果觉得不合理,可以自行调整相关代码。
#### 1.4.5.7 微信通知配置
#### 1.4.5.7 微信通知配置
微信通知是微信上收到的服务通知。
微信通知是微信上收到的服务通知。
...
@@ -717,7 +737,7 @@ litemall:
...
@@ -717,7 +737,7 @@ litemall:
在litemall-core模块的`application-core.yml`文件中配置对象存储服务:
在litemall-core模块的`application-core.yml`文件中配置对象存储服务:
* 本地对象存储配置
* 本地对象存储配置
如果开发者采用当前
主机
保存上传的文件,则需要配置:
如果开发者采用当前
服务器
保存上传的文件,则需要配置:
```
```
litemall:
litemall:
storage:
storage:
...
@@ -810,7 +830,7 @@ litemall:
...
@@ -810,7 +830,7 @@ litemall:
* litemall-wx模块部署在微信开发者工具中,此外数据API地址指向litemall-wx-api所在服务qi地址
* litemall-wx模块部署在微信开发者工具中,此外数据API地址指向litemall-wx-api所在服务qi地址
* litemall-admin编译出的静态文件放在web服务器或者tomcat服务器,此外服务器地址设置指向3中litemall-admin-api所在地址
* litemall-admin编译出的静态文件放在web服务器或者tomcat服务器,此外服务器地址设置指向3中litemall-admin-api所在地址
最后,**如果项目部署云
主机
,则根据开发者的部署环境在以下文件中或代码中修改相应的配置。**
最后,**如果项目部署云
服务器
,则根据开发者的部署环境在以下文件中或代码中修改相应的配置。**
1. MySQL数据库设置合适的用户名和密码信息;
1. MySQL数据库设置合适的用户名和密码信息;
2. 后端服务模块设置合适的配置信息;
2. 后端服务模块设置合适的配置信息;
...
@@ -819,32 +839,33 @@ litemall:
...
@@ -819,32 +839,33 @@ litemall:
实际上,最终的部署方案是灵活的:
实际上,最终的部署方案是灵活的:
* 可以是同一云
主机
中安装一个Spring Boot服务,同时提供litemall-admin、litemall-admin-api和litemall-wx-api三种服务
* 可以是同一云
服务器
中安装一个Spring Boot服务,同时提供litemall-admin、litemall-admin-api和litemall-wx-api三种服务
* 可以单一云
主机
中仅安装一个tomcat/nginx服务器部署litemall-admin静态页面分发服务,
* 可以单一云
服务器
中仅安装一个tomcat/nginx服务器部署litemall-admin静态页面分发服务,
然后部署两个Spring Boot的后端服务;
然后部署两个Spring Boot的后端服务;
* 也可以把litemall-admin静态页面托管第三方cdn,然后开发者部署两个后端服务
* 也可以把litemall-admin静态页面托管第三方cdn,然后开发者部署两个后端服务
* 当然,甚至多个服务器,采用集群式并发提供服务。
* 当然,甚至多个服务器,采用集群式并发提供服务。
注意
注意
> 1. `本机`指的是是当前的开发机
> 1. `本机`指的是是当前的开发机
> 2. `云
主机
`指的是开发者购买并部署的远程
主机
> 2. `云
服务器
`指的是开发者购买并部署的远程
服务器
以下简单列举几种方案。
以下简单列举几种方案。
### 1.5.1 单机单服务部署方案
### 1.5.1 单机单服务部署方案
本节介绍基于腾讯云的单机单服务部署方案,面向的是服务器数据和应用部署在云
主机
单机中用于演示的场景。
本节介绍基于腾讯云的单机单服务部署方案,面向的是服务器数据和应用部署在云
服务器
单机中用于演示的场景。
其他云应该也是可行的。
其他云应该也是可行的。
主要流程是:创建云
主机
,安装ubuntu操作系统,按照JDK和MySQL应用运行环境,部署单一Spring Boot服务。
主要流程是:创建云
服务器
,安装ubuntu操作系统,按照JDK和MySQL应用运行环境,部署单一Spring Boot服务。


#### 1.5.1.1
主机
#### 1.5.1.1
云服务器
请参考腾讯云官方文档进行相关操作。
1. 创建云服务器
1. 创建云主机虚拟机
请参考腾讯云、阿里云或者其他云平台的官方文档进行相关操作。
建议最低配置是**1核2G**。
2. 安装操作系统
2. 安装操作系统
...
@@ -854,48 +875,55 @@ litemall:
...
@@ -854,48 +875,55 @@ litemall:


目前允许的端口:
8081,8082,8083,
8080,80,443,22,3306
目前允许的端口:8080,80,443,22,3306
注意:
注意:
这里其实只需要8080端口,允许其他端口只是方面开发阶段的测试和调试。
这里其实只需要8080端口,允许其他端口只是方便开发阶段的测试和调试。
特别是3306端口,作为MySQL的远程访问端口,请在上线阶段关闭。
4. 设置SSH密钥(可选)
4. 设置SSH密钥(可选)
建议开发者设置SSH密钥,可以免密码登录云
主机
,以及用于脚本自动上传应用。
建议开发者设置SSH密钥,可以免密码登录云
服务器
,以及用于脚本自动上传应用。
5. 使用PuTTY远程登录云
主机
5. 使用PuTTY远程登录云
服务器
如果开发者设置SSH密钥,可以采用免密码登录;否则采用账号和密码登录。
如果开发者设置SSH密钥,可以采用免密码登录;否则采用账号和密码登录。
#### 1.5.1.2 JDK8
#### 1.5.1.2
Open
JDK8
https://www.digitalocean.com/community/tutorials/how-to-install-java-with-apt-get-on-ubuntu-16-04
这里可以安装openjdk-8-jre
http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html
```bash
sudo apt-get update
sudo apt-get install openjdk-8-jre
```
如果希望采用jdk,而不是jre,则可以运行
```bash
```bash
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get update
sudo apt-get install oracle-java8-installer
sudo apt-get install openjdk-8-jdk
sudo apt-get install oracle-java8-set-default
```
```
警告
注意
>
"ppa:webupd8team/java" 不是Oracle官方PPA,可能存在安全隐患
。
>
如果用户想采用Oracle JDK8或者其他JDK环境,请查阅相关资料安装
。
#### 1.5.1.3 MySQL
#### 1.5.1.3 MySQL
https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04
```
```
sudo apt-get update
sudo apt-get update
sudo apt-get install mysql-server
sudo apt-get install mysql-server
sudo apt-get install mysql-client
sudo apt-get install mysql-client
```
```
如果配置MySQL,可以运行命令
```
sudo mysql_secure_installation
```
#### 1.5.1.4 项目打包
#### 1.5.1.4 项目打包
1. 在
主机
或者开发机打包项目到deploy;
1. 在
服务器
或者开发机打包项目到deploy;
```
```
cd litemall
cd litemall
cat ./litemall-db/sql/litemall_schema.sql > ./deploy/db/litemall.sql
cat ./litemall-db/sql/litemall_schema.sql > ./deploy/db/litemall.sql
...
@@ -920,26 +948,26 @@ sudo apt-get install mysql-client
...
@@ -920,26 +948,26 @@ sudo apt-get install mysql-client
2. 修改litemall文件夹下面的*.yml外部配置文件,当litemall-all模块启动时会
2. 修改litemall文件夹下面的*.yml外部配置文件,当litemall-all模块启动时会
加载外部配置文件,而覆盖默认jar包内部的配置文件。
加载外部配置文件,而覆盖默认jar包内部的配置文件。
例如,配置文件中一些地方需要设置成远程
主机
的IP地址
例如,配置文件中一些地方需要设置成远程
服务器
的IP地址
此时deploy部署包结构如下:
此时deploy部署包结构如下:
* bin
* bin
存放远程
主机
运行的脚本,包括deploy.sh脚本和reset.sh脚本
存放远程
服务器
运行的脚本,包括deploy.sh脚本和reset.sh脚本
* db
* db
存放litemall数据库文件
存放litemall数据库文件
* litemall
* litemall
存放远程
主机
运行的代码,包括litemall-all二进制可执行包和litemall外部配置文件
存放远程
服务器
运行的代码,包括litemall-all二进制可执行包和litemall外部配置文件
* util
* util
存放开发
主机
运行的脚本,包括package.sh脚本和lazy.sh脚本。
存放开发
服务器
运行的脚本,包括package.sh脚本和lazy.sh脚本。
由于是本地开发
主机
运行,因此开发者可以不用上传到远程
主机
。
由于是本地开发
服务器
运行,因此开发者可以不用上传到远程
服务器
。
#### 1.5.1.5 项目部署
#### 1.5.1.5 项目部署
1. 远程
主机
环境(MySQL和JDK1.8)已经安装好,请确保云
主机
的安全组已经允许相应的端口。
1. 远程
服务器
环境(MySQL和JDK1.8)已经安装好,请确保云
服务器
的安全组已经允许相应的端口。
2. 导入db/litemall.sql
2. 导入db/litemall.sql
```bash
```bash
cd /home/ubuntu/deploy/db
cd /home/ubuntu/deploy/db
...
@@ -951,7 +979,7 @@ sudo apt-get install mysql-client
...
@@ -951,7 +979,7 @@ sudo apt-get install mysql-client
sudo ln -f -s /home/ubuntu/deploy/litemall/litemall.jar /etc/init.d/litemall
sudo ln -f -s /home/ubuntu/deploy/litemall/litemall.jar /etc/init.d/litemall
sudo service litemall start
sudo service litemall start
```
```
4. 测试是否部署成功(xxx.xxx.xxx.xxx是云
主机
IP):
4. 测试是否部署成功(xxx.xxx.xxx.xxx是云
服务器
IP):
```
```
http://xxx.xxx.xxx.xxx:8080/wx/index/index
http://xxx.xxx.xxx.xxx:8080/wx/index/index
http://xxx.xxx.xxx.xxx:8080/admin/index/index
http://xxx.xxx.xxx.xxx:8080/admin/index/index
...
@@ -970,26 +998,26 @@ sudo apt-get install mysql-client
...
@@ -970,26 +998,26 @@ sudo apt-get install mysql-client
* util/packet.sh
* util/packet.sh
在开发
主机
运行可以自动项目打包
在开发
服务器
运行可以自动项目打包
* util/lazy.sh
* util/lazy.sh
在开发
主机
运行可以自动项目打包、项目上传远程
主机
、自动登录系统执行项目部署脚本。
在开发
服务器
运行可以自动项目打包、项目上传远程
服务器
、自动登录系统执行项目部署脚本。
注意:
注意:
> 1. 开发者需要在util/lazy.sh中设置相应的远程
主机
登录账号和密钥文件路径。
> 1. 开发者需要在util/lazy.sh中设置相应的远程
服务器
登录账号和密钥文件路径。
> 2. 开发者需要在bin/reset.sh设置远程
主机
的MySQL的root登录账户。
> 2. 开发者需要在bin/reset.sh设置远程
服务器
的MySQL的root登录账户。
* bin/deploy.sh
* bin/deploy.sh
在远程
主机
运行可以自动部署服务
在远程
服务器
运行可以自动部署服务
* bin/reset.sh
* bin/reset.sh
在远程
主机
运行可以自动项目导入数据、删除本地上传图片、再执行bin/deploy.sh部署服务。
在远程
服务器
运行可以自动项目导入数据、删除本地上传图片、再执行bin/deploy.sh部署服务。
注意:
注意:
> 开发者需要在bin/reset.sh设置远程
主机
的MySQL的root登录账户。
> 开发者需要在bin/reset.sh设置远程
服务器
的MySQL的root登录账户。
总结,当开发者设置好配置信息以后,可以在本地运行lazy.sh脚本自动一键部署:
总结,当开发者设置好配置信息以后,可以在本地运行lazy.sh脚本自动一键部署:
```bash
```bash
...
@@ -1010,8 +1038,8 @@ cd litemall
...
@@ -1010,8 +1038,8 @@ cd litemall
1. 专门的云数据库部署数据
1. 专门的云数据库部署数据
2. 专门的云存储方案
2. 专门的云存储方案
3. 专门的CDN分发管理后台的静态文件
3. 专门的CDN分发管理后台的静态文件
4. 一台云
主机
部署管理后台的后端服务
4. 一台云
服务器
部署管理后台的后端服务
5. 一台或多台云
主机
部署小商场的后端服务
5. 一台或多台云
服务器
部署小商场的后端服务
虽然由于环境原因没有正式测试过,但是这种简单的集群式场景应该是可行的。
虽然由于环境原因没有正式测试过,但是这种简单的集群式场景应该是可行的。
在1.5.2节中所演示的三个服务是独立的,因此延伸到这里分布式是非常容易的。
在1.5.2节中所演示的三个服务是独立的,因此延伸到这里分布式是非常容易的。
...
@@ -1060,7 +1088,7 @@ sudo apt-get update
...
@@ -1060,7 +1088,7 @@ sudo apt-get update
sudo apt-get install nginx
sudo apt-get install nginx
```
```
有的文档会指出需要防火墙设置,但是腾讯云
主机
防火墙默认没有开启。
有的文档会指出需要防火墙设置,但是腾讯云
服务器
防火墙默认没有开启。
开发者这里自己可以开启设置,或者直接不开启。
开发者这里自己可以开启设置,或者直接不开启。
打开浏览器,输入以下地址:
打开浏览器,输入以下地址:
...
@@ -1330,12 +1358,12 @@ litemall-admin编译得到的前端文件在第一次加载时相当耗时,这
...
@@ -1330,12 +1358,12 @@ litemall-admin编译得到的前端文件在第一次加载时相当耗时,这
#### 1.7.2.1 deploy部署
#### 1.7.2.1 deploy部署
当前项目存在deploy部署文件夹,这个是上述1.5.1节部署腾讯云
主机
所采取的一些脚本。
当前项目存在deploy部署文件夹,这个是上述1.5.1节部署腾讯云
服务器
所采取的一些脚本。
流程如下:
流程如下:
1. util脚本是当前开发
主机
运行,用来打包项目和上传腾讯云
主机
;
1. util脚本是当前开发
服务器
运行,用来打包项目和上传腾讯云
服务器
;
2. 打包项目时,会编译打包项目相关模块到litemall和db文件夹中;
2. 打包项目时,会编译打包项目相关模块到litemall和db文件夹中;
3. bin脚本是云
主机
运行,用来安装数据库、导入数据、启动项目服务。
3. bin脚本是云
服务器
运行,用来安装数据库、导入数据、启动项目服务。
这里deploy部署方式比较简单不灵活,开发者可以参考开发自己的项目脚本。
这里deploy部署方式比较简单不灵活,开发者可以参考开发自己的项目脚本。
...
...
doc/wxmall.md
View file @
7023b205
...
@@ -83,9 +83,9 @@
...
@@ -83,9 +83,9 @@
2.
启动后台服务
2.
启动后台服务
3.
部署后台服务到云
主机
3.
部署后台服务到云
服务器
4.
litemall-wx的api.js设置云
主机
的域名。
4.
litemall-wx的api.js设置云
服务器
的域名。
编译运行,尝试微信支付。
编译运行,尝试微信支付。
### 3.0.3 微信退款配置
### 3.0.3 微信退款配置
...
@@ -236,14 +236,14 @@ var WxApiRoot = 'http://localhost:8082/wx/';
...
@@ -236,14 +236,14 @@ var WxApiRoot = 'http://localhost:8082/wx/';
// 局域网测试使用
// 局域网测试使用
// var WxApiRoot = 'http://192.168.0.101:8082/wx/';
// var WxApiRoot = 'http://192.168.0.101:8082/wx/';
// 云平台部署时使用
// 云平台部署时使用
// var WxApiRoot = 'http://1
18.24.0.153
:8082/wx/';
// var WxApiRoot = 'http://1
22.51.199.160
:8082/wx/';
```
```
也就是说这里存在三种类型的API服务地址,这里是考虑到开发存在三种情况:
也就是说这里存在三种类型的API服务地址,这里是考虑到开发存在三种情况:
1.
本机开发时,localhost是当前开发机的地址;
1.
本机开发时,localhost是当前开发机的地址;
2.
手机预览时,192.168.0.101是开发机的IP地址;
2.
手机预览时,192.168.0.101是开发机的IP地址;
3.
当后台部署在云
主机
中时,1
18.24.0.153是云主机
的IP地址;
3.
当后台部署在云
服务器
中时,1
22.51.199.160是云服务器
的IP地址;
4.
此外,更最重要的是,如果小程序正式部署时,这里的地址必须是域名,
4.
此外,更最重要的是,如果小程序正式部署时,这里的地址必须是域名,
而不能是IP地址。
而不能是IP地址。
...
...
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/job/OrderJob.java
View file @
7023b205
...
@@ -3,11 +3,8 @@ package org.linlinjava.litemall.admin.job;
...
@@ -3,11 +3,8 @@ package org.linlinjava.litemall.admin.job;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.apache.commons.logging.LogFactory
;
import
org.linlinjava.litemall.core.system.SystemConfig
;
import
org.linlinjava.litemall.core.system.SystemConfig
;
import
org.linlinjava.litemall.db.domain.LitemallOrder
;
import
org.linlinjava.litemall.db.domain.*
;
import
org.linlinjava.litemall.db.domain.LitemallOrderGoods
;
import
org.linlinjava.litemall.db.service.*
;
import
org.linlinjava.litemall.db.service.LitemallGoodsProductService
;
import
org.linlinjava.litemall.db.service.LitemallOrderGoodsService
;
import
org.linlinjava.litemall.db.service.LitemallOrderService
;
import
org.linlinjava.litemall.db.util.OrderUtil
;
import
org.linlinjava.litemall.db.util.OrderUtil
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.scheduling.annotation.Scheduled
;
import
org.springframework.scheduling.annotation.Scheduled
;
...
@@ -30,43 +27,10 @@ public class OrderJob {
...
@@ -30,43 +27,10 @@ public class OrderJob {
private
LitemallOrderService
orderService
;
private
LitemallOrderService
orderService
;
@Autowired
@Autowired
private
LitemallGoodsProductService
productService
;
private
LitemallGoodsProductService
productService
;
@Autowired
/**
private
LitemallGrouponService
grouponService
;
* 自动取消订单
@Autowired
* <p>
private
LitemallGrouponRulesService
rulesService
;
* 定时检查订单未付款情况,如果超时 LITEMALL_ORDER_UNPAID 分钟则自动取消订单
* 定时时间是每次相隔半个小时。
* <p>
* TODO
* 注意,因为是相隔半小时检查,因此导致订单真正超时时间是 [LITEMALL_ORDER_UNPAID, 30 + LITEMALL_ORDER_UNPAID]
*/
@Scheduled
(
fixedDelay
=
30
*
60
*
1000
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
checkOrderUnpaid
()
{
logger
.
info
(
"系统开启任务检查订单是否已经超期自动取消订单"
);
List
<
LitemallOrder
>
orderList
=
orderService
.
queryUnpaid
(
SystemConfig
.
getOrderUnpaid
());
for
(
LitemallOrder
order
:
orderList
)
{
// 设置订单已取消状态
order
.
setOrderStatus
(
OrderUtil
.
STATUS_AUTO_CANCEL
);
order
.
setEndTime
(
LocalDateTime
.
now
());
if
(
orderService
.
updateWithOptimisticLocker
(
order
)
==
0
)
{
throw
new
RuntimeException
(
"更新数据已失效"
);
}
// 商品货品数量增加
Integer
orderId
=
order
.
getId
();
List
<
LitemallOrderGoods
>
orderGoodsList
=
orderGoodsService
.
queryByOid
(
orderId
);
for
(
LitemallOrderGoods
orderGoods
:
orderGoodsList
)
{
Integer
productId
=
orderGoods
.
getProductId
();
Short
number
=
orderGoods
.
getNumber
();
if
(
productService
.
addStock
(
productId
,
number
)
==
0
)
{
throw
new
RuntimeException
(
"商品货品库存增加失败"
);
}
}
logger
.
info
(
"订单 ID"
+
order
.
getId
()
+
" 已经超期自动取消订单"
);
}
}
/**
/**
* 自动确认订单
* 自动确认订单
...
@@ -79,7 +43,7 @@ public class OrderJob {
...
@@ -79,7 +43,7 @@ public class OrderJob {
*/
*/
@Scheduled
(
cron
=
"0 0 3 * * ?"
)
@Scheduled
(
cron
=
"0 0 3 * * ?"
)
public
void
checkOrderUnconfirm
()
{
public
void
checkOrderUnconfirm
()
{
logger
.
info
(
"系统开启任务检查订单是否已经超期自动确认收货"
);
logger
.
info
(
"系统开启
定时
任务检查订单是否已经超期自动确认收货"
);
List
<
LitemallOrder
>
orderList
=
orderService
.
queryUnconfirm
(
SystemConfig
.
getOrderUnconfirm
());
List
<
LitemallOrder
>
orderList
=
orderService
.
queryUnconfirm
(
SystemConfig
.
getOrderUnconfirm
());
for
(
LitemallOrder
order
:
orderList
)
{
for
(
LitemallOrder
order
:
orderList
)
{
...
@@ -120,4 +84,55 @@ public class OrderJob {
...
@@ -120,4 +84,55 @@ public class OrderJob {
}
}
}
}
}
}
/**
* 团购订单拼团超期自动取消
*/
@Scheduled
(
initialDelay
=
5000
,
fixedDelay
=
10
*
60
*
1000
)
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
void
checkGrouponOrderTimeout
()
{
logger
.
info
(
"系统开启定时任务检查团购订单是否已经拼团超期自动取消订单"
);
List
<
LitemallGroupon
>
grouponList
=
grouponService
.
queryJoinRecord
(
0
);
for
(
LitemallGroupon
groupon
:
grouponList
)
{
LitemallGrouponRules
rules
=
rulesService
.
queryById
(
groupon
.
getRulesId
());
if
(
rulesService
.
isExpired
(
rules
))
{
List
<
LitemallGroupon
>
subGrouponList
=
grouponService
.
queryJoinRecord
(
groupon
.
getId
());
for
(
LitemallGroupon
subGroupon
:
subGrouponList
)
{
cancelGrouponScope
(
subGroupon
);
}
cancelGrouponScope
(
groupon
);
}
}
}
private
void
cancelGrouponScope
(
LitemallGroupon
groupon
)
{
LitemallOrder
order
=
orderService
.
findById
(
groupon
.
getOrderId
());
if
(
order
.
getOrderStatus
().
equals
(
OrderUtil
.
STATUS_PAY_GROUPON
))
{
order
.
setOrderStatus
(
OrderUtil
.
STATUS_TIMEOUT_GROUPON
);
order
.
setEndTime
(
LocalDateTime
.
now
());
cancelOrderScope
(
order
);
logger
.
info
(
"团购订单 ID"
+
order
.
getId
()
+
" 已经拼团超期自动取消订单"
);
}
}
private
void
cancelOrderScope
(
LitemallOrder
order
)
{
if
(
orderService
.
updateWithOptimisticLocker
(
order
)
==
0
)
{
throw
new
RuntimeException
(
"更新数据已失效"
);
}
// 商品货品数量增加
Integer
orderId
=
order
.
getId
();
List
<
LitemallOrderGoods
>
orderGoodsList
=
orderGoodsService
.
queryByOid
(
orderId
);
for
(
LitemallOrderGoods
orderGoods
:
orderGoodsList
)
{
Integer
productId
=
orderGoods
.
getProductId
();
Short
number
=
orderGoods
.
getNumber
();
if
(
productService
.
addStock
(
productId
,
number
)
==
0
)
{
throw
new
RuntimeException
(
"商品货品库存增加失败"
);
}
}
}
}
}
litemall-admin/config/dep.env.js
View file @
7023b205
module
.
exports
=
{
module
.
exports
=
{
NODE_ENV
:
'
"production"
'
,
NODE_ENV
:
'
"production"
'
,
ENV_CONFIG
:
'
"dep"
'
,
ENV_CONFIG
:
'
"dep"
'
,
BASE_API
:
'
"http://1
18.24.0.153
:8080/admin"
'
BASE_API
:
'
"http://1
22.51.199.160
:8080/admin"
'
}
}
litemall-admin/src/main.js
View file @
7023b205
...
@@ -20,6 +20,10 @@ import * as filters from './filters' // global filters
...
@@ -20,6 +20,10 @@ import * as filters from './filters' // global filters
import
permission
from
'
@/directive/permission/index.js
'
// 权限判断指令
import
permission
from
'
@/directive/permission/index.js
'
// 权限判断指令
import
Print
from
'
@/utils/print
'
// 打印
Vue
.
use
(
Print
)
Vue
.
use
(
Element
,
{
Vue
.
use
(
Element
,
{
size
:
Cookies
.
get
(
'
size
'
)
||
'
medium
'
// set element-ui default size
size
:
Cookies
.
get
(
'
size
'
)
||
'
medium
'
// set element-ui default size
})
})
...
...
litemall-admin/src/utils/print.js
0 → 100644
View file @
7023b205
// 打印类属性、方法定义
/* eslint-disable */
const
Print
=
function
(
dom
,
options
)
{
if
(
!
(
this
instanceof
Print
))
return
new
Print
(
dom
,
options
);
this
.
options
=
this
.
extend
({
'
noPrint
'
:
'
.no-print
'
},
options
);
if
((
typeof
dom
)
===
"
string
"
)
{
this
.
dom
=
document
.
querySelector
(
dom
);
}
else
{
this
.
isDOM
(
dom
)
this
.
dom
=
this
.
isDOM
(
dom
)
?
dom
:
dom
.
$el
;
}
this
.
init
();
};
Print
.
prototype
=
{
init
:
function
()
{
var
content
=
this
.
getStyle
()
+
this
.
getHtml
();
this
.
writeIframe
(
content
);
},
extend
:
function
(
obj
,
obj2
)
{
for
(
var
k
in
obj2
)
{
obj
[
k
]
=
obj2
[
k
];
}
return
obj
;
},
getStyle
:
function
()
{
var
str
=
""
,
styles
=
document
.
querySelectorAll
(
'
style,link
'
);
for
(
var
i
=
0
;
i
<
styles
.
length
;
i
++
)
{
str
+=
styles
[
i
].
outerHTML
;
}
str
+=
"
<style>
"
+
(
this
.
options
.
noPrint
?
this
.
options
.
noPrint
:
'
.no-print
'
)
+
"
{display:none;}</style>
"
;
return
str
;
},
getHtml
:
function
()
{
var
inputs
=
document
.
querySelectorAll
(
'
input
'
);
var
textareas
=
document
.
querySelectorAll
(
'
textarea
'
);
var
selects
=
document
.
querySelectorAll
(
'
select
'
);
for
(
var
k
=
0
;
k
<
inputs
.
length
;
k
++
)
{
if
(
inputs
[
k
].
type
==
"
checkbox
"
||
inputs
[
k
].
type
==
"
radio
"
)
{
if
(
inputs
[
k
].
checked
==
true
)
{
inputs
[
k
].
setAttribute
(
'
checked
'
,
"
checked
"
)
}
else
{
inputs
[
k
].
removeAttribute
(
'
checked
'
)
}
}
else
if
(
inputs
[
k
].
type
==
"
text
"
)
{
inputs
[
k
].
setAttribute
(
'
value
'
,
inputs
[
k
].
value
)
}
else
{
inputs
[
k
].
setAttribute
(
'
value
'
,
inputs
[
k
].
value
)
}
}
for
(
var
k2
=
0
;
k2
<
textareas
.
length
;
k2
++
)
{
if
(
textareas
[
k2
].
type
==
'
textarea
'
)
{
textareas
[
k2
].
innerHTML
=
textareas
[
k2
].
value
}
}
for
(
var
k3
=
0
;
k3
<
selects
.
length
;
k3
++
)
{
if
(
selects
[
k3
].
type
==
'
select-one
'
)
{
var
child
=
selects
[
k3
].
children
;
for
(
var
i
in
child
)
{
if
(
child
[
i
].
tagName
==
'
OPTION
'
)
{
if
(
child
[
i
].
selected
==
true
)
{
child
[
i
].
setAttribute
(
'
selected
'
,
"
selected
"
)
}
else
{
child
[
i
].
removeAttribute
(
'
selected
'
)
}
}
}
}
}
return
this
.
dom
.
outerHTML
;
},
writeIframe
:
function
(
content
)
{
var
w
,
doc
,
iframe
=
document
.
createElement
(
'
iframe
'
),
f
=
document
.
body
.
appendChild
(
iframe
);
iframe
.
id
=
"
myIframe
"
;
//iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
iframe
.
setAttribute
(
'
style
'
,
'
position:absolute;width:0;height:0;top:-10px;left:-10px;
'
);
w
=
f
.
contentWindow
||
f
.
contentDocument
;
doc
=
f
.
contentDocument
||
f
.
contentWindow
.
document
;
doc
.
open
();
doc
.
write
(
content
);
doc
.
close
();
var
_this
=
this
iframe
.
onload
=
function
(){
_this
.
toPrint
(
w
);
setTimeout
(
function
()
{
document
.
body
.
removeChild
(
iframe
)
},
100
)
}
},
toPrint
:
function
(
frameWindow
)
{
try
{
setTimeout
(
function
()
{
frameWindow
.
focus
();
try
{
if
(
!
frameWindow
.
document
.
execCommand
(
'
print
'
,
false
,
null
))
{
frameWindow
.
print
();
}
}
catch
(
e
)
{
frameWindow
.
print
();
}
frameWindow
.
close
();
},
10
);
}
catch
(
err
)
{
console
.
log
(
'
err
'
,
err
);
}
},
isDOM
:
(
typeof
HTMLElement
===
'
object
'
)
?
function
(
obj
)
{
return
obj
instanceof
HTMLElement
;
}
:
function
(
obj
)
{
return
obj
&&
typeof
obj
===
'
object
'
&&
obj
.
nodeType
===
1
&&
typeof
obj
.
nodeName
===
'
string
'
;
}
};
const
MyPlugin
=
{}
MyPlugin
.
install
=
function
(
Vue
,
options
)
{
// 4. 添加实例方法
Vue
.
prototype
.
$print
=
Print
}
export
default
MyPlugin
litemall-admin/src/views/config/express.vue
View file @
7023b205
...
@@ -50,8 +50,12 @@ export default {
...
@@ -50,8 +50,12 @@ export default {
update
()
{
update
()
{
this
.
$refs
[
'
dataForm
'
].
validate
((
valid
)
=>
{
this
.
$refs
[
'
dataForm
'
].
validate
((
valid
)
=>
{
if
(
!
valid
)
{
if
(
!
valid
)
{
return
return
false
}
}
this
.
doUpdate
()
})
},
doUpdate
()
{
updateExpress
(
this
.
dataForm
).
then
(
response
=>
{
updateExpress
(
this
.
dataForm
).
then
(
response
=>
{
this
.
$notify
.
success
({
this
.
$notify
.
success
({
title
:
'
成功
'
,
title
:
'
成功
'
,
...
@@ -63,7 +67,6 @@ export default {
...
@@ -63,7 +67,6 @@ export default {
message
:
response
.
data
.
errmsg
message
:
response
.
data
.
errmsg
})
})
})
})
})
}
}
}
}
}
}
...
...
litemall-admin/src/views/config/mall.vue
View file @
7023b205
...
@@ -33,6 +33,20 @@ export default {
...
@@ -33,6 +33,20 @@ export default {
litemall_mall_address
:
''
,
litemall_mall_address
:
''
,
litemall_mall_phone
:
''
,
litemall_mall_phone
:
''
,
litemall_mall_qq
:
''
litemall_mall_qq
:
''
},
rules
:
{
litemall_mall_name
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_mall_address
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_mall_phone
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_mall_qq
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
]
}
}
}
}
},
},
...
@@ -49,6 +63,14 @@ export default {
...
@@ -49,6 +63,14 @@ export default {
this
.
init
()
this
.
init
()
},
},
update
()
{
update
()
{
this
.
$refs
[
'
dataForm
'
].
validate
((
valid
)
=>
{
if
(
!
valid
)
{
return
false
}
this
.
doUpdate
()
})
},
doUpdate
()
{
updateMall
(
this
.
dataForm
)
updateMall
(
this
.
dataForm
)
.
then
(
response
=>
{
.
then
(
response
=>
{
this
.
$notify
.
success
({
this
.
$notify
.
success
({
...
...
litemall-admin/src/views/config/order.vue
View file @
7023b205
...
@@ -34,7 +34,22 @@ export default {
...
@@ -34,7 +34,22 @@ export default {
name
:
'
ConfigOrder
'
,
name
:
'
ConfigOrder
'
,
data
()
{
data
()
{
return
{
return
{
dataForm
:
{}
dataForm
:
{
litemall_order_unpaid
:
0
,
litemall_order_unconfirm
:
0
,
litemall_order_comment
:
0
},
rules
:
{
litemall_order_unpaid
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_order_unconfirm
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_order_comment
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
]
}
}
}
},
},
created
()
{
created
()
{
...
@@ -50,6 +65,14 @@ export default {
...
@@ -50,6 +65,14 @@ export default {
this
.
init
()
this
.
init
()
},
},
update
()
{
update
()
{
this
.
$refs
[
'
dataForm
'
].
validate
((
valid
)
=>
{
if
(
!
valid
)
{
return
false
}
this
.
doUpdate
()
})
},
doUpdate
()
{
updateOrder
(
this
.
dataForm
)
updateOrder
(
this
.
dataForm
)
.
then
(
response
=>
{
.
then
(
response
=>
{
this
.
$notify
.
success
({
this
.
$notify
.
success
({
...
...
litemall-admin/src/views/config/wx.vue
View file @
7023b205
...
@@ -5,9 +5,7 @@
...
@@ -5,9 +5,7 @@
:rules=
"rules"
:rules=
"rules"
:model=
"dataForm"
:model=
"dataForm"
status-icon
status-icon
label-width=
"300px"
label-width=
"300px"
>
>
<el-tabs
tab-position=
"left"
>
<el-tabs
tab-position=
"left"
>
<el-tab-pane
label=
"首页配置"
>
<el-tab-pane
label=
"首页配置"
>
<el-form-item
label=
"新品首发栏目商品显示数量"
prop=
"litemall_wx_index_new"
>
<el-form-item
label=
"新品首发栏目商品显示数量"
prop=
"litemall_wx_index_new"
>
...
@@ -51,7 +49,35 @@ export default {
...
@@ -51,7 +49,35 @@ export default {
name
:
'
ConfigWx
'
,
name
:
'
ConfigWx
'
,
data
()
{
data
()
{
return
{
return
{
dataForm
:
{
}
dataForm
:
{
litemall_wx_index_new
:
0
,
litemall_wx_index_hot
:
0
,
litemall_wx_index_brand
:
0
,
litemall_wx_index_topic
:
0
,
litemall_wx_catlog_list
:
0
,
litemall_wx_catlog_goods
:
0
,
litemall_wx_share
:
false
},
rules
:
{
litemall_wx_index_new
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_wx_index_hot
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_wx_index_brand
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_wx_index_topic
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_wx_catlog_list
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
],
litemall_wx_catlog_goods
:
[
{
required
:
true
,
message
:
'
不能为空
'
,
trigger
:
'
blur
'
}
]
}
}
}
},
},
created
()
{
created
()
{
...
@@ -67,6 +93,14 @@ export default {
...
@@ -67,6 +93,14 @@ export default {
this
.
init
()
this
.
init
()
},
},
update
()
{
update
()
{
this
.
$refs
[
'
dataForm
'
].
validate
((
valid
)
=>
{
if
(
!
valid
)
{
return
false
}
this
.
doUpdate
()
})
},
doUpdate
()
{
updateWx
(
this
.
dataForm
)
updateWx
(
this
.
dataForm
)
.
then
(
response
=>
{
.
then
(
response
=>
{
this
.
$notify
.
success
({
this
.
$notify
.
success
({
...
...
litemall-admin/src/views/mall/order.vue
View file @
7023b205
...
@@ -39,7 +39,7 @@
...
@@ -39,7 +39,7 @@
<
template
slot-scope=
"scope"
>
<
template
slot-scope=
"scope"
>
<el-button
v-permission=
"['GET /admin/order/detail']"
type=
"primary"
size=
"mini"
@
click=
"handleDetail(scope.row)"
>
详情
</el-button>
<el-button
v-permission=
"['GET /admin/order/detail']"
type=
"primary"
size=
"mini"
@
click=
"handleDetail(scope.row)"
>
详情
</el-button>
<el-button
v-permission=
"['POST /admin/order/ship']"
v-if=
"scope.row.orderStatus==201"
type=
"primary"
size=
"mini"
@
click=
"handleShip(scope.row)"
>
发货
</el-button>
<el-button
v-permission=
"['POST /admin/order/ship']"
v-if=
"scope.row.orderStatus==201"
type=
"primary"
size=
"mini"
@
click=
"handleShip(scope.row)"
>
发货
</el-button>
<el-button
v-permission=
"['POST /admin/order/refund']"
v-if=
"scope.row.orderStatus==202"
type=
"primary"
size=
"mini"
@
click=
"handleRefund(scope.row)"
>
退款
</el-button>
<el-button
v-permission=
"['POST /admin/order/refund']"
v-if=
"scope.row.orderStatus==202
||scope.row.orderStatus==204
"
type=
"primary"
size=
"mini"
@
click=
"handleRefund(scope.row)"
>
退款
</el-button>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
</el-table>
</el-table>
...
@@ -48,7 +48,7 @@
...
@@ -48,7 +48,7 @@
<!-- 订单详情对话框 -->
<!-- 订单详情对话框 -->
<el-dialog
:visible.sync=
"orderDialogVisible"
title=
"订单详情"
width=
"800"
>
<el-dialog
:visible.sync=
"orderDialogVisible"
title=
"订单详情"
width=
"800"
>
<section
ref=
"print"
>
<el-form
:data=
"orderDetail"
label-position=
"left"
>
<el-form
:data=
"orderDetail"
label-position=
"left"
>
<el-form-item
label=
"订单编号"
>
<el-form-item
label=
"订单编号"
>
<span>
{{ orderDetail.order.orderSn }}
</span>
<span>
{{ orderDetail.order.orderSn }}
</span>
...
@@ -103,6 +103,11 @@
...
@@ -103,6 +103,11 @@
<span>
(确认收货时间){{ orderDetail.order.confirmTime }}
</span>
<span>
(确认收货时间){{ orderDetail.order.confirmTime }}
</span>
</el-form-item>
</el-form-item>
</el-form>
</el-form>
</section>
<span
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"orderDialogVisible = false"
>
取 消
</el-button>
<el-button
type=
"primary"
@
click=
"printOrder"
>
打 印
</el-button>
</span>
</el-dialog>
</el-dialog>
<!-- 发货对话框 -->
<!-- 发货对话框 -->
...
@@ -138,7 +143,7 @@
...
@@ -138,7 +143,7 @@
</template>
</template>
<
script
>
<
script
>
import
{
list
Order
,
ship
Order
,
refundOrder
,
detail
Order
}
from
'
@/api/order
'
import
{
detail
Order
,
list
Order
,
refundOrder
,
ship
Order
}
from
'
@/api/order
'
import
Pagination
from
'
@/components/Pagination
'
// Secondary package based on el-pagination
import
Pagination
from
'
@/components/Pagination
'
// Secondary package based on el-pagination
import
checkPermission
from
'
@/utils/permission
'
// 权限判断函数
import
checkPermission
from
'
@/utils/permission
'
// 权限判断函数
...
@@ -146,9 +151,11 @@ const statusMap = {
...
@@ -146,9 +151,11 @@ const statusMap = {
101
:
'
未付款
'
,
101
:
'
未付款
'
,
102
:
'
用户取消
'
,
102
:
'
用户取消
'
,
103
:
'
系统取消
'
,
103
:
'
系统取消
'
,
200
:
'
已付款团购
'
,
201
:
'
已付款
'
,
201
:
'
已付款
'
,
202
:
'
申请退款
'
,
202
:
'
申请退款
'
,
203
:
'
已退款
'
,
203
:
'
已退款
'
,
204
:
'
已超时团购
'
,
301
:
'
已发货
'
,
301
:
'
已发货
'
,
401
:
'
用户收货
'
,
401
:
'
用户收货
'
,
402
:
'
系统收货
'
402
:
'
系统收货
'
...
@@ -289,6 +296,10 @@ export default {
...
@@ -289,6 +296,10 @@ export default {
excel
.
export_json_to_excel2
(
tHeader
,
this
.
list
,
filterVal
,
'
订单信息
'
)
excel
.
export_json_to_excel2
(
tHeader
,
this
.
list
,
filterVal
,
'
订单信息
'
)
this
.
downloadLoading
=
false
this
.
downloadLoading
=
false
})
})
},
printOrder
()
{
this
.
$print
(
this
.
$refs
.
print
)
this
.
orderDialogVisible
=
false
}
}
}
}
}
}
...
...
litemall-all/pom.xml
View file @
7023b205
...
@@ -57,6 +57,27 @@
...
@@ -57,6 +57,27 @@
</executions>
</executions>
</plugin>
</plugin>
<plugin>
<artifactId>
maven-resources-plugin
</artifactId>
<executions>
<execution>
<id>
copy-resources-vue
</id>
<phase>
validate
</phase>
<goals>
<goal>
copy-resources
</goal>
</goals>
<configuration>
<outputDirectory>
${basedir}/target/classes/static/vue
</outputDirectory>
<resources>
<resource>
<directory>
../litemall-vue/dist
</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</plugins>
</build>
</build>
...
...
litemall-core/pom.xml
View file @
7023b205
...
@@ -16,6 +16,12 @@
...
@@ -16,6 +16,12 @@
<artifactId>
hibernate-validator
</artifactId>
<artifactId>
hibernate-validator
</artifactId>
</dependency>
</dependency>
<dependency>
<groupId>
com.aliyun
</groupId>
<artifactId>
aliyun-java-sdk-core
</artifactId>
<version>
4.0.3
</version>
</dependency>
<dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
<artifactId>
spring-boot-starter-web
</artifactId>
...
...
Prev
1
2
3
4
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment