59 Commits

Author SHA1 Message Date
zhuoda
b782b953a5 update README.md. 2022-04-26 05:38:58 +00:00
zhuoda
4fc2976624 update 2021-09-13 14:36:17 +00:00
lipeng
c692d0e6d3 增加缺失依赖 2021-08-10 13:13:17 +08:00
zhuoda
1204787cf3 update 代码规范/api接口规范.md. 2021-05-19 10:48:01 +08:00
zhuoda
2d61c21398 update 代码规范/api接口规范.md. 2021-05-19 10:47:44 +08:00
zhuoda
fe6ab3798a update 代码规范/api接口规范.md. 2021-05-19 10:47:36 +08:00
zhuoda
0c0da77ecd 更新api接口规范 2021-05-19 10:46:37 +08:00
zhuoda
c530d8db15 add 代码规范/api接口规范.md. 2021-05-19 10:39:04 +08:00
zhuoda
a1357155b9 去掉引导和修改默认登录账号 2021-05-02 10:15:25 +08:00
zhuoda
b072b9e758 update README.md. 2021-04-16 22:48:51 +08:00
zhuoda
355643ce86 update README.md. 2021-04-15 22:33:50 +08:00
1024-lab
5e43679c3c update README.md. 2021-03-05 21:03:14 +08:00
1024-lab
5249c2fdf5 update README.md. 2021-03-05 21:02:18 +08:00
1024-lab
8fc8338bfa update README.md. 2021-03-05 08:56:10 +08:00
yandy_java
111d930f98 !6 修复同电话员工校验
Merge pull request !6 from Anonym/master
2021-01-18 21:55:43 +08:00
yandy_java
835076c301 !7 bug修复及优化
Merge pull request !7 from Turbolisten/master
2021-01-18 21:54:47 +08:00
zhuoda
02560ea621 package lock 2021-01-11 21:24:50 +08:00
zhuoda
606e763126 优化h5项目 2021-01-10 20:21:30 +08:00
Turbolisten
21cd668943 修改数据库字符编码统一为utf8mb4_unicode_ci 2021-01-09 10:22:21 +08:00
Turbolisten
ea0159ddb4 优化枚举类校验;优化Swagger配置,添加默认参数;fix删除部门;优化ResponseDTO; 2021-01-09 10:13:15 +08:00
Turbolisten
f7155ac4c2 Merge remote-tracking branch 'origin/master' 2021-01-09 09:05:03 +08:00
Turbolisten
063190c314 update .gitignore 2021-01-08 22:01:36 +08:00
zhuoda
7e580440f0 v1.10.0 2020-12-14 15:56:25 +08:00
zhuoda
653f4c2d6c fix code 2020-12-14 14:10:27 +08:00
李宗亮
46645e5696 修复同电话员工校验 2020-12-09 11:20:01 +08:00
1024-lab
0ba522632b update README.md. 2020-12-08 18:11:52 +08:00
1024-lab
56df084e57 update README.md. 2020-12-08 18:05:40 +08:00
1024-lab
29789e2b3f update README.md. 2020-12-08 18:05:10 +08:00
zhuoda
49da08dfc1 smart-admin-h5 2020-11-29 23:35:57 +08:00
zhuoda
fb33580397 !5 smartadmin问题修改
Merge pull request !5 from yandy_java/master
2020-11-29 22:39:45 +08:00
yandy_java
b03a911ba9 Merge branch 'master' of gitee.com:lab1024/smart-admin into master 2020-11-29 22:32:49 +08:00
1024-lab
80bee09d3e !4 EmployeeMapper.xml动态平台修改
Merge pull request !4 from gaoshun/master
2020-11-29 21:56:46 +08:00
yandanyang
fa21afa5ba employee bug修改 2020-11-28 23:10:34 +08:00
yandanyang
01fe8a7c16 1.修改quartz问题。2完善数据范围添加策略支持。3修改swaggerbug。4取消验证码 2020-11-28 23:02:08 +08:00
Turbolisten
701d95653e 优化枚举类校验;Decimal工具类增加max,min 2020-10-24 09:59:13 +08:00
gaoshun
3b1603aceb git commit
getEmployeeByIds 拼接sql括号添加
2020-10-16 17:44:35 +08:00
gaoshun
72118743ef git commit
getEmployeeIdByDeptIds括号添加
2020-10-16 17:42:40 +08:00
gaoshun
58113847f4 git commit
方法close open闭合括号修改
2020-10-16 17:41:06 +08:00
zhuoda
70173ebd22 v1.2.1 2020-09-22 09:33:56 +08:00
1024-lab
8f32765f44 !2 update smart-admin-web/src/views/login/login.less.
Merge pull request !2 from 葉者/N/A
2020-09-21 21:49:46 +08:00
1024-lab
291674d3a9 !3 【轻量更新修复】修改单词错误;修改PageUtil工具类等等
Merge pull request !3 from Turbolisten/master
2020-09-21 21:48:58 +08:00
Turbolisten
2a72e341e6 还原date 2020-09-18 17:41:01 +08:00
Turbolisten
68015d3e7f 更新枚举类swagger注解ApiModelPropertyEnum -增加是否隐藏属性hidden默认展示 2020-09-18 17:35:41 +08:00
葉者
418e2064a5 update smart-admin-web/src/views/login/login.less.
登陆面板圆角样式处理
2020-09-10 17:22:03 +08:00
Turbolisten
3e95e29b15 修改单词错误;修改Date为LocalDateTime;修改PageUtil工具类;添加.gitignore; 2020-09-07 18:30:26 +08:00
zhuo
486cc02088 v1.2.0 2020-09-06 17:42:14 +08:00
1024-lab
029d9b0ef0 去掉qq群 2020-05-26 08:23:50 +08:00
zhuoda
6c0fbbc7c4 v1.1.0 2020-04-20 17:10:24 +08:00
zhuoda
e486c1ff33 v1.1.0 2020-04-20 17:08:42 +08:00
1024-lab
0646df4d8e v1.1.0 2020-04-08 20:58:59 +08:00
zhuoda
d53f271fc1 v1.1.0 2020-04-08 20:44:29 +08:00
zhuoda
1a42250f2f v1.1.0 2020-04-08 20:43:08 +08:00
zhuoda
8d70747f59 v1.1.0 2020-04-08 20:32:02 +08:00
zhuoda
e540cd75cc v1.1.0 2020-04-08 20:30:05 +08:00
zhuoda
a34f5d5afa v1.1.0 2020-04-08 20:15:01 +08:00
zhuoda
8394525697 v1.1.0 2020-04-07 22:10:57 +08:00
1024-lab
741a00289a update README.md. 2020-03-25 21:57:04 +08:00
1024-lab
4d745decf3 update README.md. 2020-03-25 21:56:38 +08:00
zhuokongming
a6d3ace808 v1.0.9 2020-03-19 14:05:42 +08:00
560 changed files with 30563 additions and 3215 deletions

29
.gitignore vendored
View File

@@ -1,6 +1,31 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
**/target/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
**/node_modules/
### VS Code ###
.vscode/

View File

@@ -1,3 +1,4 @@
### SmartAdmin 2.0 (即 vue3 的 js版本和ts版本 )正在火热开发中,欢迎持续关注
#### 简介
SmartAdmin由河南·洛阳 [1024创新实验室](https://www.1024lab.net/)团队研发的一套互联网企业级的通用型中后台解决方案使用最前沿的前后台技术栈SpringBoot和Vue前后端分离<font color="#DC143C">**我们开源一套漂亮的代码和一套整洁的代码规范**</font>让大家在这浮躁的代码世界里感受到一股把代码写好的清流同时又让开发者节省大量的时间减少加班快乐工作热爱生活。SmartAdmin 让你从认识到忘不了,绝对是你最想要的!
@@ -5,7 +6,8 @@ SmartAdmin由河南·洛阳 [1024创新实验室](https://www.1024lab.net/)团
github: [https://github.com/1024-lab/smart-admin](https://github.com/1024-lab/smart-admin)
gitee: [https://gitee.com/lab1024/smart-admin](https://gitee.com/lab1024/smart-admin)
在线预览: [http://preview.smartadmin.1024lab.net](http://preview.smartadmin.1024lab.net)
部署文档:[http://smartadmin.1024lab.net/doc/1/68](http://smartadmin.1024lab.net/doc/1/68)
部署文档:[http://smartadmin.1024lab.net](http://smartadmin.1024lab.net)
#### 疑惑
有人问:又是个“轮子”? 轮子靠谱吗?为什么要选择你这个轮子?
@@ -24,38 +26,38 @@ gitee: [https://gitee.com/lab1024/smart-admin](https://gitee.com/lab1024/smart-
#### 演示图
<table>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/11.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/12.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180453_252f5e9f_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180630_ee5b4f46_5469596.png"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/21.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/22.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180737_9363e283_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180802_aefb78f4_5469596.png"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/31.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/32.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180821_30fc7aaf_5469596.png")"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180844_01ebd7d2_5469596.png")"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/41.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/42.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180902_02c8d838_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180918_ff1f7ff5_5469596.png"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/51.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/52.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180938_86b39645_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/180956_69e25a9c_5469596.png"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/61.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/62.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181013_791d92f0_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181032_9f0dbbee_5469596.png"/></td>
</tr>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/71.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/cut/72.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181049_099d0169_5469596.png"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181104_914c457a_5469596.png"/></td>
</tr>
</table>
#### 技术体系
- 前端Vue + Vue-Router + Vuex + ViewUI(iview) + vue-enum
- 前端Vue + Vue-Router + Vuex + ViewUI + vue-enum
- 后端SpringBoot2 + Mybatis-plus + jwt + druid + mysql
- 前端代码规范smart-front-standard -guide大力推荐
- 基于阿里规范之上的后端规范smart-backend-standard-guide大力推荐
@@ -67,7 +69,7 @@ gitee: [https://gitee.com/lab1024/smart-admin](https://gitee.com/lab1024/smart-
- 前端常量维护: vue-enum拒绝出现魔法数字代码不可维护的现象
- 全新的基于前端的权限设计(忘掉传统的权限设计吧,已经不适合这个前端时代)
- 基于websocket的在线人数
- 支持一级、二级、三级菜单,搜索功能
- 支持一级、二级、三级菜单,四级菜单以及搜索功能
- 其他功能:邮件、富文本、消息、系统配置等等
- 写不完了,太多好的细节需要你的发现......
@@ -103,17 +105,33 @@ gitee: [https://gitee.com/lab1024/smart-admin](https://gitee.com/lab1024/smart-
ps以上规范基础都是以团队出发让团队开心快乐的写代码而不是为了代码规范而规范不喜勿喷谢谢。
#### 联系我们
[1024创新实验室](https://www.1024lab.net/)
公众号
<table>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2021/0305/210257_cd96d824_5469596.jpeg"/></td>
</tr>
</table>
官方QQ群914442584
SmartAdmin微信群**加我拉你入群!**
SmartAdmin微信群**加我微信拉你入群!**
<table>
<tr>
<td><img src="http://cdn.1024lab.net/img/smart-admin/zhuoda-wechat.jpg"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/smart-admin-qq-group.png"/></td>
<td><img src="http://cdn.1024lab.net/img/smart-admin/zhuoda-wechat-money-v1.jpg"/></td>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181125_2ab89aa9_5469596.jpeg"/></td>
</tr>
</table>
#### 捐赠
开源不易,感谢捐赠
>*佛祖保佑捐赠这些人写程序永无bug工资翻倍迎娶白富美走上人生巅峰*
<table>
<tr>
<td><img src="https://images.gitee.com/uploads/images/2020/1208/181143_b6804a87_5469596.jpeg"/></td>
</tr>
</table>

View File

@@ -0,0 +1,2 @@
> 1%
last 2 versions

View File

@@ -0,0 +1,15 @@
root = true
[*]
# 字符
charset = utf-8
# 空格
indent_style = space
# 2个空格缩进
indent_size = 2
# 换行符
end_of_line = lf
# 文件的最后插入一个空行
insert_final_newline = true
# 删除行尾的空格
trim_trailing_whitespace = true

View File

@@ -0,0 +1,3 @@
NODE_ENV = development
VUE_APP_ENV = dev
VUE_APP_URL = http://127.0.0.1:10086/smart-admin-api

View File

@@ -0,0 +1,3 @@
NODE_ENV = development
VUE_APP_ENV = local
VUE_APP_URL = http://127.0.0.1:10086/smart-admin-api

3
smart-admin-h5/.env.pre Normal file
View File

@@ -0,0 +1,3 @@
NODE_ENV = production
VUE_APP_ENV = pre
VUE_APP_URL = http://smartadmin.1024lab.net/smart-admin-api

3
smart-admin-h5/.env.prod Normal file
View File

@@ -0,0 +1,3 @@
NODE_ENV = production
VUE_APP_ENV = prod
VUE_APP_URL = http://smartadmin.1024lab.net/smart-admin-api

3
smart-admin-h5/.env.sit Normal file
View File

@@ -0,0 +1,3 @@
NODE_ENV = production
VUE_APP_ENV = sit
VUE_APP_URL = http://smartadmin.1024lab.net/smart-admin-api

View File

@@ -0,0 +1,7 @@
# 忽略项目中某些文件的提交代码规范
build/*.js
src/assets
public
dist

232
smart-admin-h5/.eslintrc.js Normal file
View File

@@ -0,0 +1,232 @@
module.exports = {
root: true,
env: {
node: true
},
extends: [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
// 具体请看 https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/max-attributes-per-line.md
'vue/max-attributes-per-line': [
2,
{
singleline: 10,
multiline: {
max: 1,
allowFirstLine: false
}
}
],
// 在单行元素的内容前后需要换行符
'vue/singleline-html-element-content-newline': 'off',
// 在多行元素的内容之前和之后需要换行符
'vue/multiline-html-element-content-newline': 'off',
// JS/JSX中的组件名应该 大写驼峰 命名法
'vue/name-property-casing': ['error', 'PascalCase'],
// 给v-for设置键值与key结合使用可以高效的更新虚拟DOM
"vue/require-v-for-key": 1,
'vue/no-v-html': 'off',
// 在对象中强制使用getter/setter
'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'],
// 构建方法中使用super方法
'constructor-super': 2,
curly: [2, 'multi-line'],
// 在dot之前和之后强制换行
'dot-location': [2, 'property'],
// 在文件末尾要求或禁止换行
'eol-last': 2,
// 是否使用全等
eqeqeq: ['error', 'always', { null: 'ignore' }],
// 在生成器函数中强制执行*周围的间距
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
// 强制执行回调错误处理
'handle-callback-err': [1, '^(err|error)$'],
// 强制执行一致的缩进
'indent': [2, 2, {
'SwitchCase': 1
}],
// 强制在JSX文件中一致使用单引号
'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, // 禁止修改使用const声明的变量
'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, // 禁止使用eval
'no-ex-assign': 2, // 禁止在catch子句中重新分配异常
'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, // 禁止在RegExp中使用无效的正则表达式字符串
'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': 0,
'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, // 禁止finally块中的控制流语句
'no-unused-vars': [2, { // 禁止使用未声明的变量
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2, // 禁止不必要的call()和apply()方法
'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: ["error", "always"],
'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': 1,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

22
smart-admin-h5/.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
node_modules
/dist
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.DS_Store
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
package-lock.json
yarn.lock
build/env.js

View File

@@ -0,0 +1,11 @@
module.exports = {
plugins: {
autoprefixer: {
overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8']
},
'postcss-pxtorem': {
rootValue: 37.5,
propList: ['*'],
}
}
}

View File

@@ -0,0 +1,31 @@
module.exports = {
// 缩进字节数
tabWidth: 2,
// 使用单引号代替双引号
singleQuote: true,
// 在对象或数组最后一个元素后面是否加逗号在ES5中加尾逗号
trailingComma: 'none',
// 句尾添加分号
semi: true,
// 默认值。因为使用了一些折行敏感型的渲染器如GitHub comment而按照markdown文本样式进行折行
proseWrap: 'always',
// (x) => {} 箭头函数参数只有一个时是否要有小括号。avoid省略括号
arrowParens: 'avoid',
// 在对象,数组括号与文字之间加空格 "{ foo: bar }"
bracketSpacing: true,
// 在jsx中把'>' 是否单独放一行
jsxBracketSameLine: false,
// 缩进不使用tab使用空格
useTabs: false,
// 不让prettier使用eslint的代码格式进行校验
eslintIntegration: true,
overrides: [
{
files: '.prettierrc',
options: {
parser: 'json'
}
}
],
endOfLine: 'auto'
}

View File

@@ -0,0 +1,7 @@
[defaults]
url = https://sentry.1024lab.net/
org = 1024lab-sentry
project = smart-admin-h5
[auth]
token = 8dflijsldjkasdo3u49230948pkjdasoia8023jl3k4jr29o81029i40534p545ke

4
smart-admin-h5/README.md Normal file
View File

@@ -0,0 +1,4 @@
# SmartAdmin-H5
#### 介绍
SmartAdmin-H5 是SmartAdmin 平台的移动端web项目

View File

@@ -0,0 +1,16 @@
module.exports = {
presets: [['@vue/cli-plugin-babel/preset', {useBuiltIns: 'usage', corejs: 3}]],
plugins:[
// vant-ui 按需引入详情https://github.com/ElementUI/babel-plugin-component
// [
// 'import',
// {
// libraryName: 'vant',
// libraryDirectory: 'es',
// style: true
// },
// 'vant'
// ]
]
};

View File

@@ -0,0 +1,58 @@
{
"name": "smart-admin-h5",
"version": "1.0.0",
"description": "基于vue和vant的h5模板",
"author": "zhuoluodada@qq.com",
"private": true,
"scripts": {
"local": "vue-cli-service serve --open --mode local",
"dev": "vue-cli-service serve --open",
"build": "vue-cli-service build",
"build:sit": "vue-cli-service build --mode sit",
"build:pre": "vue-cli-service build --mode pre",
"build:prod": "vue-cli-service build --mode prod",
"stage": "vue-cli-service build --mode staging",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@sentry/browser": "^5.13.2",
"@sentry/integrations": "^5.13.2",
"axios": "^0.19.2",
"core-js": "^3.6.5",
"fastclick": "^1.0.6",
"js-cookie": "^2.2.1",
"lib-flexible": "^0.3.2",
"lodash": "^4.17.20",
"moment": "^2.29.0",
"nprogress": "^0.2.0",
"regenerator-runtime": "^0.13.5",
"vant": "^2.11.1",
"vue": "^2.6.12",
"vue-enum": "^1.0.5",
"vue-loading-overlay": "^3.4.2",
"vue-router": "^3.4.0",
"vuex": "^3.6.0"
},
"devDependencies": {
"@sentry/webpack-plugin": "^1.11.1",
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.0",
"babel-plugin-transform-remove-console": "^6.9.4",
"compression-webpack-plugin": "^3.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "^4.14.1",
"postcss-pxtorem": "^5.1.1",
"sass": "^1.3.0",
"sass-loader": "^9.0.3",
"script-ext-html-webpack-plugin": "^2.1.5",
"uglifyjs-webpack-plugin": "^2.2.0",
"vue-template-compiler": "^2.6.12",
"webpack-bundle-analyzer": "^4.2.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html
env="<%= VUE_APP_ENV %>"
version="<%= require('../package.json').version %>"
updated="<%= require('moment')().format('YYYY-MM-DD HH:mm:ss') %>"
>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<!--- cdn begin --->
<% if (process.env.NODE_ENV === 'production') { %>
<% for(var css of htmlWebpackPlugin.options.cdn.css) { %>
<link href="<%=css%>" rel="preload" as="style" />
<link rel="stylesheet" href="<%=css%>" as="style" />
<% } %> <% for(var js of htmlWebpackPlugin.options.cdn.js) { %>
<link href="<%=js%>" rel="preload" as="script" />
<script src="<%=js%>"></script>
<% } %> <% } %>
<!--- cdn end --->
<!--- vconsole begin --->
<% if (process.env.NODE_ENV === 'development') { %>
<script src="https://cdn.bootcss.com/vConsole/3.3.4/vconsole.min.js"></script>
<% } %>
<!--- vconsole end --->
<script type="text/javascript" src="https://3gimg.qq.com/lightmap/components/geolocation/geolocation.min.js"></script>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<!--- 无脚本提示 --->
<noscript>
<strong>
很抱歉,<%= htmlWebpackPlugin.options.title %> 在没有启用JavaScript的情况下无法正常工作请联系技术人员稍后重试
</strong>
</noscript>
<div id="app"></div>
</body>
</html>

View File

@@ -0,0 +1,16 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
};
</script>
<style lang="scss">
#nprogress .bar {
background: #1989fa !important;
}
</style>

View File

@@ -0,0 +1,43 @@
import { postAxios, getAxios } from '@/lib/http';
export const employeeApi = {
// 员工管理查询
getEmployeeList: (data) => {
return postAxios('admin/employee/query', data);
},
// 添加员工
addEmployee: (data) => {
return postAxios('admin/employee/add', data);
},
// 更新员工信息
updateEmployee: (data) => {
return postAxios('admin/employee/update', data);
},
// 禁用启用单个员工
updateStatus: (employeeId, status) => {
return getAxios('admin/employee/updateStatus/' + employeeId + '/' + status);
},
// 批量禁用
updateStatusBatch: (data) => {
return postAxios('admin/employee/batchUpdateStatus', data);
},
// 单个员工角色授权
updateRoles: (data) => {
return postAxios('admin/employee/updateRoles', data);
},
// 修改密码
updatePwd: (data) => {
return postAxios('admin/employee/updatePwd', data);
},
// 重置密码
resetPassword: (employeeId) => {
return getAxios('admin/employee/resetPasswd/' + employeeId);
},
// 通过部门id获取当前部门的人员&没有部门的人
getListEmployeeByDeptId: (departmentId) => {
return getAxios('admin/employee/listEmployeeByDeptId/' + departmentId);
},
// 删除员工
deleteEmployee: (employeeId) => {
return postAxios('admin/employee/delete/' + employeeId);
}
};

View File

@@ -0,0 +1,14 @@
import { postAxios, getAxios } from '@/lib/http';
import config from '@/config';
import Cookies from '@/lib/cookie';
const baseUrl = config.baseUrl.apiUrl;
export const fileApi = {
// 文件上传
fileUpload: (folder, data) => {
const url = baseUrl + '/common/file/upload/' + folder + '?x-access-token=' + Cookies.getToken();
return postAxios(url, data, {
headers: { 'Content-Type': 'multipart/form-data' }
});
}
};

View File

@@ -0,0 +1,10 @@
import { getAxios, postAxios } from '@/lib/http';
export const loginApi = {
login: (data) => {
return postAxios('/session/login', data);
},
logout: (token) => {
return getAxios(`/session/logOut?x-access-token=${token}`);
}
};

View File

@@ -0,0 +1,31 @@
// 系统参数API
import {
postAxios,
getAxios
} from '@/lib/http';
export const systemConfigApi = {
// 查询系统参数列表
getSystemConfigList: (data) => {
return postAxios('/admin/systemConfig/getListPage', data);
},
// 添加系统参数
addSystemConfig: (data) => {
return postAxios('/admin/systemConfig/add', data);
},
// 更新单条系统参数
updateSystemConfig: (data) => {
return postAxios('/admin/systemConfig/update', data);
},
// 通过key获取对应的信息
getConfigListByKey: (key) => {
return getAxios(`/admin/systemConfig/selectByKey?configKey=${key}`);
},
// 根据分组查询所有系统配置
getListByGroup: (group) => {
return getAxios(`/admin/systemConfig/getListByGroup?group=${group}`);
},
// 获取系统版本信息
getCodeVersion: () => {
return getAxios('/admin/codeVersion');
}
};

View File

@@ -0,0 +1,7 @@
import { getAxios } from '@/lib/http';
export const userApi = {
getSession: () => {
return getAxios('/session/get');
}
};

View File

@@ -0,0 +1,5 @@
$text-color: #323233;
$border-color: #ebedf0;
$active-color: #f2f3f5;
$background-color: #f7f8fa;
$background-color-light: #fafafa;

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,121 @@
/**
* @descriptiondepartment-employee-selector
* @author: zhuoda
* @date: 2020/10/30 13:56
*/
<template>
<div style="padding: 20px">
<template v-if="isRadio">
<van-radio-group v-model="radioSelectEmployeeId">
<van-radio
v-for="item in employeeList"
:key="item.id"
:name="item.id"
style="margin-top: 5px"
@click="clickRadio"
>
{{
item.actualName
}}
</van-radio>
</van-radio-group>
</template>
<template v-if="!isRadio">
<van-checkbox-group ref="checkboxGroup" :max="max" v-model="selectEmployeeList">
<van-checkbox
:key="item.id"
:name="item.id"
v-model="item._checked"
v-for="item in employeeList"
style="margin-top: 5px">
{{
item.actualName
}}
</van-checkbox>
</van-checkbox-group>
</template>
<br>
<van-button v-if="!isRadio" type="primary" size="small" @click="checkAll" style="margin:0 10px">全选</van-button>
<van-button v-if="!isRadio" type="info" size="small" @click="toggleAll">反选</van-button>
</div>
</template>
<script>
import { systemConfigApi } from '@/api/system-config';
import { employeeApi } from 'api/employee';
export default {
name: 'DepartmentEmployeeSelector',
props: {
// 最大数
max: Number,
isRadio: Boolean
},
data() {
return {
selectEmployeeList: [],
employeeList: [],
radioSelectEmployeeId: null,
radioSelectEmployeeName: null
};
},
created() {
this.loadEmployeeList();
},
methods: {
updateRadioSelectEmployeeId(employeeId) {
this.radioSelectEmployeeId = employeeId;
},
clickRadio(e, val) {
this.radioSelectEmployeeName = e.target.innerText;
},
getSelected() {
if (this.isRadio) {
return [{
id: this.radioSelectEmployeeId,
actualName: this.radioSelectEmployeeName
}];
} else {
const result = [];
for (const employee of this.employeeList) {
if (this.selectEmployeeList.indexOf(employee.id) > -1) {
result.push(Object.assign({}, employee));
}
}
return result;
}
},
async loadEmployeeList() {
this.$smart.loading();
try {
const departmentIdResult = await systemConfigApi.getConfigListByKey('crm_school_share_department_id');
const employeeListResult = await employeeApi.getListEmployeeByDeptId(departmentIdResult.data.configValue);
this.employeeList = employeeListResult.data.filter(e => e.isDelete === 0 && e.isDisabled === 0).map(e => {
e._checked = false;
return e;
});
} catch (e) {
this.$smartSentry.captureException(e);
} finally {
this.$smart.loadingClear();
}
},
checkAll() {
this.$refs.checkboxGroup.toggleAll(true);
},
toggleAll() {
this.$refs.checkboxGroup.toggleAll();
}
}
};
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,61 @@
<template>
<div>
<van-field
v-model="result"
v-bind="$attrs"
readonly
is-link
@click="show = !show"
/>
<van-popup v-model="show" position="bottom">
<van-picker
value-key="desc"
:columns="columns"
show-toolbar
:title="$attrs.label"
@cancel="show = !show"
@confirm="onConfirm"
/>
</van-popup>
</div>
</template>
<script>
export default {
name: 'SmartEnumSelectPicker',
model: {
prop: 'selectValue'
},
props: {
enumName: {
type: String
},
selectValue: {
type: String
}
},
data() {
return {
show: false,
result: this.selectValue,
columns: this.$enum.getValueDescList(this.enumName)
};
},
methods: {
onConfirm(value) {
this.result = value.desc;
this.show = !this.show;
this.$emit('change', value);
}
},
watch: {
selectValue: function(newVal) {
this.result = newVal;
},
result(newVal) {
this.$emit('input', newVal);
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,59 @@
<template>
<div>
<van-field
v-model="result"
v-bind="$attrs"
readonly
is-link
@click="show = !show"
/>
<van-popup v-model="show" position="bottom">
<van-picker
value-key="value"
:columns="columns"
show-toolbar
:title="$attrs.label"
@cancel="show = !show"
@confirm="onConfirm"
/>
</van-popup>
</div>
</template>
<script>
export default {
model: {
prop: 'selectValue'
},
props: {
columns: {
type: Array
},
selectValue: {
type: String
}
},
data() {
return {
show: false,
result: this.selectValue
};
},
methods: {
onConfirm(value) {
this.result = value;
this.show = !this.show;
}
},
watch: {
selectValue: function(newVal) {
this.result = newVal;
},
result(newVal) {
this.$emit('input', newVal);
}
}
};
</script>
<style></style>

View File

@@ -0,0 +1,25 @@
import cookie from '@/lib/cookie';
import { userApi } from 'api/user';
/**
* 此 mixin为登录以后的页面用的因为所有的有效路由排除登录、注册、404,500 这个几个特殊页面)都会走 App.vue里的router
* @author zhuoda
*/
export default {
created: function() {
const token = cookie.getToken();
// 如果登录过获取token
if (token && !this.$store.state.user.isHaveGotSessionInfo) {
(async() => {
try {
console.debug(' request session info ');
const res = await userApi.getSession();
const loginInfo = res.data;
this.$store.commit('user/updateSession', loginInfo);
} catch (e) {
this.$smartSentry.captureException(e);
}
})();
}
}
};

View File

@@ -0,0 +1,24 @@
<template>
<van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft" />
</template>
<script>
export default {
name: 'BackNavBar',
props: {
title: {
type: String
}
},
data() {
return {};
},
methods: {
onClickLeft() {
this.$router.go(-1);
}
}
};
</script>

View File

@@ -0,0 +1,27 @@
<template>
<van-nav-bar :title="title" left-text="返回" left-arrow @click-left="onClickLeft" />
</template>
<script>
export default {
name: 'RouterNavBar',
props: {
title: {
type: String
},
path: {
type: String
}
},
data() {
return {};
},
methods: {
onClickLeft() {
this.$router.push(this.path);
}
}
};
</script>

View File

@@ -0,0 +1,46 @@
console.log('project api url : ', process.env.VUE_APP_URL);
const isProductionEnv = ['production'].includes(process.env.NODE_ENV);
module.exports = {
// 配置显示在浏览器标签的title
title: 'Smart-Admin-H5',
// token在Cookie中存储的天数默认7天
cookieExpires: 7,
/**
* @description api请求基础路径
*/
baseUrl: {
apiUrl: process.env.VUE_APP_URL,
erpApiUrl: process.env.VUE_APP_ERP_URL,
webSocketUrl: process.env.VUE_APP_SOCKET_URL
},
/**
* 打包后静态资源地址;如果是走cdn的话可以配置如下
* publicPath: isProd ? 'https://cdn.1024lab.net/static/smart-h5/' : '/'
*/
publicPath: isProductionEnv ? '/manage-h5/' : '/',
// ==================== cdn 相关 begin ====================
cdn: {
cdnResource: {
css: [],
js: [
'https://cdn.bootcss.com/vue/2.6.11/vue.min.js',
'https://cdn.bootcss.com/vue-router/3.2.0/vue-router.min.js',
'https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js',
'https://cdn.bootcss.com/axios/0.19.2/axios.min.js',
'https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.min.js'
]
},
// 指定资源加载cdn
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
axios: 'axios',
lodash: '_'
}
}
// ==================== cdn 相关 end ====================
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,165 @@
/**
* 往来单位性质
* @type {{ENTERPRISE: {value: number, desc: string}, PERSONAL: {value: number, desc: string}}}
*/
export const CONTACT_COMPANY_NATURE_ENUM =
{
ENTERPRISE: {
value: 0,
desc: '企业'
},
PERSONAL: {
value: 1,
desc: '个人'
}
};
/**
* 往来机构类型
* @type {{CUSTOMER: {value: number, desc: string}, SUPPLIER: {value: number, desc: string}}}
*/
export const
CONTACT_COMPANY_TYPE_ENUM =
{
CUSTOMER: {
value: 0,
desc: '客户'
},
SUPPLIER: {
value: 1,
desc: '供应商'
},
SCHOOL: {
value: 2,
desc: '分校'
},
COOPERATIVE_ORG: {
value: 3,
desc: '合作机构'
}
};
/**
* 付款方式
* @type {{BANK: {value: number, desc: string}, ZHI_FU_BAO: {value: number, desc: string}, WE_CHAT: {value: number, desc: string}}}
*/
export const
PAYMENT_TYPE_ENUM =
{
BANK: {
value: 0,
desc: '银行卡'
},
WE_CHAT: {
value: 1,
desc: '微信'
},
ZHI_FU_BAO: {
value: 2,
desc: '支付宝'
}
};
/**
* 往来机构余额类型
* @type {{RECEIVE_BALANCE: {value: number, desc: string}, PAY_BALANCE: {value: number, desc: string}}}
*/
export const
CONTACT_COMPANY_BALANCE_TYPE =
{
PAY_BALANCE: {
value: 0,
desc: '应付款余额'
},
RECEIVE_BALANCE: {
value: 1,
desc: '应收款余额'
}
};
/**
* 往来单位等级
* @type {{CORE: {value: number, desc: string}, POTENTIAL: {value: number, desc: string}, BAD: {value: number, desc: string}, GENERAL: {value: number, desc: string}}}
*/
export const CONTACT_COMPANY_GRADE_ENUM = {
CORE: {
value: 1,
desc: '核心',
color: 'green'
},
POTENTIAL: {
value: 2,
desc: '有潜力',
color: 'cyan'
},
GENERAL: {
value: 3,
desc: '普通',
color: 'blue'
},
BAD: {
value: 4,
desc: '较差',
color: 'purple'
}
};
/**
* 往来单位等级
* @type {{OWNER: {value: number, desc: string}, SHARER: {value: number, desc: string}, COMMON: {value: number, desc: string}}}
*/
export const CONTACT_COMPANY_SHARE_TYPE_ENUM = {
OWNER: {
value: 0,
desc: '属于我的'
},
SHARER: {
value: 1,
desc: '共享的'
},
COMMON: {
value: 2,
desc: '公共的'
}
};
/**
* 往来单位标签
* @type {{OWNER: {value: number, desc: string}, SHARER: {value: number, desc: string}, COMMON: {value: number, desc: string}}}
*/
export const CONTACT_COMPANY_TAG_ENUM = {
POTENTIAL: {
value: 0,
desc: '潜在',
color: 'green'
},
INTENTION: {
value: 1,
desc: '意向',
color: 'cyan'
},
NEGOTIATION: {
value: 2,
desc: '洽谈',
color: 'blue'
},
DEAL: {
value: 3,
desc: '成交',
color: 'geekblue'
},
LOSS: {
value: 4,
desc: '流失',
color: 'red'
}
};
export default {
CONTACT_COMPANY_NATURE_ENUM,
CONTACT_COMPANY_TYPE_ENUM,
PAYMENT_TYPE_ENUM,
CONTACT_COMPANY_BALANCE_TYPE,
CONTACT_COMPANY_GRADE_ENUM,
CONTACT_COMPANY_SHARE_TYPE_ENUM,
CONTACT_COMPANY_TAG_ENUM
};

View File

@@ -0,0 +1,6 @@
import contactCompany from './contact-company';
export default {
...contactCompany
};

View File

@@ -0,0 +1,92 @@
export const COMMON_FILE_FOLDER_TYPE_ENUM = {
DISPLAY_PIC: {
value: 1,
desc: '轮播展示图'
},
RESOURCE_LECTURER: {
value: 2,
desc: '资源-讲师图片'
},
RESOURCE_FILE: {
value: 3,
desc: '资源-文件资源'
},
USER_AVATAR: {
value: 4,
desc: '用户头像'
},
STOCK_BASIC: {
value: 5,
desc: '货物基本信息图片'
},
PUBLICATION_QR_CODE: {
value: 6,
desc: '出版物二维码图片'
},
RESOURCE_PAGE_QR_CODE: {
value: 7,
desc: '资源页面链接二维码图片'
},
FINANCE_RECEIVE_QR_CODE: {
value: 8,
desc: '财务收款二维码'
},
FINANCE_WX_PAY_CERT: {
value: 9,
desc: '财务-微信支付证书'
},
GOODS: {
value: 10,
desc: '商品图片-公用文件夹'
},
EXCEL_EXPORT: {
value: 11,
desc: 'excel导出-私有文件夹'
},
FINANCE_WAIT_PAYMENT_PAYMENT_PROOF: {
value: 12,
desc: '财务待支付支付凭证'
},
FEEDBACK: {
value: 99,
desc: '用户反馈图片'
},
EDITOR: {
value: 100,
desc: '文本编辑器'
},
EDITOR_IMG: {
value: 100,
desc: '文本编辑器'
},
INTERNAL_INFORMATION: {
value: 14,
desc: '内部资料'
},
CRM_USER: {
value: 111,
desc: 'CRM学员跟进附件'
},
CRM_SCHOOL: {
value: 112,
desc: 'CRM分校跟进附件'
},
// = =======erp 相关 begin============
ERP_STOCK_IMG: {
value: 201,
desc: '货物图片'
},
ERP_CONTACT_COMPANY_RECEIVE_IMAGE: {
value: 210,
desc: '往来单位收款二维码'
},
ERP_CONTACT_COMPANY_ATTACHMENT: {
value: 211,
desc: '往来单位附件'
}
// = =======erp 相关 end ============
};
export default {
COMMON_FILE_FOLDER_TYPE_ENUM
};

View File

@@ -0,0 +1,7 @@
import school from '@/constants/school';
import erp from './erp';
export default {
...school,
...erp
};

View File

@@ -0,0 +1,71 @@
/**
* 分校标签
*/
export const SCHOOL_TAG_ENUM = {
POTENTIAL: {
value: 0,
desc: '潜在'
},
INTENTION: {
value: 1,
desc: '意向'
},
NEGOTIATION: {
value: 2,
desc: '洽谈'
},
DEAL: {
value: 3,
desc: '成交'
},
LOSS: {
value: 4,
desc: '流失'
}
};
/**
* 分校等级
*/
export const SCHOOL_GRADE_ENUM = {
CORE: {
value: 1,
desc: '核心'
},
POTENTIAL: {
value: 2,
desc: '有潜力'
},
GENERAL: {
value: 3,
desc: '普通'
},
BAD: {
value: 4,
desc: '较差'
}
};
/**
* 共享类型
*/
export const SCHOOL_SHARE_TYPE_ENUM = {
OWNER: {
value: 0,
desc: '属于我的'
},
SHARER: {
value: 1,
desc: '共享的'
},
COMMON: {
value: 2,
desc: '公共的'
}
};
export default {
SCHOOL_TAG_ENUM,
SCHOOL_GRADE_ENUM,
SCHOOL_SHARE_TYPE_ENUM
};

View File

@@ -0,0 +1,298 @@
import Vue from 'vue';
function ellipsis(value, length) {
if (!value) return '';
if (value.length > length) {
return value.slice(0, length) + '...';
}
return value;
}
/**
* 去除空格 type 1-所有空格 2-前后空格 3-前空格 4-后空格
*/
function trim(value, trim) {
switch (trim) {
case 1:
return value.replace(/\s+/g, '');
case 2:
return value.replace(/(^\s*)|(\s*$)/g, '');
case 3:
return value.replace(/(^\s*)/g, '');
case 4:
return value.replace(/(\s*$)/g, '');
default:
return value;
}
}
/**
* 任意格式日期处理
使用格式:
{{ '2018-09-14 01:05' | formatDate(yyyy-MM-dd hh:mm:ss) }}
{{ '2018-09-14 01:05' | formatDate(yyyy-MM-dd) }}
{{ '2018-09-14 01:05' | formatDate(MM/dd) }} 等
* @param value
* @param fmt
* @returns {*}
*/
function formatDate(value, fmt) {
var date = new Date(value);
var o = {
'M+': date.getMonth() + 1, // 月份
'd+': date.getDate(), // 日
'h+': date.getHours(), // 小时
'm+': date.getMinutes(), // 分
's+': date.getSeconds(), // 秒
'w+': date.getDay(), // 星期
'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
'S': date.getMilliseconds() // 毫秒
};
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
for (var k in o) {
if (k === 'w+') {
if (o[k] === 0) {
fmt = fmt.replace('w', '周日');
} else if (o[k] === 1) {
fmt = fmt.replace('w', '周一');
} else if (o[k] === 2) {
fmt = fmt.replace('w', '周二');
} else if (o[k] === 3) {
fmt = fmt.replace('w', '周三');
} else if (o[k] === 4) {
fmt = fmt.replace('w', '周四');
} else if (o[k] === 5) {
fmt = fmt.replace('w', '周五');
} else if (o[k] === 6) {
fmt = fmt.replace('w', '周六');
}
} else if (new RegExp('(' + k + ')').test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
}
}
return fmt;
}
/**
* 字母大小写切换
type
1:首字母大写
2首页母小写
3大小写转换
4全部大写
5全部小写
* @param str
* @param type
* @returns {string|*}
*/
function changeCase(str, type) {
function ToggleCase(str) {
var itemText = '';
str.split('').forEach(
function(item) {
if (/^([a-z]+)/.test(item)) {
itemText += item.toUpperCase();
} else if (/^([A-Z]+)/.test(item)) {
itemText += item.toLowerCase();
} else {
itemText += item;
}
});
return itemText;
}
switch (type) {
case 1:
return str.replace(/\b\w+\b/g, function(word) {
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
});
case 2:
return str.replace(/\b\w+\b/g, function(word) {
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
});
case 3:
return ToggleCase(str);
case 4:
return str.toUpperCase();
case 5:
return str.toLowerCase();
default:
return str;
}
}
/**
* 字符串循环复制,count->次数
*/
function repeatStr(str, count) {
var text = '';
for (var i = 0; i < count; i++) {
text += str;
}
return text;
}
/**
* 字符串替换
*/
function replaceAll(str, AFindText, ARepText) {
const raRegExp = new RegExp(AFindText, 'g');
return str.replace(raRegExp, ARepText);
}
/**
*
* 字符替换*,隐藏手机号或者身份证号等
replaceStr(字符串,字符格式, 替换方式,替换的字符(默认*)
ecDo.replaceStr('18819322663',[3,5,3],0)
result188*****663
ecDo.replaceStr('asdasdasdaa',[3,5,3],1)
result***asdas***
ecDo.replaceStr('1asd88465asdwqe3',[5],0)
result*****8465asdwqe3
ecDo.replaceStr('1asd88465asdwqe3',[5],1,'+')
result"1asd88465as+++++"
*
* @param str
* @param regArr
* @param type
* @param ARepText
* @returns {*}
*/
function replaceStr(str, regArr, type, ARepText) {
var regtext = '';
var Reg = null;
var replaceText = ARepText || '*';
// repeatStr是在上面定义过的字符串循环复制大家注意哦
if (regArr.length === 3 && type === 0) {
regtext = '(\\w{' + regArr[0] + '})\\w{' + regArr[1] + '}(\\w{' + regArr[2] + '})';
Reg = new RegExp(regtext);
var replaceCount = this.repeatStr(replaceText, regArr[1]);
return str.replace(Reg, '$1' + replaceCount + '$2');
} else if (regArr.length === 3 && type === 1) {
regtext = '\\w{' + regArr[0] + '}(\\w{' + regArr[1] + '})\\w{' + regArr[2] + '}';
Reg = new RegExp(regtext);
var replaceCount1 = this.repeatStr(replaceText, regArr[0]);
var replaceCount2 = this.repeatStr(replaceText, regArr[2]);
return str.replace(Reg, replaceCount1 + '$1' + replaceCount2);
} else if (regArr.length === 1 && type === 0) {
regtext = '(^\\w{' + regArr[0] + '})';
Reg = new RegExp(regtext);
var replaceCount = this.repeatStr(replaceText, regArr[0]);
return str.replace(Reg, replaceCount);
} else if (regArr.length === 1 && type === 1) {
regtext = '(\\w{' + regArr[0] + '}$)';
Reg = new RegExp(regtext);
var replaceCount = this.repeatStr(replaceText, regArr[0]);
return str.replace(Reg, replaceCount);
}
}
/**
* 格式化处理字符串
ecDo.formatText('1234asda567asd890')
result"12,34a,sda,567,asd,890"
ecDo.formatText('1234asda567asd890',4,' ')
result"1 234a sda5 67as d890"
ecDo.formatText('1234asda567asd890',4,'-')
result"1-234a-sda5-67as-d890"
* @param str
* @param size
* @param delimiter
* @returns {*}
*/
function formatText(str, size, delimiter) {
var _size = size || 3;
var _delimiter = delimiter || ',';
var regText = '\\B(?=(\\w{' + _size + '})+(?!\\w))';
var reg = new RegExp(regText, 'g');
return str.replace(reg, _delimiter);
}
/**
* 现金额大写转换函数
ecDo.upDigit(168752632)
result"人民币壹亿陆仟捌佰柒拾伍万贰仟陆佰叁拾贰元整"
ecDo.upDigit(1682)
result"人民币壹仟陆佰捌拾贰元整"
ecDo.upDigit(-1693)
result"欠人民币壹仟陆佰玖拾叁元整"
* @param n
* @returns {string}
*/
function upDigit(n) {
var fraction = ['角', '分', '厘'];
var digit = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
var unit = [
['元', '万', '亿'],
['', '拾', '佰', '仟']
];
var head = n < 0 ? '欠人民币' : '人民币';
n = Math.abs(n);
var s = '';
for (var i = 0; i < fraction.length; i++) {
s += (digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');
}
s = s || '整';
n = Math.floor(n);
for (var i = 0; i < unit[0].length && n > 0; i++) {
var p = '';
for (var j = 0; j < unit[1].length && n > 0; j++) {
p = digit[n % 10] + unit[1][j] + p;
n = Math.floor(n / 10);
}
s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;
// s = p + unit[0][i] + s;
}
return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');
}
// 保留2位小数
function toFixed(val, acc) {
let num = parseFloat(val);
if (isNaN(num)) {
num = 0;
}
let accuracy = parseInt(acc);
if (isNaN(accuracy) || accuracy < 0 || accuracy > 10) {
accuracy = 2;
}
return num.toFixed(accuracy);
}
// 转百分比
function toPercent(val, acc) {
let num = parseFloat(val);
if (isNaN(num)) {
num = 0;
}
let accuracy = parseInt(acc);
if (isNaN(accuracy) || accuracy < 0 || accuracy > 10) {
accuracy = 2;
}
return (num * 100).toFixed(accuracy) + '%';
}
// ------------ enum begin ------------
function getEnumDescByValue(value, enumName) {
return Vue.prototype.$enum.getDescByValue(enumName, value);
}
// ------------ enum end ------------
export {
trim,
changeCase,
repeatStr,
replaceAll,
replaceStr,
formatText,
upDigit,
toFixed,
formatDate,
toPercent,
getEnumDescByValue,
ellipsis
};

View File

@@ -0,0 +1,5 @@
import Vue from 'vue'
import * as filter from './filter'
Object.keys(filter).forEach(key => Vue.filter(key, filter[key]))

View File

@@ -0,0 +1,21 @@
import Cookies from 'js-cookie';
import config from '@/config';
const { cookieExpires } = config;
export const TOKEN_KEY = 'token';
export default {
setToken: token => {
Cookies.set(TOKEN_KEY, token, {
// token在Cookie中存储的天数默认1天
expires: cookieExpires || 7
});
},
getToken: () => {
const token = Cookies.get(TOKEN_KEY);
if (token) return token;
else return null;
},
clearToken: () => {
Cookies.remove(TOKEN_KEY);
}
};

View File

@@ -0,0 +1,65 @@
import Axios from 'axios';
import config from '@/config';
import cookie from '@/lib/cookie';
import { Toast } from 'vant';
export const baseUrl = config.baseUrl.erpApiUrl;
const axios = Axios.create({
baseURL: baseUrl,
timeout: 30000,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
});
// 添加请求拦截器
axios.interceptors.request.use(
function(config) {
const token = cookie.getToken();
if (token) {
config.headers['x-access-token'] = token;
}
return config;
},
function(error) {
return Promise.reject(error);
}
);
// 添加响应拦截器
axios.interceptors.response.use(
res => {
const { data } = res;
if (data && data.code && data.code !== 1) {
if (data.code === 121) {
cookie.clearToken();
localStorage.clear();
window.location.href = window.location.pathname + '#/login';
Toast.fail('未登录,或登录失效,请登录');
return;
} else if (data.code === 502) {
window.location.href = window.location.pathname + '#/500';
return;
} else {
Toast.fail(data.msg);
return Promise.reject(res);
}
}
return Promise.resolve(data);
},
error => {
Toast.fail('服务内部错误');
return Promise.reject(error);
}
);
export const postAxios = (url, data, config) => {
return axios.post(url, data, config);
};
export const getAxios = (url, data) => {
return axios.get(url, {
params: data
});
};

View File

@@ -0,0 +1,65 @@
import Axios from 'axios';
import config from '@/config';
import cookie from '@/lib/cookie';
import { Toast } from 'vant';
export const baseUrl = config.baseUrl.apiUrl;
const axios = Axios.create({
baseURL: baseUrl,
timeout: 30000,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
});
// 添加请求拦截器
axios.interceptors.request.use(
function(config) {
const token = cookie.getToken();
if (token) {
config.headers['x-access-token'] = token;
}
return config;
},
function(error) {
return Promise.reject(error);
}
);
// 添加响应拦截器
axios.interceptors.response.use(
res => {
const { data } = res;
if (data && data.code && data.code !== 1) {
if (data.code === 1001) {
cookie.clearToken();
localStorage.clear();
window.location.href = window.location.pathname + '#/login';
Toast.fail('未登录,或登录失效,请登录');
return;
} else if (data.code === 502) {
window.location.href = window.location.pathname + '#/500';
return;
} else {
Toast.fail(data.msg);
return Promise.reject(res);
}
}
return Promise.resolve(data);
},
error => {
Toast.fail('服务内部错误');
return Promise.reject(error);
}
);
export const postAxios = (url, data, config) => {
return axios.post(url, data, config);
};
export const getAxios = (url, data) => {
return axios.get(url, {
params: data
});
};

View File

@@ -0,0 +1,8 @@
export const localSave = (key, value) => {
localStorage.setItem(key, value);
};
export const localRead = key => {
return localStorage.getItem(key) || '';
};

View File

@@ -0,0 +1,276 @@
import { forEach, hasOneOf, objEqual } from '@/lib/util';
import config from '@/config';
import { localRead, localSave } from '@/lib/local';
const { title, useI18n } = config;
export const hasChild = item => {
return item.children && item.children.length !== 0;
};
/**
* 通过权限过滤菜单
* @param {Object} map 权限对象
* @param {Array} menuList 菜单列表
* @returns {Array}
*/
export const getShowMenu = (map = {}, menuList, access = false) => {
// 判断是否为超级管理员
if (access) {
return menuList;
}
// 返回的菜单列表
let result = [];
for (let menuItem of menuList) {
let routerObj = JSON.parse(JSON.stringify(menuItem));
if (
map.hasOwnProperty(menuItem.name) &&
(menuItem.name !== 'home' && menuItem.name !== '_home')
) {
// 判断该菜单权限下是否为数组,若为数组,则为功能点权限否则为子菜单
if (getType(map[routerObj.name]) === 'array') {
let funcPrivilege = localRead('funcPrivilegeInfo')
? JSON.parse(localRead('funcPrivilegeInfo'))
: {};
localSave(
'funcPrivilegeInfo',
JSON.stringify({
...funcPrivilege,
[routerObj.name]: map[routerObj.name]
})
);
} else if (
getType(map[routerObj.name]) !== 'array' &&
!routerObj.children
) {
// 判断是否为二级菜单,若是则需要多枚举一层赋值
let funcPrivilege = localRead('funcPrivilegeInfo')
? JSON.parse(localRead('funcPrivilegeInfo'))
: {};
localSave(
'funcPrivilegeInfo',
JSON.stringify({
...funcPrivilege,
[routerObj.name]: map[routerObj.name][routerObj.name]
})
);
} else if (
getType(map[routerObj.name]) !== 'array' &&
routerObj.children
) {
// 循环子菜单权限
routerObj.children = getShowMenu(
map[routerObj.name],
routerObj.children
);
}
result.push(routerObj);
}
}
return result;
};
// 获取数据类型
export const getType = obj => {
return {}.toString
.call(obj)
.match(/\s([a-zA-Z]+)/)[1]
.toLowerCase();
};
/**
* @description 本地存储和获取标签导航列表
*/
export const setTagNavListInLocalStorage = list => {
localStorage.tagNaveList = JSON.stringify(list);
};
/**
* @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
*/
export const getTagNavListFromLocalStorage = () => {
const list = localStorage.tagNaveList;
return list ? JSON.parse(list) : [];
};
export const getBreadCrumbList = (route, homeRoute) => {
let homeItem = {
...homeRoute,
icon: homeRoute.meta.icon
};
let routeMatched = route.matched;
if (routeMatched.some(item => item.name === homeRoute.name)) {
return [homeItem];
}
let res = routeMatched
.filter(item => {
return item.meta === undefined || !item.meta.hideInBread;
})
.map(item => {
let meta = {
...item.meta
};
if (meta.title && typeof meta.title === 'function') {
meta.__titleIsFunction__ = true;
meta.title = meta.title(route);
}
let obj = {
icon: (item.meta && item.meta.icon) || '',
name: item.name,
meta: meta
};
return obj;
});
res = res.filter(item => {
return !item.meta.hideInMenu;
});
return [...res];
};
/**
* @param {Array} routers 路由列表数组
* @description 用于找到路由列表中name为home的对象
*/
export const getHomeRoute = (routers, homeName = 'Home') => {
let i = -1;
let len = routers.length;
let homeRoute = {};
while (++i < len) {
let item = routers[i];
if (item.children && item.children.length) {
let res = getHomeRoute(item.children, homeName);
if (res.name) return res;
} else {
if (item.name === homeName) homeRoute = item;
}
}
return homeRoute;
};
/**
* @param {Array} list 标签列表
* @param {String} name 当前关闭的标签的name
*/
export const getNextRoute = (list, route) => {
let res = {};
if (list.length === 2) {
res = getHomeRoute(list);
} else {
const index = list.findIndex(item => routeEqual(item, route));
if (index === list.length - 1) res = list[list.length - 2];
else res = list[index + 1];
}
return res;
};
/**
* 判断打开的标签列表里是否已存在这个新添加的路由对象
*/
export const routeHasExist = (tagNavList, routeItem) => {
let len = tagNavList.length;
let res = false;
doCustomTimes(len, index => {
if (routeEqual(tagNavList[index], routeItem)) res = true;
});
return res;
};
/**
* @param {*} list 现有标签导航列表
* @param {*} newRoute 新添加的路由原信息对象
* @description 如果该newRoute已经存在则不再添加
*/
export const getNewTagList = (list, newRoute) => {
const { name, path, meta, query } = newRoute;
let newList = [...list];
let index = newList.findIndex(item => item.name === name);
if (index >= 0) {
newList[index] = { name, path, meta, query };
} else newList.push({ name, path, meta, query });
return newList;
};
export const routeEqual = (route1, route2) => {
return route1.name === route2.name;
};
export const getRouteTitleHandled = route => {
let router = {
...route
};
let meta = {
...route.meta
};
let title = '';
if (meta.title) {
if (typeof meta.title === 'function') {
meta.__titleIsFunction__ = true;
title = meta.title(router);
} else title = meta.title;
}
meta.title = title;
router.meta = meta;
return router;
};
/**
* @param {Number} times 回调函数需要执行的次数
* @param {Function} callback 回调函数
*/
export const doCustomTimes = (times, callback) => {
let i = -1;
while (++i < times) {
callback(i);
}
};
export const showTitle = (item, vm) => {
let { title, __titleIsFunction__ } = item.meta;
if (!title) return;
if (useI18n) {
if (title.includes('{{') && title.includes('}}') && useI18n) {
title = title.replace(/({{[\s\S]+?}})/, (m, str) =>
str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim()))
);
} else if (__titleIsFunction__) title = item.meta.title;
else title = vm.$t(item.name);
} else title = (item.meta && item.meta.title) || item.name;
return title;
};
/**
* @description 根据当前跳转的路由设置显示在浏览器标签的title
* @param {Object} routeItem 路由对象
* @param {Object} vm Vue实例
*/
export const setTitle = (routeItem, vm) => {
const handledRoute = getRouteTitleHandled(routeItem);
const pageTitle = showTitle(handledRoute, vm);
const resTitle = pageTitle ? `${pageTitle} - ${title}` : title;
window.document.title = resTitle;
};
export const findNodeUpper = (ele, tag) => {
if (ele.parentNode) {
if (ele.parentNode.tagName === tag.toUpperCase()) {
return ele.parentNode;
} else {
return findNodeUpper(ele.parentNode, tag);
}
}
};
export const findNodeUpperByClasses = (ele, classes) => {
let parentNode = ele.parentNode;
if (parentNode) {
let classList = parentNode.classList;
if (
classList &&
classes.every(className => classList.contains(className))
) {
return parentNode;
} else {
return findNodeUpperByClasses(parentNode, classes);
}
}
};
export const findNodeDownward = (ele, tag) => {
const tagName = tag.toUpperCase();
if (ele.childNodes.length) {
let i = -1;
let len = ele.childNodes.length;
while (++i < len) {
let child = ele.childNodes[i];
if (child.tagName === tagName) return child;
else return findNodeDownward(child, tag);
}
}
};

View File

@@ -0,0 +1,133 @@
// 打印类属性、方法定义
/* eslint-disable */
//第二个参数表明是否要关闭当前窗口
const Print = function(dom, close, options) {
if (!(this instanceof Print)) return new Print(dom, close, options);
this.options = this.extend(
{
noPrint: '.no-print'
},
options
);
if (typeof dom === 'string') {
this.dom = document.querySelector(dom);
} else {
this.dom = dom;
}
this.init(close);
};
Print.prototype = {
init: function(close) {
var content = this.getStyle() + this.getHtml();
this.writeIframe(content, close);
},
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>body, html{height: auto; overflow: auto !important;}' +
(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 in inputs) {
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);
}
}
for (var k2 in textareas) {
if (textareas[k2].type == 'textarea') {
textareas[k2].innerHTML = textareas[k2].value;
}
}
for (var k3 in selects) {
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, close) {
var w,
doc,
iframe = document.createElement('iframe'),
f = document.body.appendChild(iframe);
iframe.id = 'myIframe';
iframe.style = 'position:absolute;';
w = f.contentWindow || f.contentDocument;
doc = f.contentDocument || f.contentWindow.document;
doc.open();
doc.write(content);
doc.close();
this.toPrint(w, close);
setTimeout(function() {
document.body.removeChild(iframe);
}, 500);
},
toPrint: function(frameWindow, close) {
try {
setTimeout(function() {
frameWindow.focus();
try {
if (!frameWindow.document.execCommand('print', false, null)) {
frameWindow.print();
}
} catch (e) {
frameWindow.print();
}
frameWindow.close();
if (close) {
window.close();
}
}, 500);
} catch (err) {
console.log('err', err);
}
}
};
const MyPlugin = {};
MyPlugin.install = function(Vue, options) {
// 4. 添加实例方法
Vue.prototype.$print = Print;
};
export default MyPlugin;

View File

@@ -0,0 +1,10 @@
export default {
name: 'RenderDom',
functional: true,
props: {
render: Function
},
render: (h, ctx) => {
return ctx.props.render(h);
}
};

View File

@@ -0,0 +1,21 @@
/*
* @Description:
* @Author: hanyu
* @Date: 2020-05-28 12:46:06
* @LastEditTime: 2020-07-08 09:16:15
* @LastEditors: hy
*/
// smart sentry
import * as Sentry from '@sentry/browser';
export default {
/**
* sentry 主动上报
* @param {error} error 错误信息
*/
captureException: (error) => {
if (error.config && error.data && error && error.headers && error.request && error.status) {
return;
}
Sentry.captureException(error);
}
};

View File

@@ -0,0 +1,515 @@
import moment from 'moment';
/**
* @param {String} url
* @description 从URL中解析参数
*/
export const getParams = url => {
const keyValueArr = url.split('?')[1].split('&');
let paramObj = {};
keyValueArr.forEach(item => {
const keyValue = item.split('=');
paramObj[keyValue[0]] = keyValue[1];
});
return paramObj;
};
/**
* @param {Any} obj
* @description 获取数据类型
*/
export const getType = obj => {
return {}.toString
.call(obj)
.match(/\s([a-zA-Z]+)/)[1]
.toLowerCase();
};
// 日期格式
export const dateFormat = {
YMD: 'YMD',
YMDHM: 'YMDHM',
YMDHMS: 'YMDHMS'
};
export const forEach = (arr, fn) => {
if (!arr.length || !fn) return;
let i = -1;
let len = arr.length;
while (++i < len) {
let item = arr[i];
fn(item, i, arr);
}
};
/**
* @param {Array} arr1
* @param {Array} arr2
* @description 得到两个数组的交集, 两个数组的元素为数值或字符串
*/
export const getIntersection = (arr1, arr2) => {
let len = Math.min(arr1.length, arr2.length);
let i = -1;
let res = [];
while (++i < len) {
const item = arr2[i];
if (arr1.indexOf(item) > -1) res.push(item);
}
return res;
};
/**
* @param {Array} arr1
* @param {Array} arr2
* @description 得到两个数组的并集, 两个数组的元素为数值或字符串
*/
export const getUnion = (arr1, arr2) => {
return Array.from(new Set([...arr1, ...arr2]));
};
/**
* @param {Array} target 目标数组
* @param {Array} arr 需要查询的数组
* @description 判断要查询的数组是否至少有一个元素包含在目标数组中
*/
export const hasOneOf = (targetarr, arr) => {
return targetarr.some(_ => arr.indexOf(_) > -1);
};
/**
* @param {String|Number} value 要验证的字符串或数值
* @param {*} validList 用来验证的列表
*/
export function oneOf (value, validList) {
for (let i = 0; i < validList.length; i++) {
if (value === validList[i]) {
return true;
}
}
return false;
}
/**
* @param {Number} timeStamp 判断时间戳格式是否是毫秒
* @returns {Boolean}
*/
const isMillisecond = timeStamp => {
const timeStr = String(timeStamp);
return timeStr.length > 10;
};
/**
* @param {Number} timeStamp 传入的时间戳
* @param {Number} currentTime 当前时间时间戳
* @returns {Boolean} 传入的时间戳是否早于当前时间戳
*/
const isEarly = (timeStamp, currentTime) => {
return timeStamp < currentTime;
};
/**
* @param {Number} num 数值
* @returns {String} 处理后的字符串
* @description 如果传入的数值小于10即位数只有1位则在前面补充0
*/
const getHandledValue = num => {
return num < 10 ? '0' + num : num;
};
/**
* @param {Number} timeStamp 传入的时间戳
* @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间
*/
const getDate = (timeStamp, startType) => {
const d = new Date(timeStamp * 1000);
const year = d.getFullYear();
const month = getHandledValue(d.getMonth() + 1);
const date = getHandledValue(d.getDate());
const hours = getHandledValue(d.getHours());
const minutes = getHandledValue(d.getMinutes());
const second = getHandledValue(d.getSeconds());
let resStr = '';
if (startType === 'year') {
resStr =
year +
'-' +
month +
'-' +
date +
' ' +
hours +
':' +
minutes +
':' +
second;
}
else resStr = month + '-' + date + ' ' + hours + ':' + minutes;
return resStr;
};
/**
* @param {String|Number} timeStamp 时间戳
* @returns {String} 相对时间字符串
*/
export const getRelativeTime = timeStamp => {
// 判断当前传入的时间戳是秒格式还是毫秒
const IS_MILLISECOND = isMillisecond(timeStamp);
// 如果是毫秒格式则转为秒格式
if (IS_MILLISECOND) Math.floor((timeStamp /= 1000));
// 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
timeStamp = Number(timeStamp);
// 获取当前时间时间戳
const currentTime = Math.floor(Date.parse(new Date()) / 1000);
// 判断传入时间戳是否早于当前时间戳
const IS_EARLY = isEarly(timeStamp, currentTime);
// 获取两个时间戳差值
let diff = currentTime - timeStamp;
// 如果IS_EARLY为false则差值取反
if (!IS_EARLY) diff = -diff;
let resStr = '';
const dirStr = IS_EARLY ? '前' : '后';
// 少于等于59秒
if (diff <= 59) resStr = diff + '秒' + dirStr;
// 多于59秒少于等于59分钟59秒
else if (diff > 59 && diff <= 3599) { resStr = Math.floor(diff / 60) + '分钟' + dirStr; }
// 多于59分钟59秒少于等于23小时59分钟59秒
else if (diff > 3599 && diff <= 86399) { resStr = Math.floor(diff / 3600) + '小时' + dirStr; }
// 多于23小时59分钟59秒少于等于29天59分钟59秒
else if (diff > 86399 && diff <= 2623859) { resStr = Math.floor(diff / 86400) + '天' + dirStr; }
// 多于29天59分钟59秒少于364天23小时59分钟59秒且传入的时间戳早于当前
else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) { resStr = getDate(timeStamp); }
else resStr = getDate(timeStamp, 'year');
return resStr;
};
/**
* @returns {String} 当前浏览器名称
*/
export const getExplorer = () => {
const ua = window.navigator.userAgent;
const isExplorer = exp => {
return ua.indexOf(exp) > -1;
};
if (isExplorer('MSIE')) return 'IE';
else if (isExplorer('Firefox')) return 'Firefox';
else if (isExplorer('Chrome')) return 'Chrome';
else if (isExplorer('Opera')) return 'Opera';
else if (isExplorer('Safari')) return 'Safari';
};
/**
* @description 绑定事件 on(element, event, handler)
*/
export const on = (function () {
if (document.addEventListener) {
return function (element, event, handler) {
if (element && event && handler) {
element.addEventListener(event, handler, false);
}
};
} else {
return function (element, event, handler) {
if (element && event && handler) {
element.attachEvent('on' + event, handler);
}
};
}
})();
/**
* @description 解绑事件 off(element, event, handler)
*/
export const off = (function () {
if (document.removeEventListener) {
return function (element, event, handler) {
if (element && event) {
element.removeEventListener(event, handler, false);
}
};
} else {
return function (element, event, handler) {
if (element && event) {
element.detachEvent('on' + event, handler);
}
};
}
})();
/**
* 判断一个对象是否存在key如果传入第二个参数key则是判断这个obj对象是否存在key这个属性
* 如果没有传入key这个参数则判断obj对象是否有键值对
*/
export const hasKey = (obj, key) => {
if (key) return key in obj;
else {
let keysArr = Object.keys(obj);
return keysArr.length;
}
};
/**
* @param {*} obj1 对象
* @param {*} obj2 对象
* @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
*/
export const objEqual = (obj1, obj2) => {
const keysArr1 = Object.keys(obj1);
const keysArr2 = Object.keys(obj2);
if (keysArr1.length !== keysArr2.length) return false;
else if (keysArr1.length === 0 && keysArr2.length === 0) return true;
/* eslint-disable-next-line */ else { return !keysArr1.some(key => obj1[key] != obj2[key]); }
};
// 相关工具类
export const utils = {
/**
* @description table实现反选
* @param {Object} vm Vue实例
* @param {Array} tableSelectDate 选中的数据
* @param {Array} allData 所有数据
* @param {Array} key 数据中的唯一值
*/
reverseSelect (vm, tableSelectDate, allData, key) {
let copyMess = JSON.parse(JSON.stringify(tableSelectDate));
// 流程:先全部选中->再部分选中
vm.handleSelectAll(false);
// 选中的idList
let idList = copyMess.map(item => item[key]);
console.log(idList);
for (let item of allData) {
if (idList.every(id => id !== item.id)) {
vm.$set(item, '_checked', true);
tableSelectDate.push(item);
} else {
vm.$set(item, '_checked', false);
}
}
},
// 校验字符串是否相同 合同使用
contrastString (originStr, changeStr) {
let origin = originStr
.replace(/\s*/g, '')
.replace(/"/g, '\'')
.replace(/&nbsp;/g, '')
.replace(/disabled=\/'\/'/g, 'disabled');
let change = changeStr
.replace(/\s*/g, '')
.replace(/"/g, '\'')
.replace(/&nbsp;/g, '')
.replace(/disabled=\/'\/'/g, 'disabled');
return origin === change;
},
// 获取当前日期getDateStr(0)、前几天getDateStr(-10)、后几天getDateStr(20)
getDateStr (AddDayCount, format) {
let date = new Date();
// 获取AddDayCount天后的日期
date.setDate(date.getDate() + AddDayCount);
return this.getDate(date, format);
},
getDate (date, format) {
let year = date.getFullYear();
// day获取当前几号不足10补0
let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate();
// month获取当前月份的日期不足10补0
let month =
date.getMonth() + 1 > 9
? date.getMonth() + 1
: '0' + (date.getMonth() + 1);
// h获取当前小时不足10补0
let h = date.getHours() > 9 ? date.getHours() : '0' + date.getHours();
// s获取当前分钟不足10补0
let m = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes();
// s获取当前秒数不足10补0
let s = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds();
let resultDate = '';
if (format === dateFormat.YMD) {
resultDate = year + '-' + month + '-' + day;
}
if (format === dateFormat.YMDHM) {
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m;
}
if (format === dateFormat.YMDHMS) {
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s;
}
return resultDate;
},
// 获取周一和周日日期,返回两种格式时间
getDateWeek () {
let now = new Date();
let nowTime = now.getTime();
let day = now.getDay();
let oneDayLong = 1000 * 60 * 60 * 24;
let MondayTime = nowTime - (day - 1) * oneDayLong;
let SundayTime = nowTime + (7 - day) * oneDayLong;
let monday = new Date(MondayTime);
let sunday = new Date(SundayTime);
return {
// first: this.getDateAll(monday),
// last: this.getDateAll(sunday),
firstDate: monday,
lastDate: sunday
};
},
// 获取月初与月末日期,返回两种时间格式
getDateMonth () {
let dateFirter = new Date();
let dateLast = new Date();
dateFirter.setDate(1);
let currentMonth = dateLast.getMonth();
let nextMonth = ++currentMonth;
let nextMonthFirstDay = new Date(dateLast.getFullYear(), nextMonth, 1);
let oneDay = 1000 * 60 * 60 * 24;
dateLast = new Date(nextMonthFirstDay - oneDay);
return {
// first: this.getDateAll(dateFirter),
// last: this.getDateAll(dateLast),
firstDate: dateFirter,
lastDate: dateLast
};
},
// 计算天数
getDayBetweenDate (date) {
date = this.getDate(new Date(date), 'YMD');
let startTime = Date.parse(new Date(date)); // IE支持“yyyy/MM/dd”格式
let endTime = Date.parse(this.getDate(new Date(), 'YMD'));
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
return day;
},
getDateIntervalYear (firstDate, secondDate) {
if (!firstDate || !secondDate) {
return 0;
}
let first = new Date(firstDate);
let second = new Date(secondDate);
let firstYear = first.getFullYear();
let secondYear = second.getFullYear();
let intervalYear = secondYear - firstYear;
return intervalYear < 0 ? 0 : intervalYear;
},
getDateIntervalYearFixed2 (firstDate, secondDate) {
if (!firstDate || !secondDate) {
return 0;
}
// 格式化时间
let startDate = new Date(this.getDate(new Date(firstDate), 'YMD'));
let endDate = new Date(this.getDate(new Date(secondDate), 'YMD'));
// 得到毫秒值
let startTime = Date.parse(startDate);
let endTime = Date.parse(endDate);
// 得到差了多少天
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
if (day <= 0) {
return 0;
}
// 得到差的多少年 保留两位小数
let resultYear = parseFloat((day / (30 * 12)).toFixed(2));
return resultYear;
},
// 数字转化为中文大写
// 代码如下所示:
convertCurrency (money) {
// 汉字的数字
let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
// 基本单位
let cnIntRadice = ['', '拾', '佰', '仟'];
// 对应整数部分扩展单位
let cnIntUnits = ['', '万', '亿', '兆'];
// 对应小数部分单位
let cnDecUnits = ['角', '分', '毫', '厘'];
// 整数金额时后面跟的字符
let cnInteger = '整';
// 整型完以后的单位
let cnIntLast = '元';
// 最大处理的数字
let maxNum = 999999999999999.9999;
// 金额整数部分
let integerNum;
// 金额小数部分
let decimalNum;
// 输出的中文金额字符串
let chineseStr = '';
// 分离金额后用的数组,预定义
let parts;
if (money === '') {
return '';
}
money = parseFloat(money);
if (money >= maxNum) {
// 超出最大处理数字
return '';
}
if (money === 0) {
chineseStr = cnNums[0] + cnIntLast + cnInteger;
return chineseStr;
}
// 转换为字符串
money = money.toString();
if (money.indexOf('.') === -1) {
integerNum = money;
decimalNum = '';
} else {
parts = money.split('.');
integerNum = parts[0];
decimalNum = parts[1].substr(0, 4);
}
// 获取整型部分转换
if (parseInt(integerNum, 10) > 0) {
let zeroCount = 0;
let IntLen = integerNum.length;
for (let i = 0; i < IntLen; i++) {
let n = integerNum.substr(i, 1);
let p = IntLen - i - 1;
let q = p / 4;
let m = p % 4;
if (n === '0') {
zeroCount++;
} else {
if (zeroCount > 0) {
chineseStr += cnNums[0];
}
// 归零
zeroCount = 0;
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
}
if (m === 0 && zeroCount < 4) {
chineseStr += cnIntUnits[q];
}
}
chineseStr += cnIntLast;
}
// 小数部分
if (decimalNum !== '') {
let decLen = decimalNum.length;
for (let i = 0; i < decLen; i++) {
let n = decimalNum.substr(i, 1);
if (n !== '0') {
chineseStr += cnNums[Number(n)] + cnDecUnits[i];
}
}
}
if (chineseStr === '') {
chineseStr += cnNums[0] + cnIntLast + cnInteger;
} else if (decimalNum === '') {
chineseStr += cnInteger;
}
return chineseStr;
}
};
export const dateTimeRangeConvert = (timerange) => {
// timerange
let arr = [];
if (timerange[0] === '') {
arr.push(null);
} else {
arr.push(moment(timerange[0]).format("YYYY-MM-DD 00:00:00"));
}
if (timerange[1] === '') {
arr.push(null);
} else {
arr.push(moment(timerange[1]).format("YYYY-MM-DD 23:59:59"));
}
return arr;
}

View File

@@ -0,0 +1,49 @@
const watermark = {};
const setWatermark = (str) => {
const id = '1.23452384164.123412415';
if (document.getElementById(id) !== null) {
document.body.removeChild(document.getElementById(id));
}
const can = document.createElement('canvas');
can.width = 150;
can.height = 120;
const cans = can.getContext('2d');
cans.rotate(-20 * Math.PI / 180);
cans.font = '15px Vedana';
cans.fillStyle = 'rgba(0, 0, 0, 0.15)';
cans.textAlign = 'left';
cans.textBaseline = 'Middle';
cans.fillText(str, can.width / 20, can.height);
const div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';
div.style.top = '3px';
div.style.left = '0px';
div.style.position = 'fixed';
div.style.zIndex = '100000';
div.style.width = document.documentElement.clientWidth + 'px';
div.style.height = document.documentElement.clientHeight + 'px';
div.style.background = 'url(' + can.toDataURL('image/png') + ') left top repeat';
document.body.appendChild(div);
return id;
};
// 该方法只允许调用一次
watermark.set = (str) => {
let id = setWatermark(str);
setInterval(() => {
if (document.getElementById(id) === null) {
id = setWatermark(str);
}
}, 2000);
window.onresize = () => {
setWatermark(str);
};
};
export default watermark;

View File

@@ -0,0 +1,62 @@
// vue 三大核心
import Vue from 'vue';
import router from '@/router';
import store from '@/store';
// 更好的兼容性
import 'core-js/stable';
import 'regenerator-runtime/runtime';
// 移动端适配
import 'lib-flexible/flexible.js';
import 'vant/lib/index.css';
// 引入首个组件
import App from './App.vue';
// 引入自定义主题样式
import './themes/index.scss';
// 引入过滤器
import './filters';
// 引入配置信息
import config from '@/config';
// 引入自定义smart 插件
import SmartPlugin from './plugins/smart';
// Import component
import Loading from 'vue-loading-overlay';
// Import stylesheet
import 'vue-loading-overlay/dist/vue-loading.css';
import Vant from 'vant';
import 'vant/lib/index.css';
// sentry错误预警
import SmartSentry from './plugins/smart-sentry';
import Enum from 'vue-enum';
import enumInfo from '@/constants';
import _ from 'lodash';
Vue.use(Vant);
Vue.use(Loading);
Vue.use(SmartPlugin);
Vue.use(SmartSentry);
Vue.prototype.$config = config;
Vue.config.productionTip = false;
Vue.use(Enum, {
enumInfo
});
window._ = _;
new Vue({
el: '#app',
router,
store,
render: h => h(App)
});

View File

@@ -0,0 +1,17 @@
import * as Sentry from '@sentry/browser';
const SmartSentry = {};
SmartSentry.install = function(Vue, options) {
Vue.prototype.$smartSentry = {
captureException: (error) => {
console.error(error);
if (error.config && error.data && error && error.headers && error.request && error.status) {
return;
}
Sentry.captureException(error);
}
};
};
export default SmartSentry;

View File

@@ -0,0 +1,24 @@
let loader = null;
const SmartPlugin = {};
SmartPlugin.install = function(Vue, options) {
Vue.prototype.$smart = {
loading: (message) => {
if (loader) {
loader.hide();
}
loader = Vue.$loading.show({
// Optional parameters
lockScroll: true,
color: '#1989fa'
});
},
loadingClear: () => {
loader.hide();
}
};
};
export default SmartPlugin;

View File

@@ -0,0 +1,8 @@
// 按需全局引入 vant组件
import Vue from 'vue';
import { Button, List, Cell, Tabbar, TabbarItem } from 'vant';
Vue.use(Button);
Vue.use(Cell);
Vue.use(List);
Vue.use(Tabbar).use(TabbarItem);

View File

@@ -0,0 +1,42 @@
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
/**
* dashboard首页
*/
export const dashboardRouter = [
{
path: '/',
// redirect: '/dashboard/contact-company',
redirect: '/dashboard/user',
meta: {
title: '首页',
keepAlive: true,
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
},
component: () => import('@/views/dashboard/dashboard'),
children: [
// {
// path: '/dashboard/contact-company',
// name: 'ContactCompany',
// meta: {
// title: '往来单位',
// keepAlive: true,
// showTabbar: true,
// permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
// },
// component: () => import('@/views/erp/contact-company/contact-company')
// },
{
path: '/dashboard/user',
name: 'Mine',
meta: {
title: '我的',
keepAlive: false,
showTabbar: true,
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
},
component: () => import('@/views/user/index')
}
]
}
];

View File

@@ -0,0 +1,21 @@
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
export const developRouter = [
{
path: '/develop',
component: () => import('@/views/dashboard/dashboard'),
children: [
{
path: '/develop/config',
name: 'DevelopConfig',
meta: {
title: '开发专用配置',
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
},
component: () => import('views/develop/config')
}
]
}
];

View File

@@ -0,0 +1,26 @@
// 错误页
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
export const errorRouter = [
{
path: '/404',
name: 'Error404',
meta: {
hideInMenu: true,
access: true,
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
},
component: () => import('views/error/404.vue')
},
{
path: '/500',
name: 'Error500',
meta: {
hideInMenu: true,
access: true,
noValidatePrivilege: true,
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
},
component: () => import('views/error/404.vue')
}
];

View File

@@ -0,0 +1,150 @@
import Vue from 'vue';
import Router from 'vue-router';
import { routers } from './routers';
import cookie from '@/lib/cookie';
import { ROUTER_PERMISSION_TYPE } from './router-const';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
const projectConfig = require('@/config/index.js');
Vue.use(Router);
/**
* 导入所有的router
* @type {VueRouter}
*/
const router = new Router({
routes: routers
});
// 解决路由跳转相同的地址报错
const originalPush = Router.prototype.push;
Router.prototype.push = function(location) {
try {
return originalPush.call(this, location).catch(err => err);
} catch (error) {
// TODO zhuoda sentry
console.error(error);
}
};
const LOGIN_PAGE_NAME = 'Login';
// --------------------- router 守卫 begin ---------------------
router.beforeEach((to, from, next) => {
// 加载进度条
NProgress.start();
// 权限
const permissionType = to.meta.permissionType;
// 不需要验证,直接放行
if (permissionType === ROUTER_PERMISSION_TYPE.NO_VALID.value) {
next();
return;
}
const token = cookie.getToken();
// 需要登录
if (permissionType === ROUTER_PERMISSION_TYPE.NEED_LOGIN.value) {
if (token) {
next();
} else {
next({
name: LOGIN_PAGE_NAME
});
}
return;
}
// 需要登录,且验证权限
if (permissionType === ROUTER_PERMISSION_TYPE.VALIDATE_PERMISSION.value) {
if (!token) {
// TODO 验证权限
next({
name: LOGIN_PAGE_NAME
});
return;
}
}
next({
name: 'Error404'
});
});
router.afterEach(to => {
NProgress.done();
window.scrollTo(0, 0);
if (to.meta.title) {
console.log(to.meta);
document.title = to.meta.title + ' ' + projectConfig.title;
}
});
// --------------------- router 守卫 end ---------------------
/**
* router 检测
*
* 如果存在相同的 path 或者 name 是一件非常恐怖的事情所以在develop环境将所有router进行一次遍历<br>
* 检测内容如下:<br>
* 1、相同的router name
* 2、相同的router name
* 3、path没有以 / 开头
*
*/
const tempCheckObj = {
checkRouterNameMap: new Map(),
checkRouterPathMap: new Map()
};
function recursionCheckRouter(routerArray) {
for (const routerItem of routerArray) {
if (!routerItem.name) {
console.error('没有配置router name', routerItem);
} else {
const existNameRouter = tempCheckObj.checkRouterNameMap.get(
routerItem.name
);
if (typeof existNameRouter !== 'undefined') {
console.error('存在相同的router name', routerItem, existNameRouter);
} else {
tempCheckObj.checkRouterNameMap.set(routerItem.name, routerItem);
}
}
if (!routerItem.path) {
console.error('没有配置router path', routerItem);
} else {
// path必须以 / 开头
if (routerItem.path !== '*' && routerItem.path.indexOf('/') !== 0) {
console.error('path 没有以/开头 ', routerItem);
}
const existPathRouter = tempCheckObj.checkRouterPathMap.get(
routerItem.path
);
if (typeof existPathRouter !== 'undefined') {
console.error('存在相同的router path', routerItem, existPathRouter);
} else {
tempCheckObj.checkRouterPathMap.set(routerItem.path, routerItem);
}
}
if (routerItem.children) {
recursionCheckRouter(routerItem.children);
}
}
}
// 如果是开发环境需要检测router的规范性
if (process.env.NODE_ENV === 'development') {
recursionCheckRouter(routers);
delete tempCheckObj.checkRouterNameMap;
delete tempCheckObj.checkRouterPathMap;
}
export default router;

View File

@@ -0,0 +1,15 @@
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
export const loginRouter = [
{
path: '/login',
name: 'Login',
meta: {
title: '登录',
keepAlive: false,
permissionType: ROUTER_PERMISSION_TYPE.NO_VALID.value
},
component: () => import('@/views/login/login.vue')
}
];

View File

@@ -0,0 +1,23 @@
/**
* 权限类型
*/
export const ROUTER_PERMISSION_TYPE = {
/**
* 不 验 证
*/
NO_VALID: {
value: 1
},
/**
* 需要登录
*/
NEED_LOGIN: {
value: 2
},
/**
* 需要验证权限
*/
VALIDATE_PERMISSION: {
value: 3
}
};

View File

@@ -0,0 +1,32 @@
// 全局错误页面
import { errorRouter } from './error/error';
// 登录注册模块
import { loginRouter } from './login/login';
// tabbar dashboard 框架页面
import { dashboardRouter } from './dashboard';
// 用户相关
import { userRouter } from './user/user';
// 开发相关
import { developRouter } from './develop/develop';
/**
* router meta 说明: <br>
*
* title: 为页面的title会显示到浏览器的title上
* permissionType: 具体使用 router-const.js中的 ROUTER_PERMISSION_TYPE 常量;情况有: 1)不验证 2)校验登录 3)登录后校验权限
* keepAlive: true or false ; 是否进行页面keepalive, 如果想删除keepalive可以使用vuex中的app module里有mutation
* showTabbar: true or false ; 是否展示 tabbar, 如果是true 则会展示tabbar
*
*/
export const routers = [
// 登录、注册
...loginRouter,
// 404、500、403等
...errorRouter,
// tab bar 页面
...dashboardRouter,
// 用户
...userRouter,
// 开发相关
...developRouter
];

View File

@@ -0,0 +1,21 @@
import { ROUTER_PERMISSION_TYPE } from '@/router/router-const';
export const userRouter = [
{
path: '/user',
component: () => import('@/views/dashboard/dashboard'),
children: [
{
path: '/user/change-password',
name: 'UserChangePassword',
meta: {
title: '修改密码',
permissionType: ROUTER_PERMISSION_TYPE.NEED_LOGIN.value
},
component: () =>
import('views/user/change-password')
}
]
}
];

View File

@@ -0,0 +1,23 @@
import Vue from 'vue';
import Vuex from 'vuex';
import user from './module/user';
import app from './module/app';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//
},
mutations: {
//
},
actions: {
//
},
modules: {
app,
user
}
});

View File

@@ -0,0 +1,32 @@
/**
* 整个应用相关的状态信息
*
* 比如: keepalive等
*/
export default {
namespaced: true,
state: {
// 缓存路由
keepAliveIncludes: []
},
mutations: {
// 加入keep-alive缓存
pushKeepAliveIncludes(state, val) {
if (state.keepAliveIncludes.length < 30) {
const number = state.keepAliveIncludes.findIndex(e => e === val);
if (number === -1) {
state.keepAliveIncludes.push(val);
}
}
},
// 删除缓存
deleteKeepAliveIncludes(state, val) {
const number = state.keepAliveIncludes.findIndex(e => e === val);
if (number !== -1) {
state.keepAliveIncludes.splice(number, 1);
}
}
}
};

View File

@@ -0,0 +1,41 @@
import cookie from '@/lib/cookie.js';
export default {
namespaced: true,
state: {
token: cookie.getToken(),
// session 信息
sessionInfo: {},
// 是否获取了session
isHaveGotSessionInfo: false,
// 权限集合
privilegeKeySet: new Set()
},
mutations: {
clearSession() {
state.token = null;
state.sessionInfo = null;
state.privilegeKeySet = new Set();
},
updateSession(state, userLoginInfo) {
state.isHaveGotSessionInfo = true;
state.sessionInfo = userLoginInfo;
if (userLoginInfo.privilegeList) {
state.privilegeKeySet = new Set(userLoginInfo.privilegeList.map(e => e.key));
}
}
},
getters: {
// 用户菜单权限
privilegeKeySet: state => state.privilegeKeySet,
isSuperMan: state => state.sessionInfo.isSuperMan,
actualName: state => state.sessionInfo.actualName,
loginUserId: state => state.sessionInfo.id
},
actions: {
// 登录
handleLogin({ commit }, params) {
}
}
};

View File

@@ -0,0 +1,6 @@
html,
body {
font-family: Arial, Helvetica, 'STHeiti STXihei', 'Microsoft YaHei', Tohoma, sans-serif;
background-color: $background-color;
}

View File

@@ -0,0 +1,110 @@
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* Parse the time to string
* @param {(Object|string|number)} time
* @param {string} cFormat
* @returns {string}
*/
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
/**
* @param {number} time
* @param {string} option
* @returns {string}
*/
export function formatTime(time, option) {
if (('' + time).length === 10) {
time = parseInt(time) * 1000
} else {
time = +time
}
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {string} url
* @returns {Object}
*/
export function param2Obj(url) {
const search = url.split('?')[1]
if (!search) {
return {}
}
return JSON.parse(
'{"' +
decodeURIComponent(search)
.replace(/"/g, '\\"')
.replace(/&/g, '","')
.replace(/=/g, '":"')
.replace(/\+/g, ' ') +
'"}'
)
}

View File

@@ -0,0 +1,58 @@
import axios from 'axios'
import store from '@/store'
import { Toast } from 'vant'
// 根据环境不同引入不同api地址
import { baseApi } from '@/config'
// create an axios instance
const service = axios.create({
baseURL: baseApi, // url = base api url + request url
withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
// request拦截器 request interceptor
service.interceptors.request.use(
config => {
// 不传递默认开启loading
if (!config.hideloading) {
// loading
Toast.loading({
forbidClick: true
})
}
if (store.getters.token) {
config.headers['X-Token'] = ''
}
return config
},
error => {
// do something with request error
console.log(error) // for debug
return Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
response => {
Toast.clear()
const res = response.data
if (res.status && res.status !== 200) {
// 登录超时,重新登录
if (res.status === 401) {
store.dispatch('FedLogOut').then(() => {
location.reload()
})
}
return Promise.reject(res || 'error')
} else {
return Promise.resolve(res)
}
},
error => {
Toast.clear()
console.log('err' + error) // for debug
return Promise.reject(error)
}
)
export default service

View File

@@ -0,0 +1,20 @@
/**
* Created by Sunnie on 19/06/04.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path)
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ['admin', 'editor']
return valid_map.indexOf(str.trim()) >= 0
}

View File

@@ -0,0 +1,99 @@
<template>
<div>
<!---------------- 页面内容 begin ---------------->
<div class="main-content">
<keep-alive :include="keepAliveIncludes">
<router-view/>
</keep-alive>
</div>
<!---------------- 页面内容 end ---------------->
<!---------------- 底部 tabbar begin ---------------->
<!---------------- 对于一些需要展示tabbar的页面则进行展示 ---------------->
<div class="main-footer" v-show="$route.meta && $route.meta.showTabbar">
<van-tabbar
fixed
route
v-model="active"
>
<van-tabbar-item
v-for="(item, index) in tabbar"
:to="item.to"
:icon="item.icon"
:name="item.name"
:key="index">
{{ item.title }}
</van-tabbar-item>
</van-tabbar>
</div>
<!---------------- 底部 tabbar end ---------------->
</div>
</template>
<script type="text/javascript">
import SessionMixin from 'components/mixin/session-mixin';
import { mapMutations, mapState } from 'vuex';
export default {
name: 'DashBoard',
mixins: [SessionMixin],
data() {
return {
active: 'Mine',
tabbar: [
// {
// name: 'ContactCompany',
// title: '首页',
// icon: 'user-o',
// badge: 0,
// to: '/contact-company'
// },
{
name: 'Mine',
title: '我的',
icon: 'user-o',
to: '/user'
}
]
};
},
computed: {
...mapState({
keepAliveIncludes: state => state.app.keepAliveIncludes
})
},
created() {
// 通过路由跳转绑定Tabbar的选中
this.updateTabbarSelected(this.$route.name);
this.checkRouterKeepAlive(this.$route);
},
watch: {
$route(newRoute) {
this.checkRouterKeepAlive(newRoute);
}
},
methods: {
...mapMutations('app', [
'pushKeepAliveIncludes',
'deleteKeepAliveIncludes'
]),
checkRouterKeepAlive(newRoute) {
const { name, meta } = newRoute;
if (meta && meta.keepAlive) {
this.pushKeepAliveIncludes(name);
} else {
this.deleteKeepAliveIncludes(name);
}
},
updateTabbarSelected(item) {
console.log(item, 12222);
this.active = item;
}
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,47 @@
<!-- home -->
<template>
<div>
<router-nav-bar path="/dashboard/user" title="开发专用配置" left-text="返回" left-arrow />
<van-cell center title="VConsole">
<van-switch v-model="vconsoleFlag" @change="switchVConsole" />
</van-cell>
</div>
</template>
<script>
import RouterNavBar from 'components/van-bar/RouterNavBar';
const VCONSOLE_ID = '__vconsole';
export default {
name: 'DevelopConfig',
components: {
RouterNavBar
},
data() {
return {
vconsole: null,
vconsoleFlag: false
};
},
mounted() {
this.checkVConsoleExist();
},
methods: {
// 检测vconsole是否存在
checkVConsoleExist() {
const vconsoleElement = document.getElementById(VCONSOLE_ID);
this.vconsoleFlag = !!vconsoleElement;
},
// 提交表单
switchVConsole(flag) {
if (flag) {
this.vconsole = new VConsole();
} else {
delete this.vconsole;
document.getElementById(VCONSOLE_ID).remove();
this.vconsole = null;
}
}
}
};
</script>

View File

@@ -0,0 +1,23 @@
<!-- home -->
<template>
<div class="index-container">
<h1>404!</h1>
</div>
</template>
<script>
export default {
data() {
return {
list: []
};
},
computed: {},
mounted() {
},
methods: {}
};
</script>

View File

@@ -0,0 +1,68 @@
<!-- home -->
<template>
<div style="padding: 0.4rem">
<h1 align="center">Smart-Admin-H5</h1>
<van-form @submit="onSubmit">
<van-field
v-model="formData.loginName"
name="用户名"
label="用户名"
placeholder="用户名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<van-field
v-model="formData.loginPwd"
type="password"
name="密码"
label="密码"
placeholder="密码"
:rules="[{ required: true, message: '请填写密码' }]"
/>
<div style="margin: 16px;">
<van-button block type="info" native-type="submit">
登录
</van-button>
</div>
</van-form>
</div>
</template>
<script>
import { loginApi } from '@/api/login';
import cookie from '@/lib/cookie';
export default {
data() {
return {
formData: {
loginName: '',
loginPwd: ''
},
};
},
mounted() {
},
methods: {
// 提交登录表单
async onSubmit() {
this.$smart.loading();
try {
const res = await loginApi.login(this.formData);
const loginInfo = res.data;
this.$store.commit('user/updateSession', loginInfo);
cookie.setToken(loginInfo.xaccessToken);
this.$toast.success('登录成功');
this.$router.replace('/dashboard/user');
// this.$router.replace('/contact-company');
} catch (e) {
this.$smartSentry.captureException(e);
await this.getVerificationCode();
} finally {
this.$smart.loadingClear();
}
}
}
};
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,76 @@
<!-- home -->
<template>
<div>
<router-nav-bar path="/dashboard/user" title="修改密码" left-text="返回" left-arrow />
<van-form @submit="onSubmit">
<van-field
v-model="formData.loginName"
name="旧密码"
label="旧密码"
placeholder="旧密码"
:rules="[{ required: true, message: '请填写旧密码' }]"
/>
<van-field
v-model="formData.loginPwd"
type="password"
name="新密码"
label="新密码"
placeholder="新密码"
:rules="[{ required: true, message: '请填写新密码' }]"
/>
<van-field
style="width: 60%;float:left"
v-model="formData.code"
type="password"
name="新密码"
label="新密码"
placeholder="新密码"
:rules="[{ required: true, message: '请填写新密码' }]"
/>
<div style="margin: 16px;">
<van-button block type="info" native-type="submit" size="small">
提交
</van-button>
</div>
</van-form>
</div>
</template>
<script>
import RouterNavBar from 'components/van-bar/RouterNavBar';
export default {
components: {
RouterNavBar
},
data() {
return {
formData: {
loginName: '',
loginPwd: '',
code: '',
codeUuid: ''
},
codeUrl: ''
};
},
mounted() {
},
methods: {
// 提交表单
onSubmit() {
this.$smart.loading();
try {
this.$toast.success('暂未实现');
this.$router.replace('/dashboard/user');
} catch (e) {
console.log(e);
this.$smartSentry.captureException(e);
} finally {
this.$smart.loadingClear();
}
}
}
};
</script>

View File

@@ -0,0 +1,79 @@
<!-- home -->
<template>
<div>
<van-nav-bar title="个人中心"/>
<van-grid :column-num="1">
<van-grid-item icon="home-o" :text="actualName"/>
</van-grid>
<van-cell-group>
<van-cell icon="location-o" to="/user/change-password" title="修改密码" is-link />
<van-cell icon="bulb-o" title="更新权限" @click="forceUpdatePrivilege" is-link/>
<van-cell icon="delete" title="清空缓存" @click="clearCache" is-link/>
<van-cell icon="apps-o" title="开发专用" is-link to="/develop/config"/>
</van-cell-group>
<div style="margin: 16px;">
<van-button block @click="logout" type="warning" size="small">
退出登录
</van-button>
</div>
</div>
</template>
<script>
import { loginApi } from 'api/login';
import cookie from '@/lib/cookie';
import { userApi } from 'api/user';
export default {
name: 'Mine',
data() {
return {
actualName: null
};
},
computed: {},
mounted() {
this.actualName = '你好, ' + this.$store.getters['user/actualName'];
},
methods: {
// 清空缓存
clearCache() {
this.$toast('清空了!!');
},
// 更新权限
async forceUpdatePrivilege() {
this.$smart.loading();
try {
const res = await userApi.getSession();
const loginInfo = res.data;
this.$store.commit('user/updateSession', loginInfo);
this.$toast('已成功更新权限!');
} catch (e) {
this.$smartSentry.captureException(e);
} finally {
this.$smart.loadingClear();
}
},
// 退出
async logout() {
this.$smart.loading();
try {
await loginApi.logout(cookie.getToken());
} catch (e) {
this.$smartSentry.captureException(e);
} finally {
cookie.clearToken();
this.$smart.loadingClear();
this.$router.replace('/login');
}
}
}
};
</script>

View File

@@ -0,0 +1,200 @@
const path = require('path');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
const SentryPlugin = require('@sentry/webpack-plugin');
const resolve = dir => path.join(__dirname, dir);
// 项目配置
const projectConfig = require('./src/config/index.js');
// 生产环境,测试和正式
const isProductionEnv = ['production'].includes(process.env.NODE_ENV);
const isProductionAppEnv = ['prod', 'pre'].includes(process.env.VUE_APP_ENV);
module.exports = {
publicPath: projectConfig.publicPath,
// 生产环境构建文件的目录
outputDir: 'dist',
// outputDir的静态资源(js、css、img、fonts)目录
assetsDir: 'static',
// eslint检测 按需开启
lintOnSave: !isProductionEnv,
// 如果你不需要生产环境的 source map可以将其设置为 false 以加速生产环境构建。
productionSourceMap: false,
devServer: {
// 设置主机地址
host: '0.0.0.0',
// 设置默认端口
port: 8090,
// 禁用host验证
disableHostCheck: true,
// 启动后打开浏览器
open: true,
overlay: {
// 当出现编译器错误或警告时,在浏览器中显示全屏覆盖层
warnings: false,
errors: true
}
// proxy: {
// //配置跨域
// '/api': {
// // 接口前缀
// target: "https://sit.smart-h5.1024lab.net/api",
// // ws:true,
// changOrigin:true,
// // 改写规则,把/api 替换为/
// pathRewrite:{
// '^/api':'/'
// }
// }
// }
},
css: {
// 是否使用css分离插件 ExtractTextPlugin 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。
extract: isProductionEnv,
// 开启 CSS source maps
sourceMap: false,
// 使用vw布局去掉这个
requireModuleExtension: true,
loaderOptions: {
// 引入全局变量
scss: {
additionalData: `@import "@/assets/css/index";` // 全局引入
}
}
},
configureWebpack: config => {
config.name = projectConfig.title;
},
chainWebpack: config => {
// 移除资源预加载(路由懒加载才能正常使用)
config.plugins.delete('preload');
config.plugins.delete('prefetch');
// 别名 alias
config.resolve.alias
.set('@', resolve('src'))
.set('assets', resolve('src/assets'))
.set('api', resolve('src/api'))
.set('views', resolve('src/views'))
.set('components', resolve('src/components'));
// 应用名字
config.plugin('html').tap(args => {
args[0].title = projectConfig.title;
return args;
});
// 设置保留空格
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options.compilerOptions.preserveWhitespace = true;
return options;
})
.end();
// ==================== 生产环境配置 begin ====================
if (isProductionEnv) {
// 打包分析
config.plugin('webpack-report').use(BundleAnalyzerPlugin, [
{
analyzerMode: 'static'
}
]);
// 不显示源码
config.devtool('cheap-source-map');
// cdn
config.plugin('html').tap(args => {
args[0].cdn = projectConfig.cdn.cdnResource;
// 压缩html中的css
args[0].minify.minifyCSS = true;
return args;
});
// 指定资源加载cdn
config.externals(projectConfig.cdn.externals);
// 开启gzip , Nginx上也需要配置gzip才会生效
config
.plugin('compression')
.use(CompressionWebpackPlugin)
.tap(() => [
{
// 压缩 js 与 css
test: new RegExp(
'\\.(js|css)$'
),
// 资源文件大于10240B=10kB时会被压缩
threshold: 10240,
// 最小压缩比达到0.8时才会被压缩
minRatio: 0.8
}
]);
// sentry
if (isProductionAppEnv) {
config.plugin('sentry').use(SentryPlugin, [{
ignore: ['node_modules'],
include: './dist', // 上传dist文件的js
configFile: './.sentryclirc' // 配置文件地址
}]);
}
config.optimization.minimizer = [
new UglifyjsWebpackPlugin({
// 生产环境推荐关闭 sourcemap 防止源码泄漏
// 服务端通过前端发送的行列,根据 sourcemap 转为源文件位置
sourceMap: false,
uglifyOptions: {
warnings: false,
compress: {
drop_console: true,
drop_debugger: true
}
}
})
];
config
.plugin('ScriptExtHtmlWebpackPlugin')
.after('html')
.use(ScriptExtHtmlWebpackPlugin, [
{
// 将 runtime 作为内联引入不单独存在
inline: /runtime\..*\.js$/
}
])
.end();
config.optimization.splitChunks({
chunks: 'all',
cacheGroups: {
commons: {
name: 'chunk-commons',
test: resolve('src/components'),
minChunks: 3, // 模块至少使用次数
priority: 5,
reuseExistingChunk: true // 模块嵌套引入时,判断是否复用已经被打包的模块
},
node_vendors: {
name: 'chunk-libs',
chunks: 'initial',
test: /[\\/]node_modules[\\/]/,
priority: 10
},
vantUI: {
name: 'chunk-vantUI',
priority: 20,
test: /[\\/]node_modules[\\/]_?vant(.*)/
}
}
});
}
// ==================== 生产环境配置 end ====================
}
};

31
smart-admin-service/.gitignore vendored Normal file
View File

@@ -0,0 +1,31 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/

View File

@@ -3,7 +3,7 @@
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>com.gangquan360</groupId>
<groupId>net.1024lab</groupId>
<artifactId>smart-admin-service-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
@@ -11,74 +11,42 @@
<modules>
<module>smart-admin-api</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<hibernate.annotations.version>3.3.0.ga</hibernate.annotations.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<log4j.web.version>2.10.0</log4j.web.version>
<smartadmin.springboot.version>2.1.9.RELEASE</smartadmin.springboot.version>
<smartadmin.springcloud.version>Finchley.SR1</smartadmin.springcloud.version>
<spring-framework-bom.version>5.1.10.RELEASE</spring-framework-bom.version>
<actuator.version>2.0.5.RELEASE</actuator.version>
<jolokia.version>1.5.0</jolokia.version>
<micrometer.version>1.0.6</micrometer.version>
<thymeleaf-extras-data-attribute.version>2.0.1</thymeleaf-extras-data-attribute.version>
<thymeleaf-extras-java8time.version>3.0.1.RELEASE</thymeleaf-extras-java8time.version>
<thymeleaf-extras-springsecurity4.version>3.0.2.RELEASE</thymeleaf-extras-springsecurity4.version>
<thymeleaf-layout-dialect.version>2.3.0</thymeleaf-layout-dialect.version>
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
<smartadmin.springboot.version>2.2.5.RELEASE</smartadmin.springboot.version>
<velocity.version>1.7</velocity.version>
<swagger.version>2.7.0</swagger.version>
<mybatis-spring-boot.version>1.3.0</mybatis-spring-boot.version>
<sql-server.version>6.3.2.jre8-preview</sql-server.version>
<fastjson.version>1.2.9</fastjson.version>
<feign-gson-version>8.18.0</feign-gson-version>
<guava-version>23.1-jre</guava-version>
<pagehelper-version>1.2.3</pagehelper-version>
<oss.version>2.7.0</oss.version>
<qiniu.version>[7.2.0, 7.2.99]</qiniu.version>
<fileupload.version>1.3.1</fileupload.version>
<jjwt.version>0.9.0</jjwt.version>
<openhtml.version>0.0.1-RC11</openhtml.version>
<hibernate-validator-version>6.0.2.Final</hibernate-validator-version>
<javax.validation-version>2.0.0.Final</javax.validation-version>
<javax.el-version>3.0.1-b08</javax.el-version>
<druid.version>1.0.29</druid.version>
<commons-lang3.version>3.3.2</commons-lang3.version>
<mybatisplus.version>2.1.6</mybatisplus.version>
<mybatisplus-spring-boot-starter.version>1.0.4</mybatisplus-spring-boot-starter.version>
<concurrentlinkedhashmap-version>1.4.2</concurrentlinkedhashmap-version>
<velocity-engine-core.version>2.0</velocity-engine-core.version>
<client.version>1.0.0-SNAPSHOT</client.version>
<springboot.redis.version>2.0.2.RELEASE</springboot.redis.version>
<apache-poi-version>3.15</apache-poi-version>
<easypoi-version>3.3.0</easypoi-version>
<jpush-api-version>3.3.4</jpush-api-version>
<swagger.version>2.7.0</swagger.version>
<knife4j.version>2.0.4</knife4j.version>
<mybatis-plus-boot.version>3.3.1</mybatis-plus-boot.version>
<fastjson.version>1.2.73</fastjson.version>
<guava.version>28.2-jre</guava.version>
<aliyun-oss.version>2.7.0</aliyun-oss.version>
<qiniu-oss.version>[7.2.0, 7.2.99]</qiniu-oss.version>
<jjwt.version>0.9.1</jjwt.version>
<druid.version>1.1.21</druid.version>
<p6spy.version>3.9.1</p6spy.version>
<concurrentlinkedhashmap.version>1.4.2</concurrentlinkedhashmap.version>
<easypoi.version>4.1.2</easypoi.version>
<commons-fileupload.version>1.3.1</commons-fileupload.version>
<commons-lang3.version>3.3.2</commons-lang3.version>
<commons-beanutils.version>1.9.3</commons-beanutils.version>
<weixin-sdk.version>3.1.0</weixin-sdk.version>
<kafka.version>2.1.11.RELEASE</kafka.version>
<kafka-test.version>2.1.11.RELEASE</kafka-test.version>
<sigar.version>1.6.4</sigar.version>
<userAgent.version>1.21</userAgent.version>
<commons-pool2.version>2.8.0</commons-pool2.version>
<kaptcha.version>2.3.2</kaptcha.version>
<lombok.version>1.18.8</lombok.version>
<okhttp.version>4.2.2</okhttp.version>
<mysql.version>8.0.19</mysql.version>
<user-agent-util.version>1.21</user-agent-util.version>
<lombok.version>1.18.8</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<artifactId>velocity</artifactId>
<groupId>org.apache.velocity</groupId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>${spring-framework-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--BOM begin-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
@@ -86,26 +54,65 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<!--BOM end-->
<!--springboot starter dependency begin -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-log4j2</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-actuator</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-quartz</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-validation</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-data-redis</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-web</artifactId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-websocket</artifactId>-->
<!-- <version>${smartadmin.springboot.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<!--springboot starter dependency end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${actuator.version}</version>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot.version}</version>
</dependency>
<!--velocity begin-->
<dependency>
<artifactId>velocity</artifactId>
<groupId>org.apache.velocity</groupId>
<version>${velocity.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
<version>${jolokia.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-influx</artifactId>
<version>${micrometer.version}</version>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity-engine-core.version}</version>
</dependency>
<!--velocity end-->
<!--fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
@@ -119,195 +126,59 @@
<version>${druid.version}</version>
</dependency>
<!--微信sdk依赖-->
<!--p6spy-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>${weixin-sdk.version}</version>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
<version>${kafka.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<version>${kafka.version}</version>
</dependency>
<!-- spring cloud -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${smartadmin.springcloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hibernate-validator 验证框架 start -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator-version}</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${javax.validation-version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>${javax.el-version}</version>
</dependency>
<!-- hibernate-validator 验证框架 end -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>${log4j.web.version}</version>
</dependency>
<!--thymeleaf3 begin -->
<dependency>
<groupId>com.github.mxab.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-data-attribute</artifactId>
<version>${thymeleaf-extras-data-attribute.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>${thymeleaf-extras-java8time.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>${thymeleaf-extras-springsecurity4.version}</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>${thymeleaf-layout-dialect.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
<exclusions>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<!--thymeleaf3 end -->
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${smartadmin.springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${smartadmin.springboot.version}</version>
<scope>test</scope>
</dependency>
<!-- swagger -->
<!-- swagger begin -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- swagger end -->
<!--mybatis 匹配spring Boot1.5 or higher-->
<!-- knife4j start -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!-- sql server -->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>${sql-server.version}</version>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- feign-gson -->
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-gson</artifactId>
<version>${feign-gson-version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- spring-boot cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>${smartadmin.springboot.version}</version>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- knife4j end -->
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava-version}</version>
<version>${guava.version}</version>
</dependency>
<!--page helper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper-version}</version>
</dependency>
<!-- 阿里云oss -->
<!-- oss begin -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${oss.version}</version>
<version>${aliyun-oss.version}</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>${qiniu.version}</version>
<version>${qiniu-oss.version}</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${fileupload.version}</version>
<version>${commons-fileupload.version}</version>
</dependency>
<!-- oss end -->
<!--jjwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
@@ -315,86 +186,33 @@
<version>${jjwt.version}</version>
</dependency>
<dependency>
<!-- ALWAYS required. -->
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-core</artifactId>
<version>${openhtml.version}</version>
</dependency>
<dependency>
<!-- Required for PDF output. -->
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-pdfbox</artifactId>
<version>${openhtml.version}</version>
</dependency>
<dependency>
<!-- Required for image output only. -->
<groupId>com.openhtmltopdf</groupId>
<artifactId>openhtmltopdf-java2d</artifactId>
<version>${openhtml.version}</version>
</dependency>
<!-- easy poi -->
<!-- easy poi begin -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>${easypoi-version}</version>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>${easypoi.version}</version>
</dependency>
<!-- easy poi end -->
<!--mysql-->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>${easypoi-version}</version>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>${easypoi-version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${apache-poi-version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>${apache-poi-version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${apache-poi-version}</version>
</dependency>
<!-- 极光推送 -->
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jpush-client</artifactId>
<version>${jpush-api-version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons-beanutils.version}</version>
</dependency>
<dependency>
<groupId>org.fusesource</groupId>
<artifactId>sigar</artifactId>
<version>${sigar.version}</version>
</dependency>
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${userAgent.version}</version>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>${commons-pool2.version}</version>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
@@ -404,20 +222,7 @@
<dependency>
<groupId>com.googlecode.concurrentlinkedhashmap</groupId>
<artifactId>concurrentlinkedhashmap-lru</artifactId>
<version>${concurrentlinkedhashmap-version}</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity-engine-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatisplus.version}</version>
<version>${concurrentlinkedhashmap.version}</version>
</dependency>
<dependency>
@@ -426,17 +231,10 @@
<version>${okhttp.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
<version>${mybatisplus-spring-boot-starter.version}</version>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
<version>${user-agent-util.version}</version>
</dependency>
<dependency>
@@ -523,6 +321,12 @@
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>telework</id>
<properties>
<profiles.active>telework</profiles.active>
</properties>
</profile>
<profile>
<id>sit</id>
<properties>

View File

@@ -1,17 +1,15 @@
1 更新密码
com.gangquan360.smartadmin.module.employee.EmployeeController.updatePwd
2 更新功能点
PrivilegeController functionSaveOrUpdate和menuBatchSave
3 超管默认账号
1 超管默认账号
sa/123456
4 执行脚本:
2 执行脚本:
先执行src/main/resources/sql/smart-admin.sql
再执行src/main/resources/sql/quartz_mysql_2.3.0.sql
5 除dev之外文件
3 除dev之外文件
6 刷新页面,获取权限是否走缓存
com.gangquan360.smartadmin.module.login.LoginService.getSession
4 刷新页面,获取权限是否走缓存
LoginService.getSession
5 test类中去掉代码生成run
6 前端百度统计

View File

@@ -1,7 +1,7 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.gangquan360</groupId>
<groupId>net.1024lab</groupId>
<artifactId>smart-admin-service-parent</artifactId>
<version>1.0.0</version>
<relativePath>../pom.xml</relativePath>
@@ -16,32 +16,55 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<artifactId>velocity</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
</exclusions>
<groupId>org.apache.velocity</groupId>
</dependency>
<!--springboot starter dependency begin -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
<version>2.10.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
@@ -56,60 +79,122 @@
</exclusion>
</exclusions>
</dependency>
<!--springboot starter dependency end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--velocity begin-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<artifactId>velocity</artifactId>
<groupId>org.apache.velocity</groupId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!--druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<!--velocity end-->
<!--fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- p6spy -->
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
</dependency>
<!-- swagger begin -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<!-- swagger end -->
<!-- knife4j begin -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- knife4j end -->
<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- oss begin -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<exclusions>
<exclusion>
<artifactId>logback-classic</artifactId>
<groupId>ch.qos.logback</groupId>
</exclusion>
<exclusion>
<artifactId>spring-boot-starter</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- oss end -->
<!--jjwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!-- easy poi begin -->
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
</dependency>
<!-- easy poi end -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
@@ -117,79 +202,8 @@
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatisplus-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
</dependency>
<dependency>
@@ -198,103 +212,8 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<scope>test</scope>
</dependency>
<!--redis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<exclusions>
<exclusion>
<artifactId>javassist</artifactId>
<groupId>org.javassist</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!-- 七牛云 -->
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
</dependency>
<!-- 阿里云oss -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
@@ -303,13 +222,9 @@
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@@ -1,34 +0,0 @@
package com.gangquan360.smartadmin.common.anno;
import com.gangquan360.smartadmin.module.datascope.constant.DataScopeTypeEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* [ 数据范围 ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2019 1024lab.netInc. All rights reserved.
* @date
* @since JDK1.8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataScope {
DataScopeTypeEnum dataScopeType() default DataScopeTypeEnum.DEFAULT;
/**
* 第几个where 条件 从0开始
* @return
*/
int whereIndex() default 0;
String joinSql() default "";
}

View File

@@ -1,39 +0,0 @@
package com.gangquan360.smartadmin.config;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.plugins.PerformanceInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* description
*
* @author listen
* @date 2017/12/19 13:54
*/
@EnableTransactionManagement
@Configuration
@MapperScan(basePackages = {"com.gangquan360.smartadmin.module.*"})
public class SmartMybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* mybatis-plus SQL执行效率插件【生产环境可以关闭】
*/
@Bean
@Conditional(SystemEnvironmentCondition.class)
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
}

View File

@@ -1,74 +0,0 @@
package com.gangquan360.smartadmin.module.codegenerator.service;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* [ ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2018 1024lab.netInc. All rights reserved.
* @date 2019/5/11 0011 上午 8:33
* @since JDK1.8
*/
@Component
public class CodeGeneratorComponent {
private static Map<String,String> dataMap = new HashMap<>(16);
static {
dataMap();
}
public static void dataMap(){
dataMap.put("int","Integer");
dataMap.put("tinyint","Integer");
dataMap.put("smallint","Integer");
dataMap.put("integer","Integer");
dataMap.put("bigint","Long");
dataMap.put("float","Float");
dataMap.put("double","Double");
dataMap.put("decimal","BigDecimal");
dataMap.put("char","String");
dataMap.put("varchar","String");
dataMap.put("tinytext","String");
dataMap.put("text","String");
dataMap.put("longtext","String");
dataMap.put("date","Date");
dataMap.put("datetime","Date");
dataMap.put("timestamp","Date");
}
public Map<String,String> codeTemplates(String moduleClass, String basePackage, String modulePackage){
String javaPackagePath = "src"+File.separator+"main" + File.separator + "java" + File.separator;
javaPackagePath = javaPackagePath + basePackage.replace(".", File.separator) + File.separator+"module"+File.separator + modulePackage + File.separator;
String xmlPackagePath = "src"+File.separator+"main" + File.separator + "resources" + File.separator +"mapper"+File.separator+ modulePackage + File.separator;
Map<String,String> templateMap = new HashMap<>(7);
templateMap.put("templates/codegenerator/Controller.java.vm",javaPackagePath+"controller"+File.separator+moduleClass+"Controller.java");
templateMap.put("templates/codegenerator/Dao.java.vm",javaPackagePath+"dao"+File.separator+moduleClass+"Dao.java");
templateMap.put("templates/codegenerator/Dao.xml.vm",xmlPackagePath+moduleClass+"Mapper.xml");
templateMap.put("templates/codegenerator/DTO.java.vm",javaPackagePath+"domain"+File.separator+"dto"+File.separator+moduleClass+"DTO.java");
templateMap.put("templates/codegenerator/Entity.java.vm",javaPackagePath+"domain"+File.separator+"entity"+File.separator+moduleClass+"Entity.java");
templateMap.put("templates/codegenerator/QueryDTO.java.vm",javaPackagePath+"domain"+File.separator+"dto"+File.separator+moduleClass+"QueryDTO.java");
templateMap.put("templates/codegenerator/Service.java.vm",javaPackagePath+"service"+File.separator+moduleClass+"Service.java");
return templateMap;
}
public String getJavaType(String mysqlType ){
String javaType = dataMap.get(mysqlType);
return javaType;
}
}

View File

@@ -1,55 +0,0 @@
package com.gangquan360.smartadmin.module.datascope.constant;
import java.util.Arrays;
import java.util.Optional;
/**
* [ ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2018 1024lab.netInc. All rights reserved.
* @date 2019/4/28 0028 下午 15:37
* @since JDK1.8
*/
public enum DataScopeViewTypeEnum {
ME(0,0,"本人"),
DEPARTMENT(1,5,"本部门"),
DEPARTMENT_AND_SUB(2,10,"本部门及下属子部门"),
ALL(3,15,"全部");
private Integer type;
private Integer level;
private String name;
DataScopeViewTypeEnum(Integer type,Integer level, String name) {
this.type = type;
this.level = level;
this.name = name;
}
public Integer getType() {
return type;
}
public Integer getLevel() {
return level;
}
public String getName() {
return name;
}
public static DataScopeViewTypeEnum valueOf(Integer type) {
DataScopeViewTypeEnum[] values = DataScopeViewTypeEnum.values();
Optional<DataScopeViewTypeEnum> first = Arrays.stream(values).filter(e -> e.getType().equals(type)).findFirst();
return !first.isPresent() ? null : first.get();
}
}

View File

@@ -1,37 +0,0 @@
package com.gangquan360.smartadmin.module.datascope.constant;
/**
* [ ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2018 1024lab.netInc. All rights reserved.
* @date 2019/5/8 0008 下午 16:00
* @since JDK1.8
*/
public enum DataScopeWhereInTypeEnum {
EMPLOYEE(0,"以员工IN"),
DEPARTMENT(1,"以部门IN");
private Integer type;
private String desc;
DataScopeWhereInTypeEnum(Integer type, String desc) {
this.type = type;
this.desc = desc;
}
public Integer getType() {
return type;
}
public String getDesc() {
return desc;
}
}

View File

@@ -1,25 +0,0 @@
package com.gangquan360.smartadmin.module.datascope.domain.dto;
import lombok.Data;
/**
* [ ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2018 1024lab.netInc. All rights reserved.
* @date 2019/4/28 0028 下午 17:21
* @since JDK1.8
*/
@Data
public class DataScopeSqlConfigDTO {
private Integer dataScopeType;
private String joinSql;
private Integer whereIndex;
private Integer dataScopeWhereInType;
}

View File

@@ -1,4 +1,4 @@
package com.gangquan360.smartadmin;
package net.lab1024.smartadmin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -15,8 +15,9 @@ import org.springframework.scheduling.annotation.EnableScheduling;
* @copyright (c) 2019 1024lab.netInc. All rights reserved.
* @date
* @since JDK1.8
*
*/
@SpringBootApplication(scanBasePackages = {"com.gangquan360.smartadmin", "cn.afterturn.easypoi"})
@SpringBootApplication(scanBasePackages = {"net.lab1024.smartadmin", "cn.afterturn.easypoi"})
@EnableCaching
@EnableScheduling
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

View File

@@ -1,6 +1,6 @@
package com.gangquan360.smartadmin.common.anno;
package net.lab1024.smartadmin.common.anno;
import com.gangquan360.smartadmin.common.domain.BaseEnum;
import net.lab1024.smartadmin.common.domain.BaseEnum;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -26,6 +26,18 @@ public @interface ApiModelPropertyEnum {
String example() default "";
/**
* 是否隐藏
*
* @return
*/
boolean hidden() default false;
/**
* 是否必须
*
* @return
*/
boolean required() default true;
String dataType() default "";

View File

@@ -0,0 +1,49 @@
package net.lab1024.smartadmin.common.anno;
import net.lab1024.smartadmin.module.system.datascope.constant.DataScopeTypeEnum;
import net.lab1024.smartadmin.module.system.datascope.constant.DataScopeWhereInTypeEnum;
import net.lab1024.smartadmin.module.system.datascope.strategy.DataScopePowerStrategy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* [ 数据范围 ]
*
* @author yandanyang
* @version 1.0
* @company 1024lab.net
* @copyright (c) 2019 1024lab.netInc. All rights reserved.
* @date
* @since JDK1.8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataScope {
DataScopeTypeEnum dataScopeType() default DataScopeTypeEnum.DEFAULT;
DataScopeWhereInTypeEnum whereInType() default DataScopeWhereInTypeEnum.EMPLOYEE;
/**
* DataScopeWhereInTypeEnum.CUSTOM_STRATEGY类型 才可使用joinSqlImplClazz属性
* @return
*/
Class<? extends DataScopePowerStrategy> joinSqlImplClazz() default DataScopePowerStrategy.class;
/**
*
* 第几个where 条件 从0开始
* @return
*/
int whereIndex() default 0;
/**
* DataScopeWhereInTypeEnum为CUSTOM_STRATEGY类型时此属性无效
* @return
*/
String joinSql() default "";
}

View File

@@ -1,4 +1,4 @@
package com.gangquan360.smartadmin.common.anno;
package net.lab1024.smartadmin.common.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@@ -1,4 +1,4 @@
package com.gangquan360.smartadmin.common.anno;
package net.lab1024.smartadmin.common.anno;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

View File

@@ -1,4 +1,4 @@
package com.gangquan360.smartadmin.common.anno;
package net.lab1024.smartadmin.common.anno;
import java.lang.annotation.*;

View File

@@ -1,7 +1,7 @@
package com.gangquan360.smartadmin.common.constant;
package net.lab1024.smartadmin.common.constant;
import com.gangquan360.smartadmin.common.domain.BaseEnum;
import net.lab1024.smartadmin.common.domain.BaseEnum;
/**
* 全局排序枚举类

View File

@@ -1,6 +1,6 @@
package com.gangquan360.smartadmin.common.constant;
package net.lab1024.smartadmin.common.constant;
import com.gangquan360.smartadmin.common.domain.BaseEnum;
import net.lab1024.smartadmin.common.domain.BaseEnum;
import java.util.Arrays;
import java.util.Optional;

View File

@@ -1,14 +1,14 @@
package com.gangquan360.smartadmin.common.constant;
package net.lab1024.smartadmin.common.constant;
import com.gangquan360.smartadmin.module.department.DepartmentResponseCodeConst;
import com.gangquan360.smartadmin.module.employee.constant.EmployeeResponseCodeConst;
import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst;
import com.gangquan360.smartadmin.module.log.orderoperatelog.constant.OrderOperateLogOperateTypeConst;
import com.gangquan360.smartadmin.module.login.LoginResponseCodeConst;
import com.gangquan360.smartadmin.module.position.PositionResponseCodeConst;
import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeResponseCodeConst;
import com.gangquan360.smartadmin.module.role.basic.RoleResponseCodeConst;
import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigResponseCodeConst;
import net.lab1024.smartadmin.module.system.department.DepartmentResponseCodeConst;
import net.lab1024.smartadmin.module.system.employee.constant.EmployeeResponseCodeConst;
import net.lab1024.smartadmin.module.support.file.constant.FileResponseCodeConst;
import net.lab1024.smartadmin.module.business.log.orderoperatelog.constant.OrderOperateLogOperateTypeConst;
import net.lab1024.smartadmin.module.system.login.LoginResponseCodeConst;
import net.lab1024.smartadmin.module.system.position.PositionResponseCodeConst;
import net.lab1024.smartadmin.module.system.privilege.constant.PrivilegeResponseCodeConst;
import net.lab1024.smartadmin.module.system.role.basic.RoleResponseCodeConst;
import net.lab1024.smartadmin.module.system.systemconfig.constant.SystemConfigResponseCodeConst;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
@@ -37,9 +37,7 @@ public class ResponseCodeConst {
}
public static final ResponseCodeConst SUCCESS = new ResponseCodeConst(1, "success", true);
public static final ResponseCodeConst COMMON_ERROR = new ResponseCodeConst(2, "我错了....");
public static final ResponseCodeConst SUCCESS = new ResponseCodeConst(1, "操作成功!", true);
public static final ResponseCodeConst ERROR_PARAM = new ResponseCodeConst(101, "参数异常!");

View File

@@ -0,0 +1,42 @@
package net.lab1024.smartadmin.common.controller;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
/**
* @author: zhuoda
* @create: 2020-03-31 08:54 PM from win10
*/
@Slf4j
public class BaseController {
/**
* 下载 Excel 消息头
* @param fileName
* @param workbook
* @param response
*/
public void downloadExcel(String fileName, Workbook workbook, HttpServletResponse response) {
try {
fileName = URLEncoder.encode(fileName, "UTF-8");
} catch (UnsupportedEncodingException e) {
log.error("", e);
}
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xls");
try {
workbook.write(response.getOutputStream());
workbook.close();
} catch (IOException e) {
log.error("", e);
}
}
}

View File

@@ -1,9 +1,10 @@
package com.gangquan360.smartadmin.common.domain;
package net.lab1024.smartadmin.common.domain;
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
/**

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