79 Commits
v1.0 ... v2.2

Author SHA1 Message Date
2cc14e5f56 若依 2.2 2020-03-18 09:43:17 +08:00
505ee1d63e 添加一个打包Web工程bat 2020-03-15 21:00:53 +08:00
4bbdc1e87b 修复TagsView组件中,鼠标滚轮按下的时候,可以关闭不可关闭的tag 2020-03-15 20:25:58 +08:00
3b87128461 修复点击退出登录有时会无效问题 2020-03-15 20:13:33 +08:00
bc65e59fcb 修复charts切换侧边栏或者缩放窗口显示bug 2020-03-15 20:07:14 +08:00
56339214b6 升级element-ui版本到2.13.0 2020-03-15 20:00:01 +08:00
61142595c4 固定重定向路径表达式 2020-03-15 19:53:09 +08:00
af7aa35884 路由地址添加必填限制 2020-03-14 10:58:51 +08:00
109c64e7c2 批量替换表前缀调整 2020-03-13 22:14:58 +08:00
c0cd030d0f 批量替换表前缀修改 2020-03-13 21:41:57 +08:00
7604d59e49 修复通知公告批量删除异常问题 2020-03-13 21:24:26 +08:00
02062f31e9 通用http工具类 2020-03-13 21:18:41 +08:00
ab992f4848 修复防重复提交注解无效问题 2020-03-13 21:15:50 +08:00
baea48be68 调整包路径 2020-03-13 18:10:32 +08:00
1590e1068c 删除多余包 2020-03-13 18:07:02 +08:00
103583a847 个人信息创建时间获取属性值 2020-03-08 21:16:16 +08:00
166d5ec55f 修改个人信息,密码后redis中登录信息不会过期问题 2020-03-07 10:19:04 +08:00
09a3a971ff 操作日志排序调整 2020-03-07 10:11:22 +08:00
f18b3bc6be 代码生成字段描述可编辑 2020-02-28 20:29:19 +08:00
0c1a27769a 删除无用页面 2020-02-28 19:56:19 +08:00
bb1340ecc6 操作日志详细显示类型 2020-02-25 19:33:29 +08:00
759a0fcb32 导入表单击行数据时选中对应的复选框 2020-02-25 13:49:48 +08:00
9d45070429 设置mybatis全局的配置文件 2020-02-24 14:32:21 +08:00
cb0a4b78ee 若依 2.1 2020-02-24 09:28:16 +08:00
46a1695292 修复地址开关无效问题 2020-02-23 15:43:50 +08:00
b7107a4dba 用户手机邮箱必填&密码参数修改 2020-02-18 11:15:08 +08:00
c0cd2f61da 返回参数忽略密码字段 2020-02-17 15:07:27 +08:00
c0ca2f837c 修改密码更新缓存信息 2020-02-10 13:28:50 +08:00
891062a7de 配置文件增加redis属性password 2020-02-08 19:25:57 +08:00
554beaf6e7 修改在角色管理页修改菜单权限偶尔未选中问题 2020-02-08 18:30:09 +08:00
a5c170fa2a 修改同一页面el-upload和Editor时不显示问题。 2020-02-08 17:05:46 +08:00
5cdb4ecba5 修改用户个人资料同步缓存信息 2020-02-08 16:39:13 +08:00
d49ac2e0f8 成功登陆不恢复按钮,防止多次点击 2020-02-08 15:31:29 +08:00
c23c8ae248 README 2020-02-08 14:54:17 +08:00
140be61003 根据用户权限加载菜单数据树形结构 2020-02-08 14:49:46 +08:00
a5dce6cccc 防止db字段名为一个字母导致出现生成异常 2020-02-02 15:43:43 +08:00
f754a18676 添加新群号 2020-01-11 10:39:49 +08:00
0348349a86 Jackson日期反序列化时区问题 2020-01-03 16:57:35 +08:00
436f8eb737 部门顶级节点逻辑优化 2019-12-31 18:45:15 +08:00
d677cd11d1 修改部门树默认值为[] 2019-12-31 18:03:01 +08:00
9067369ce0 防止时间为空出现的异常 2019-12-31 17:24:34 +08:00
3436f77c4a request.js缺少Message引用 2019-12-31 17:18:56 +08:00
b9a97ef4aa 修改验证码记录提示错误 2019-12-31 17:04:19 +08:00
de870bd2fe 修改用户管理分页不正确的问题 2019-12-26 17:32:10 +08:00
61e48da354 规避上传头像控制台异常 2019-12-26 16:36:09 +08:00
3755597c76 添加一个默认空属性,用来判断节点显示 2019-12-26 15:59:03 +08:00
71c31dfd66 HTML过滤器不替换双引号为",防止json格式无效 2019-12-20 17:09:33 +08:00
8bc7296fb4 添加HTML过滤器,用于去除XSS漏洞隐患 2019-12-20 11:34:45 +08:00
2d992db62a 修复多数据源下enabled=false导致读取不到bean导致异常问题 2019-12-19 16:21:49 +08:00
687e67dbea 修正关键词错误 2019-12-16 11:26:39 +08:00
b508e6f202 新增用户导入 2019-12-11 18:12:00 +08:00
8216d4e839 阿里云服务器89元/年,双12年末特惠,爆款产品限时1折 2019-12-09 11:33:23 +08:00
d2854c73f0 代码生成vue文件修正 2019-12-04 10:23:48 +08:00
04289c6021 代码生成sql权限修正 2019-12-04 10:17:06 +08:00
80242d712b 代码生成vue文件修正 2019-12-04 10:08:42 +08:00
4e8b69c1d7 汉化错误页面 2019-12-03 19:18:22 +08:00
9f5ed82cdf 动态加载路由 页面刷新问题 2019-12-03 18:02:35 +08:00
b70024487a RedisCache的getCacheSet方法会移除元素的bug 2019-12-02 17:00:38 +08:00
2e2882b0d5 代码生成防止缓存内的数据没有及时写入到zip文件 2019-12-02 16:09:20 +08:00
bc827ef377 无法匹配到的页面返回跳转至404页,防止整个页面显示空白 2019-12-02 16:03:18 +08:00
fee8a5955b 若依 2.0 2019-12-02 09:28:11 +08:00
cef26e770e 系统退出删除用户缓存记录 2019-11-20 12:08:08 +08:00
9f97fd0953 添加jsencrypt实现参数的前端加密 2019-11-20 11:53:04 +08:00
3af0158d40 2019年度最受欢迎中国开源软件评选
请给若依/RuoYi 投票,谢谢。
2019-11-20 10:46:05 +08:00
018195e47b 用户上传头像实时同步缓存,无需重新登录 2019-11-19 16:08:30 +08:00
cdc56a663e 修改代码生成路由脚本错误 2019-11-19 15:22:06 +08:00
a46e5460a6 日志记录过滤特殊对象,防止转换异常 2019-11-19 15:16:55 +08:00
5d4b0e6b21 添加主目录添加/删除操作 2019-11-19 14:50:07 +08:00
e6cd9c430f 新增@RepeatSubmit注解,防止重复提交 2019-11-13 15:20:05 +08:00
bcee37b84b 若依 1.1 2019-11-11 08:59:15 +08:00
85c17f4563 修复文件上传多级目录识别问题 2019-11-01 09:33:27 +08:00
c0e7f31fac 阿里云服务器86元/年,双11冰点底价,错过再等1年 2019-10-24 11:12:56 +08:00
66d6a5d0b1 若依前后端分离群937441 2019-10-11 15:36:01 +08:00
e235d5aa57 新增在线用户 2019-10-11 10:50:47 +08:00
319dfc2de3 修改函数命名防止冲突 2019-10-09 17:21:43 +08:00
3ba458b108 去除上级菜单校验,默认为顶级 2019-10-09 10:41:53 +08:00
7c908e9a56 用户密码无法修改问题 2019-10-09 10:21:06 +08:00
fcacf93582 按钮类型显示权限标识 2019-10-09 10:20:21 +08:00
4b7400f272 前后端分离交流群 2019-10-08 10:49:39 +08:00
262 changed files with 17625 additions and 762 deletions

View File

@ -6,6 +6,8 @@
参考后台模板[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) 参考后台模板[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
> 阿里云服务器89元/年双12年末特惠爆款产品限时1折 [点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link)
> 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi) `(保持同步更新)`,如需其他版本,请移步 [项目扩展](http://doc.ruoyi.vip/ruoyi/document/xmkz.html) `(不定时更新)` > 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi) `(保持同步更新)`,如需其他版本,请移步 [项目扩展](http://doc.ruoyi.vip/ruoyi/document/xmkz.html) `(不定时更新)`
> 阿里云通用云产品1888优惠券 [点我领取](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)    腾讯云通用云产品2860优惠券 [点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)  `(仅限新用户)` > 阿里云通用云产品1888优惠券 [点我领取](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)    腾讯云通用云产品2860优惠券 [点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)  `(仅限新用户)`
@ -47,12 +49,12 @@
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/97fcdc766fa04c03722aef4b3d77f71e8d2.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/707825ad3f29de74a8d6d02fbd73ad631ea.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/642858372da91853c39e2d4746f036ea171.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/46be40cc6f01aa300eed53a19b5012bf484.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/8678d5204148e2610c9d02822274a961dcf.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/4284796d4cea240d181b8f2201813dda710.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/feb2b25a08bf9dd121b8f51274ae935ead6.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/3ecfac87a049f7fe36abbcaafb2c40d36cf.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td>
@ -63,16 +65,20 @@
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/c162686bf3a39e3cd6b4fd6b5919f515ebf.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/fdea1d8bb8625c27bf964176a2c8ebc6945.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/412fb931faa8b3e3de6f9cbbc5b7979cf36.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/509d2708cfd762b6e6339364cac1cc1970c.jpg"/></td>
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/up-f1fd681cc9d295db74e85ad6d2fe4389454.png"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
</tr>
<tr>
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/5f3d39a141f21f81b90536f391b8408f1fa.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-6d73c2140ce694e3de4c05035fdc1868d4c.png"/></td>
</tr> </tr>
</table> </table>
## 若依交流群 ## 若依前后端分离交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/12633588-blue.svg)](https://jq.qq.com/?_wv=1027&k=5PjgQ8e) 点击按钮入群。 QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH)点击按钮入群。

12
ruoyi-ui/bin/build.bat Normal file
View File

@ -0,0 +1,12 @@
@echo off
echo.
echo [<5B><>Ϣ] <20><><EFBFBD><EFBFBD>Web<65><62><EFBFBD>̣<EFBFBD><CCA3><EFBFBD><EFBFBD><EFBFBD>dist<73>ļ<EFBFBD><C4BC><EFBFBD>
echo.
%~d0
cd %~dp0
cd ..
npm run build:prod
pause

View File

@ -1,6 +1,6 @@
@echo off @echo off
echo. echo.
echo [<5B><>Ϣ] <20><><EFBFBD><EFBFBD>Web<EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>node_modules<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD> echo [<5B><>Ϣ] <20><>װWeb<EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>node_modules<EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>
echo. echo.
%~d0 %~d0

View File

@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "1.0.0", "version": "2.2.0",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
@ -40,27 +40,33 @@
"url": "https://gitee.com/y_project/RuoYi-Vue.git" "url": "https://gitee.com/y_project/RuoYi-Vue.git"
}, },
"dependencies": { "dependencies": {
"@riophae/vue-treeselect": "0.1.0", "@riophae/vue-treeselect": "0.4.0",
"vue-quill-editor": "3.0.6",
"vue-cropper": "0.4.9",
"axios": "0.18.1", "axios": "0.18.1",
"clipboard": "2.0.4",
"echarts": "4.2.1", "echarts": "4.2.1",
"element-ui": "2.11.1", "element-ui": "2.13.0",
"file-saver": "2.0.1",
"js-beautify": "^1.10.2",
"fuse.js": "3.4.4", "fuse.js": "3.4.4",
"js-cookie": "2.2.0", "js-cookie": "2.2.0",
"jsencrypt": "3.0.0-rc.1",
"normalize.css": "7.0.0", "normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"path-to-regexp": "2.4.0", "path-to-regexp": "2.4.0",
"screenfull": "4.2.0", "screenfull": "4.2.0",
"vue": "2.6.10", "vue": "2.6.10",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-quill-editor": "3.0.6",
"vue-cropper": "0.4.9",
"vue-router": "3.0.2", "vue-router": "3.0.2",
"vue-splitpane": "1.0.4", "vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0" "vuex": "3.1.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.0.0", "@babel/core": "7.0.0",
"@babel/register": "7.0.0", "@babel/register": "7.0.0",
"@babel/parser": "^7.7.4",
"@vue/cli-plugin-babel": "3.5.3", "@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "^3.9.1", "@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.5.3", "@vue/cli-plugin-unit-jest": "3.5.3",

View File

@ -0,0 +1,80 @@
import request from '@/utils/request'
// 查询定时任务调度列表
export function listJob(query) {
return request({
url: '/monitor/job/list',
method: 'get',
params: query
})
}
// 查询定时任务调度详细
export function getJob(jobId) {
return request({
url: '/monitor/job/' + jobId,
method: 'get'
})
}
// 新增定时任务调度
export function addJob(data) {
return request({
url: '/monitor/job',
method: 'post',
data: data
})
}
// 修改定时任务调度
export function updateJob(data) {
return request({
url: '/monitor/job',
method: 'put',
data: data
})
}
// 删除定时任务调度
export function delJob(jobId) {
return request({
url: '/monitor/job/' + jobId,
method: 'delete'
})
}
// 导出定时任务调度
export function exportJob(query) {
return request({
url: '/monitor/job/export',
method: 'get',
params: query
})
}
// 任务状态修改
export function changeJobStatus(jobId, status) {
const data = {
jobId,
status
}
return request({
url: '/monitor/job/changeStatus',
method: 'put',
data: data
})
}
// 定时任务立即执行一次
export function runJob(jobId, jobGroup) {
const data = {
jobId,
jobGroup
}
return request({
url: '/monitor/job/run',
method: 'put',
data: data
})
}

View File

@ -0,0 +1,35 @@
import request from '@/utils/request'
// 查询调度日志列表
export function listJobLog(query) {
return request({
url: '/monitor/jobLog/list',
method: 'get',
params: query
})
}
// 删除调度日志
export function delJobLog(jobLogId) {
return request({
url: '/monitor/jobLog/' + jobLogId,
method: 'delete'
})
}
// 清空调度日志
export function cleanJobLog() {
return request({
url: '/monitor/jobLog/clean',
method: 'delete'
})
}
// 导出调度日志
export function exportJobLog(query) {
return request({
url: '/monitor/jobLog/export',
method: 'get',
params: query
})
}

View File

@ -8,3 +8,28 @@ export function list(query) {
params: query params: query
}) })
} }
// 删除登录日志
export function delLogininfor(infoId) {
return request({
url: '/monitor/logininfor/' + infoId,
method: 'delete'
})
}
// 清空登录日志
export function cleanLogininfor() {
return request({
url: '/monitor/logininfor/clean',
method: 'delete'
})
}
// 导出登录日志
export function exportLogininfor(query) {
return request({
url: '/monitor/logininfor/export',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,18 @@
import request from '@/utils/request'
// 查询在线用户列表
export function list(query) {
return request({
url: '/monitor/online/list',
method: 'get',
params: query
})
}
// 强退用户
export function forceLogout(tokenId) {
return request({
url: '/monitor/online/' + tokenId,
method: 'delete'
})
}

View File

@ -8,3 +8,28 @@ export function list(query) {
params: query params: query
}) })
} }
// 删除操作日志
export function delOperlog(operId) {
return request({
url: '/monitor/operlog/' + operId,
method: 'delete'
})
}
// 清空操作日志
export function cleanOperlog() {
return request({
url: '/monitor/operlog/clean',
method: 'delete'
})
}
// 导出操作日志
export function exportOperlog(query) {
return request({
url: '/monitor/operlog/export',
method: 'get',
params: query
})
}

View File

@ -50,3 +50,12 @@ export function delConfig(configId) {
method: 'delete' method: 'delete'
}) })
} }
// 导出参数
export function exportConfig(query) {
return request({
url: '/system/config/export',
method: 'get',
params: query
})
}

View File

@ -50,3 +50,12 @@ export function delData(dictCode) {
method: 'delete' method: 'delete'
}) })
} }
// 导出字典数据
export function exportData(query) {
return request({
url: '/system/dict/data/export',
method: 'get',
params: query
})
}

View File

@ -42,3 +42,20 @@ export function delType(dictId) {
method: 'delete' method: 'delete'
}) })
} }
// 导出字典类型
export function exportType(query) {
return request({
url: '/system/dict/type/export',
method: 'get',
params: query
})
}
// 获取字典选择框列表
export function optionselect() {
return request({
url: '/system/dict/type/optionselect',
method: 'get'
})
}

View File

@ -42,3 +42,12 @@ export function delPost(postId) {
method: 'delete' method: 'delete'
}) })
} }
// 导出岗位
export function exportPost(query) {
return request({
url: '/system/post/export',
method: 'get',
params: query
})
}

View File

@ -64,3 +64,12 @@ export function delRole(roleId) {
method: 'delete' method: 'delete'
}) })
} }
// 导出角色
export function exportRole(query) {
return request({
url: '/system/role/export',
method: 'get',
params: query
})
}

View File

@ -1,4 +1,5 @@
import request from '@/utils/request' import request from '@/utils/request'
import { praseStrEmpty } from "@/utils/ruoyi";
// 查询用户列表 // 查询用户列表
export function listUser(query) { export function listUser(query) {
@ -12,7 +13,7 @@ export function listUser(query) {
// 查询用户详细 // 查询用户详细
export function getUser(userId) { export function getUser(userId) {
return request({ return request({
url: '/system/user/' + userId, url: '/system/user/' + praseStrEmpty(userId),
method: 'get' method: 'get'
}) })
} }
@ -43,6 +44,15 @@ export function delUser(userId) {
}) })
} }
// 导出用户
export function exportUser(query) {
return request({
url: '/system/user/export',
method: 'get',
params: query
})
}
// 用户密码重置 // 用户密码重置
export function resetUserPwd(userId, password) { export function resetUserPwd(userId, password) {
const data = { const data = {
@ -107,3 +117,11 @@ export function uploadAvatar(data) {
data: data data: data
}) })
} }
// 下载用户导入模板
export function importTemplate() {
return request({
url: '/system/user/importTemplate',
method: 'get'
})
}

View File

@ -0,0 +1,59 @@
import request from '@/utils/request'
// 查询生成表数据
export function listTable(query) {
return request({
url: '/tool/gen/list',
method: 'get',
params: query
})
}
// 查询db数据库列表
export function listDbTable(query) {
return request({
url: '/tool/gen/db/list',
method: 'get',
params: query
})
}
// 查询表详细信息
export function getGenTable(tableId) {
return request({
url: '/tool/gen/' + tableId,
method: 'get'
})
}
// 修改代码生成信息
export function updateGenTable(data) {
return request({
url: '/tool/gen',
method: 'put',
data: data
})
}
// 导入表
export function importTable(data) {
return request({
url: '/tool/gen/importTable',
method: 'post',
params: data
})
}
// 预览生成代码
export function previewTable(tableId) {
return request({
url: '/tool/gen/preview/' + tableId,
method: 'get'
})
}
// 删除表数据
export function delTable(tableId) {
return request({
url: '/tool/gen/' + tableId,
method: 'delete'
})
}

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575982282951" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="902" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M828.40625 90.125H195.59375C137.375 90.125 90.125 137.375 90.125 195.59375v632.8125c0 58.21875 47.25 105.46875 105.46875 105.46875h632.8125c58.21875 0 105.46875-47.25 105.46875-105.46875V195.59375c0-58.21875-47.25-105.46875-105.46875-105.46875z m52.734375 738.28125c0 29.16-23.57015625 52.734375-52.734375 52.734375H195.59375c-29.109375 0-52.734375-23.574375-52.734375-52.734375V195.59375c0-29.109375 23.625-52.734375 52.734375-52.734375h632.8125c29.16 0 52.734375 23.625 52.734375 52.734375v632.8125z" p-id="903"></path><path d="M421.52890625 709.55984375a36.28125 36.28125 0 0 1-27.55265625-12.66890625L205.17453125 476.613125a36.28546875 36.28546875 0 0 1 55.10109375-47.22890625l164.986875 192.4846875 342.16171875-298.48078125a36.2896875 36.2896875 0 0 1 47.70984375 54.68765625L445.3859375 700.6203125a36.3234375 36.3234375 0 0 1-23.85703125 8.93953125z" p-id="904"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577252187056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2508" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M747.59340925 691.12859384c11.51396329 0.25305413 22.43746719-0.21087818 40.74171707-1.51832482 29.35428085-2.10878421 35.84933734-2.36183835 46.47761114-0.8856895 24.71495444 3.37405491 41.12129828 21.76265671 32.47528161 47.95376084-85.57447632 258.19957947-442.00123984 249.76444099-628.67084683 50.73735554-153.47733892-159.33976008-153.09775772-414.41833795 0.92786545-573.42069196 159.71934128-162.67163983 424.03439521-166.59397897 565.78689185 0.63263534 80.38686649 94.81095318 108.34934958 169.16669549 89.11723508 230.57450162-15.01454608 47.99593598-50.61082928 77.68762207-119.77896259 114.63352789-4.89237973 2.65706845-29.35428085 15.52065436-35.84933652 19.02123633-46.94154346 25.30541465-63.51659033 41.20565021-62.20914449 58.45550757 2.95229856 39.13904114 24.16667102 52.7196135 70.98168823 53.81618115z m44.41100207 50.10472101c-19.82257471 1.43397372-32.05352527 1.940082-45.63409763 1.6448519-70.34905207-1.60267593-115.98314969-30.91478165-121.38163769-101.64341492-3.45840683-46.05585397 24.7571304-73.13264758 89.24376132-107.96976837 6.7902866-3.66928501 31.37871396-16.57504688 36.06021551-19.06341229 57.69634516-30.83042972 85.15271997-53.73183005 94.76877722-84.47790866 12.77923398-40.78389304-9.10994898-98.94417051-79.24812286-181.6507002-121.17075953-142.97559219-350.14258521-139.60153647-489.2380134 2.06660824-134.49827774 138.84237405-134.79350784 362.12048163-0.42175717 501.637667 158.53842169 168.99799328 451.9968783 181.18676788 534.57688175-11.80919339-4.68150156 0.2952301-10.71262573 0.67481131-18.72600705 1.26527069z" p-id="2509"></path><path d="M346.03865637 637.18588562a78.82636652 78.82636652 0 0 0 78.32025825-79.29029883c0-43.69401562-35.005823-79.29029883-78.32025825-79.29029882a78.82636652 78.82636652 0 0 0-78.36243338 79.29029882c0 43.69401562 35.005823 79.29029883 78.36243338 79.29029883z m0-51.7495729a27.07679361 27.07679361 0 0 1-26.5706845-27.54072593c0-15.30977536 11.97789643-27.54072593 26.5706845-27.54072592 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072592a27.07679361 27.07679361 0 0 1-26.57068533 27.54072593zM475.7289063 807.11174353a78.82636652 78.82636652 0 0 0 78.3624334-79.29029882c0-43.69401562-34.96364785-79.29029883-78.32025825-79.29029883a78.82636652 78.82636652 0 0 0-78.32025742 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029882z m0-51.74957208a27.07679361 27.07679361 0 0 1-26.57068532-27.54072674c0-15.30977536 12.06224753-27.54072593 26.57068532-27.54072593 14.59278892 0 26.57068533 12.23095057 26.57068453 27.54072593a27.07679361 27.07679361 0 0 1-26.57068453 27.54072674zM601.24376214 377.21492718a78.82636652 78.82636652 0 0 0 78.32025742-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025742-79.29029882a78.82636652 78.82636652 0 0 0-78.32025823 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025824 79.29029883z m1e-8-51.74957208a27.07679361 27.07679361 0 0 1-26.57068534-27.54072675c0-15.30977536 11.97789643-27.54072593 26.57068534-27.54072591 14.55061295 0 26.57068533 12.23095057 26.57068451 27.54072592a27.07679361 27.07679361 0 0 1-26.57068451 27.54072674zM378.80916809 433.85687983a78.82636652 78.82636652 0 0 0 78.32025824-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025824-79.29029802a78.82636652 78.82636652 0 0 0-78.32025742 79.29029802c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029883z m0-51.74957209a27.07679361 27.07679361 0 0 1-26.57068451-27.54072674c0-15.30977536 11.97789643-27.54072593 26.57068451-27.54072593 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072593a27.07679361 27.07679361 0 0 1-26.57068533 27.54072674z" p-id="2510"></path></svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -1 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h54.857v54.857H0V0zm0 73.143h54.857V128H0V73.143zm73.143 0H128V128H73.143V73.143zm27.428-18.286C115.72 54.857 128 42.577 128 27.43 128 12.28 115.72 0 100.571 0 85.423 0 73.143 12.28 73.143 27.429c0 15.148 12.28 27.428 27.428 27.428z"/></svg> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575804206892" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3145" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M826.56 470.016c-32.896 0-64.384 12.288-89.984 35.52l0-104.96c0-62.208-50.496-112.832-112.64-113.088L623.936 287.04 519.552 287.104C541.824 262.72 554.56 230.72 554.56 197.12c0-73.536-59.904-133.44-133.504-133.44-73.472 0-133.376 59.904-133.376 133.44 0 32.896 12.224 64.256 35.52 89.984L175.232 287.104l0 0.576C113.728 288.704 64 338.88 64 400.576l0.32 0 0.32 116.48C60.864 544.896 70.592 577.728 100.8 588.48c12.736 4.608 37.632 7.488 60.864-25.28 12.992-18.368 34.24-29.248 56.64-29.248 38.336 0 69.504 31.104 69.504 69.312 0 38.4-31.168 69.504-69.504 69.504-22.656 0-44.032-11.264-57.344-30.4C138.688 610.112 112.576 615.36 102.464 619.136c-29.824 10.752-39.104 43.776-38.144 67.392l0 160.384L64 846.912C64 909.248 114.752 960 177.216 960l446.272 0c62.4 0 113.152-50.752 113.152-113.152l0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.536 0 133.44-59.904 133.44-133.504C960 529.92 900.096 470.016 826.56 470.016zM826.56 672.896c-22.72 0-44.032-11.264-57.344-30.4-22.272-32.384-48.448-27.136-58.56-23.36-29.824 10.752-39.04 43.776-38.08 67.392l0 160.384c0 27.136-22.016 49.152-49.152 49.152L177.216 896.064C150.08 896 128 873.984 128 846.848l0.32 0 0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.6 0 133.504-59.904 133.504-133.504 0-73.472-59.904-133.376-133.504-133.376-32.896 0-64.32 12.288-89.984 35.52l0-104.96L128 400.512c0-27.072 22.08-49.152 49.216-49.152L177.216 351.04 334.656 350.72c3.776 0.512 7.616 0.832 11.52 0.832 24.896 0 50.752-10.816 60.032-37.056 4.544-12.736 7.424-37.568-25.344-60.736C362.624 240.768 351.68 219.52 351.68 197.12c0-38.272 31.104-69.44 69.376-69.44 38.336 0 69.504 31.168 69.504 69.44 0 22.72-11.264 44.032-30.528 57.472C427.968 276.736 433.088 302.784 436.8 313.024c10.752 29.888 43.072 39.232 67.392 38.08l119.232 0 0 0.384c27.136 0 49.152 22.08 49.152 49.152l0.256 116.48c-3.776 27.84 6.016 60.736 36.224 71.488 12.736 4.608 37.632 7.488 60.8-25.28 13.056-18.368 34.24-29.248 56.704-29.248C864.832 534.016 896 565.12 896 603.392 896 641.728 864.832 672.896 826.56 672.896z" p-id="3146"></path></svg>

Before

Width:  |  Height:  |  Size: 319 B

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774833889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1376" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M887.466667 192.853333h-100.693334V119.466667c0-10.24-6.826667-17.066667-17.066666-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H303.786667V119.466667c0-10.24-6.826667-17.066667-17.066667-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H168.96c-46.08 0-85.333333 37.546667-85.333333 85.333334V836.266667c0 46.08 37.546667 85.333333 85.333333 85.333333H887.466667c46.08 0 85.333333-37.546667 85.333333-85.333333V278.186667c0-47.786667-37.546667-85.333333-85.333333-85.333334z m-718.506667 34.133334h100.693333v66.56c0 10.24 6.826667 17.066667 17.066667 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56h450.56v66.56c0 10.24 6.826667 17.066667 17.066666 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56H887.466667c27.306667 0 51.2 22.186667 51.2 51.2v88.746666H117.76v-88.746666c0-29.013333 22.186667-51.2 51.2-51.2zM887.466667 887.466667H168.96c-27.306667 0-51.2-22.186667-51.2-51.2V401.066667H938.666667V836.266667c0 27.306667-22.186667 51.2-51.2 51.2z" p-id="1377"></path><path d="M858.453333 493.226667H327.68c-10.24 0-17.066667 6.826667-17.066667 17.066666v114.346667h-116.053333c-10.24 0-17.066667 6.826667-17.066667 17.066667v133.12c0 10.24 6.826667 17.066667 17.066667 17.066666H460.8c10.24 0 17.066667-6.826667 17.066667-17.066666v-114.346667h380.586666c10.24 0 17.066667-6.826667 17.066667-17.066667v-133.12c0-10.24-6.826667-17.066667-17.066667-17.066666z m-413.013333 34.133333v97.28h-98.986667v-97.28h98.986667z m-230.4 131.413333h98.986667v98.986667h-98.986667v-98.986667z m131.413333 97.28v-97.28h98.986667v97.28h-98.986667z m133.12-228.693333h97.28v98.986667h-97.28v-98.986667z m131.413334 0h98.986666v98.986667h-98.986666v-98.986667z m230.4 97.28h-98.986667v-98.986667h98.986667v98.986667z" p-id="1378"></path></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1567417179372" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1155" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M947.2 1024 76.8 1024C38.4 1024 0 992 0 953.6L0 172.8c0-38.4 38.4-70.4 76.8-70.4l38.4 0 0 102.4c0 38.4 38.4 70.4 76.8 70.4l76.8 0c44.8 0 76.8-32 76.8-70.4L345.6 102.4l313.6 0 0 102.4c0 38.4 38.4 70.4 76.8 70.4l76.8 0c44.8 0 76.8-32 76.8-70.4L889.6 102.4l38.4 0c44.8 0 76.8 32 76.8 70.4l0 787.2C1024 992 985.6 1024 947.2 1024zM352 339.2 115.2 339.2 115.2 512l236.8 0L352 339.2zM352 544 115.2 544l0 172.8 236.8 0L352 544zM352 748.8 115.2 748.8l0 172.8 236.8 0L352 748.8zM627.2 339.2 396.8 339.2 396.8 512l236.8 0L633.6 339.2zM627.2 544 396.8 544l0 172.8 236.8 0L633.6 544zM627.2 748.8 396.8 748.8l0 172.8 236.8 0L633.6 748.8zM908.8 339.2l-236.8 0L672 512l236.8 0L908.8 339.2zM908.8 544l-236.8 0 0 172.8 236.8 0L908.8 544zM908.8 748.8l-236.8 0 0 172.8 236.8 0L908.8 748.8zM787.2 236.8c-44.8 0-76.8-32-76.8-70.4L710.4 70.4c0-38.4 38.4-70.4 76.8-70.4s76.8 32 76.8 70.4l0 102.4C864 211.2 832 236.8 787.2 236.8zM236.8 236.8C192 236.8 160 211.2 160 172.8L160 70.4C160 32 192 0 236.8 0s76.8 32 76.8 70.4l0 102.4C313.6 211.2 281.6 236.8 236.8 236.8z" p-id="1156"></path></svg> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577186573535" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1068" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M479.85714249 608.42857168h64.28571502c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285751s-12.85714249-32.14285751-32.14285664-32.14285664h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285662s12.85714249 32.14285751 32.14285664 32.14285753z m-2e-8 122.14285665h64.28571504c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285665s-12.85714249-32.14285751-32.14285664-32.14285751h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285751s12.85714249 32.14285751 32.14285664 32.14285664z m353.57142921-559.28571416h-128.57142921v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285664-32.14285753s-32.14285751 12.85714249-32.14285751 32.14285753v32.14285664h-257.14285665v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285752-32.14285753s-32.14285751 12.85714249-32.14285664 32.14285753v32.14285664h-128.57142919c-70.71428585 0-128.57142832 57.85714249-128.57142832 122.14285751v501.42857081c0 70.71428585 57.85714249 128.57142832 128.57142832 122.14285751h642.85714335c70.71428585 0 128.57142832-57.85714249 128.57142833-122.14285751v-501.42857081c0-70.71428585-57.85714249-122.14285753-128.57142833-122.14285751z m64.28571415 623.57142832c0 32.14285751-32.14285751 64.28571415-64.28571416 64.28571504h-642.85714335c-32.14285751 0-64.28571415-25.71428583-64.28571417-64.28571504v-372.85714249h771.42857168v372.85714249z m0-437.14285664h-771.42857168v-64.28571417c0-32.14285751 32.14285751-64.28571415 64.28571417-64.28571415h128.57142919v32.14285664c0 19.28571417 12.85714249 32.14285751 32.14285664 32.14285751s32.14285751-12.85714249 32.14285753-32.14285751v-32.14285664h257.14285665v32.14285664c0 19.28571417 12.85714249 32.14285751 32.1428575 32.14285751s32.14285751-12.85714249 32.14285664-32.14285751v-32.14285664h128.57142921c32.14285751 0 64.28571415 25.71428583 64.28571415 64.28571415v64.28571417z m-610.71428583 372.85714247h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285664s-12.85714249-32.14285751-32.14285753-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285751s12.85714249 32.14285751 32.14285751 32.14285665z m385.71428583-122.14285664h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285751s-12.85714249-32.14285751-32.14285751-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285664s12.85714249 32.14285751 32.14285753 32.14285751z m-385.71428583 0h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285751s-12.85714249-32.14285751-32.14285753-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285664s12.85714249 32.14285751 32.14285751 32.14285751z m385.71428583 122.14285665h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285665s-12.85714249-32.14285751-32.14285751-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285751s12.85714249 32.14285751 32.14285753 32.14285665z" p-id="1069"></path></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1581238998885" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4187" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M511.542857 14.057143C228.914286 13.942857 0 242.742857 0 525.142857 0 748.457143 143.2 938.285714 342.628571 1008c26.857143 6.742857 22.742857-12.342857 22.742858-25.371429v-88.571428c-155.085714 18.171429-161.371429-84.457143-171.771429-101.6C172.571429 756.571429 122.857143 747.428571 137.714286 730.285714c35.314286-18.171429 71.314286 4.571429 113.028571 66.171429 30.171429 44.685714 89.028571 37.142857 118.857143 29.714286 6.514286-26.857143 20.457143-50.857143 39.657143-69.485715-160.685714-28.8-227.657143-126.857143-227.657143-243.428571 0-56.571429 18.628571-108.571429 55.2-150.514286-23.314286-69.142857 2.171429-128.342857 5.6-137.142857 66.4-5.942857 135.428571 47.542857 140.8 51.771429 37.714286-10.171429 80.8-15.542857 129.028571-15.542858 48.457143 0 91.657143 5.6 129.714286 15.885715 12.914286-9.828571 76.914286-55.771429 138.628572-50.171429 3.314286 8.8 28.228571 66.628571 6.285714 134.857143 37.028571 42.057143 55.885714 94.514286 55.885714 151.2 0 116.8-67.428571 214.971429-228.571428 243.314286a145.714286 145.714286 0 0 1 43.542857 104v128.571428c0.914286 10.285714 0 20.457143 17.142857 20.457143 202.4-68.228571 348.114286-259.428571 348.114286-484.685714 0-282.514286-229.028571-511.2-511.428572-511.2z" p-id="4188"></path></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802859706" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3102" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 224H128c-35.2 0-64 28.8-64 64v448c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64z m0 480c0 19.2-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V320c0-19.2 12.8-32 32-32h704c19.2 0 32 12.8 32 32v384z" p-id="3103"></path><path d="M224 352c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32s32-12.8 32-32V384c0-16-12.8-32-32-32z" p-id="3104"></path></svg>

After

Width:  |  Height:  |  Size: 744 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802851180" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2867" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M279.272727 791.272727h512a46.545455 46.545455 0 0 1 0 93.090909H279.272727a46.545455 46.545455 0 0 1 0-93.090909z m33.838546-617.984V651.636364H193.722182V395.170909c0-37.003636-0.884364-59.298909-2.653091-66.746182a24.948364 24.948364 0 0 0-14.615273-16.989091c-8.005818-3.863273-25.786182-5.771636-53.341091-5.771636h-11.822545v-55.854545c57.716364-12.381091 101.562182-37.888 131.490909-76.520728h70.283636z m303.709091 396.8V651.636364H354.164364v-68.235637c77.777455-127.255273 124.043636-206.010182 138.705454-236.218182 14.661818-30.254545 22.016-53.853091 22.016-70.74909 0-13.032727-2.234182-22.714182-6.656-29.137455-4.421818-6.376727-11.170909-9.588364-20.247273-9.588364a22.248727 22.248727 0 0 0-20.200727 10.612364c-4.468364 7.121455-6.656 21.178182-6.656 42.263273v45.521454H354.164364v-17.454545c0-26.763636 1.396364-47.941818 4.142545-63.348364 2.746182-15.499636 9.541818-30.72 20.386909-45.661091 10.798545-14.987636 24.901818-26.298182 42.216727-33.978182 17.361455-7.68 38.167273-11.543273 62.37091-11.543272 47.476364 0 83.316364 11.776 107.706181 35.328 24.296727 23.552 36.445091 53.341091 36.445091 89.367272 0 27.368727-6.842182 56.32-20.48 86.853819-13.730909 30.533818-54.039273 95.325091-121.018182 194.420363h130.885819z m270.615272-189.393454c18.152727 6.097455 31.650909 16.104727 40.494546 29.975272 8.843636 13.917091 13.312 46.452364 13.312 97.652364 0 38.027636-4.328727 67.490909-13.032727 88.529455-8.657455 20.945455-23.598545 36.910545-44.869819 47.848727-21.271273 10.938182-48.593455 16.384-81.873454 16.384-37.794909 0-67.490909-6.330182-89.088-19.083636-21.550545-12.660364-35.746909-28.253091-42.542546-46.638546-6.795636-18.432-10.193455-50.362182-10.193454-95.883636v-37.841455h119.389091v77.730909c0 20.666182 1.210182 33.838545 3.723636 39.424 2.420364 5.585455 7.912727 8.424727 16.337455 8.424728 9.309091 0 15.36-3.537455 18.338909-10.612364 2.932364-7.121455 4.421818-25.6 4.421818-55.575273v-33.047273c0-18.338909-2.048-31.744-6.190546-40.215272a30.72 30.72 0 0 0-18.338909-16.709818c-8.052364-2.653091-23.738182-4.189091-46.964363-4.561455V357.050182c28.392727 0 45.893818-1.070545 52.596363-3.258182a22.946909 22.946909 0 0 0 14.475637-14.149818c2.932364-7.307636 4.421818-18.711273 4.421818-34.257455v-26.624c0-16.756364-1.722182-27.741091-5.12-33.047272-3.490909-5.352727-8.843636-8.005818-16.151273-8.005819-8.285091 0-13.963636 2.792727-16.989091 8.378182-3.025455 5.632-4.561455 17.640727-4.561454 35.933091v39.284364h-119.389091v-40.773818c0-45.661091 10.472727-76.567273 31.325091-92.625455 20.898909-16.058182 54.085818-24.064 99.607272-24.064 56.878545 0 95.511273 11.170909 115.805091 33.373091 20.293818 22.248727 30.394182 53.201455 30.394182 92.765091 0 26.810182-3.630545 46.173091-10.891636 58.088727-7.307636 11.915636-20.107636 22.807273-38.446546 32.628364z" p-id="2868"></path></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1 +1 @@
<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z"/></svg> <?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802846045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.593046 403.832442c-30.081109-28.844955-70.037123-44.753273-112.624057-44.753273L265.949606 359.079168c-42.554188 0-82.510202 15.908318-112.469538 44.690852-30.236652 28.782533-46.857191 67.222007-46.857191 108.198258l0 294.079782c0 40.977273 16.619516 79.414701 46.702672 108.136859 29.959336 28.844955 70.069869 44.814672 112.624057 44.814672l490.019383 0c42.585911 0 82.696444-15.969717 112.624057-44.814672 30.082132-28.844955 46.579875-67.222007 46.579875-108.136859L915.172921 511.968278C915.171897 471.053426 898.675178 432.677397 868.593046 403.832442zM841.821309 806.049083c0 22.098297-8.882298 42.772152-25.099654 58.306964-16.154935 15.661701-37.81935 24.203238-60.752666 24.203238L265.949606 888.559285c-22.934339 0-44.567032-8.54256-60.877509-24.264637-16.186657-15.474436-25.067932-36.148291-25.067932-58.246589L180.004165 511.968278c0-22.035876 8.881274-42.772152 25.192775-58.307987 16.186657-15.536858 37.81935-24.139793 60.753689-24.139793l490.019383 0c22.933315 0 44.597731 8.602935 60.752666 24.139793 16.21838 15.535835 25.099654 36.272112 25.099654 58.307987L841.822332 806.049083zM510.974136 135.440715c114.914216 0 208.318536 89.75214 208.318536 200.055338l73.350588 0c0-149.113109-126.366036-270.496667-281.669124-270.496667-155.333788 0-281.699824 121.383558-281.699824 270.496667l73.350588 0C302.623877 225.193879 396.059919 135.440715 510.974136 135.440715zM474.299865 747.244792l73.350588 0L547.650453 629.576859l-73.350588 0L474.299865 747.244792z" p-id="2751"></path></svg>

Before

Width:  |  Height:  |  Size: 623 B

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1581238842264" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1409" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 0C229.233778 0 0 229.233778 0 512s229.233778 512 512 512 512-229.233778 512-512A512 512 0 0 0 512 0z m0 938.666667C276.366222 938.666667 85.333333 747.633778 85.333333 512 85.333333 276.366222 276.366222 85.333333 512 85.333333c235.633778 0 426.666667 191.032889 426.666667 426.666667a426.666667 426.666667 0 0 1-426.666667 426.666667z m0-717.653334a170.666667 170.666667 0 0 0-170.666667 170.666667 42.666667 42.666667 0 0 0 85.333334 0 85.333333 85.333333 0 1 1 85.333333 85.333333 42.666667 42.666667 0 0 0-42.666667 42.666667v111.36a42.666667 42.666667 0 0 0 85.333334 0v-74.24A170.666667 170.666667 0 0 0 512 221.013333z m-42.666667 542.293334a42.666667 42.666667 0 1 0 85.333334 0 42.666667 42.666667 0 0 0-85.333334 0z" p-id="1410"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575966775973" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="879" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M507.39346659 71.84873358c241.53533667 0 437.39770766 195.85422109 437.39770767 437.37442191 0 241.53766571-195.86237099 437.38955776-437.39770767 437.38955776-241.50040803 0-437.34997219-195.85189205-437.34997219-437.38955776C70.0434944 267.70295467 265.89189347 71.84873358 507.39346659 71.84873358L507.39346659 71.84873358zM507.39346659 282.81899805c-125.00686734 0-226.37039389 101.38914133-226.37039388 226.41813048 0 125.01268821 101.36352768 226.39717262 226.37039388 226.39717262 125.04295993 0 226.42395136-101.38448441 226.42395136-226.39717262C733.81625401 384.20813938 632.43642653 282.81899805 507.39346659 282.81899805L507.39346659 282.81899805zM507.39346659 120.78172615c-214.46664192 0-388.42047261 173.95150279-388.4204726 388.44026539 0 214.51204949 173.95499463 388.46122325 388.4204726 388.46122325 214.52369237 0 388.46005817-173.94800981 388.46005818-388.46122325C895.85236082 294.73322894 721.91715897 120.78172615 507.39346659 120.78172615z" p-id="880"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577246781606" class="icon" viewBox="0 0 1069 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1098" xmlns:xlink="http://www.w3.org/1999/xlink" width="84.5595703125" height="81"><defs><style type="text/css"></style></defs><path d="M633.72929961 378.02038203l9.49872568 18.68789795 20.78025469 2.79745225 206.61592412 27.33248408a11.46496817 11.46496817 0 0 1 6.6095543 19.47324902l-147.2675168 147.35350284-14.89299345 14.89299345 3.8006376 20.68280244 37.84585956 204.89044571a11.46496817 11.46496817 0 0 1-16.4808914 12.2961788L554.68980898 751.84713388l-18.68789794-9.49299345-18.48726123 9.99171915-183.23885392 99.34968163a11.46496817 11.46496817 0 0 1-16.78471347-11.8662416l32.5433127-205.79617881 3.29617793-20.78598692-15.19108243-14.49172002-151.03375839-143.48407587a11.46496817 11.46496817 0 0 1 6.09936328-19.63949062l205.79617881-32.63503185 20.78598691-3.2961788L428.87898125 380.72038203 518.59235674 192.64331182a11.46496817 11.46496817 0 0 1 20.56815264-0.26369385l94.56879023 185.63503183zM496.64840732 85.52038203l-121.75796162 254.98089229L95.76433145 384.76178369A34.3949045 34.3949045 0 0 0 77.46050938 443.66879023l204.87324901 194.66369385-44.16879023 279.1146498a34.3949045 34.3949045 0 0 0 50.36560489 35.61592325l248.4-134.67898038 251.84522285 128.27579591a34.3949045 34.3949045 0 0 0 49.43694287-36.89426777l-51.30573223-277.85350284 199.73120977-199.90891758a34.3949045 34.3949045 0 0 0-19.82866201-58.40827998l-280.11783428-37.03184736L558.32993633 84.71210205a34.3949045 34.3949045 0 0 0-61.68152901 0.80254775z" p-id="1099"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579339929870" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1182" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M152 854.856875h325.7146875V237.715625H134.856875v600q0 6.99375 5.0746875 12.0684375T152 854.856875z m737.143125-17.1421875v-600H546.284375v617.1421875H872q6.99375 0 12.0684375-5.07375t5.0746875-12.0684375z m68.5715625-651.429375V837.715625q0 35.3821875-25.16625 60.5484375T872 923.4284375H152q-35.383125 0-60.5484375-25.1653125T66.284375 837.7146875V186.284375q0-35.3821875 25.16625-60.5484375T152 100.5715625h720q35.383125 0 60.5484375 25.1653125t25.16625 60.5484375z" p-id="1183"></path></svg>

After

Width:  |  Height:  |  Size: 873 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575803481213" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="804" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M62 511.97954521C62 263.86590869 263.90681826 62 511.97954521 62s449.97954521 201.825 449.97954521 449.97954521c0 248.19545479-201.90681826 449.97954521-449.97954521 449.97954521C263.90681826 962 62 760.175 62 511.97954521M901.98636348 511.97954521c0-215.24318174-175.00909131-390.41590869-390.00681827-390.41590869-215.03863652 0-389.96590869 175.17272695-389.96590868 390.41590869 0 215.28409131 175.00909131 390.45681826 389.96590868 390.45681826C727.01818174 902.47727305 901.98636348 727.30454521 901.98636348 511.97954521M264.17272695 430.28409131c0-5.76818174 2.12727305-11.51590869 6.64772696-15.87272696 8.71363652-8.75454521 22.88863652-8.75454521 31.725 0l209.4340913 208.22727305L721.45454521 414.53409131c8.75454521-8.71363652 22.97045479-8.71363652 31.90909132 0 8.71363652 8.75454521 8.71363652 22.88863652 0 31.60227304L511.97954521 685.74090869 270.71818174 446.01363653C266.27954521 441.77954521 264.17272695 436.05227305 264.17272695 430.28409131" p-id="805"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577185310368" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1238" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M951.453125 476.84375H523.671875a131.8359375 131.8359375 0 0 0-254.1796875 0H72.546875v70.3125h196.9453125a131.8359375 131.8359375 0 0 0 254.1796875 0H951.453125z" p-id="1239"></path></svg>

After

Width:  |  Height:  |  Size: 564 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576042673958" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1110" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M692 792H332c-150 0-270-120-270-270s120-270 270-270h360c150 0 270 120 270 270 0 147-120 270-270 270zM332 312c-117 0-210 93-210 210s93 210 210 210h360c117 0 210-93 210-210s-93-210-210-210H332z" p-id="1111"></path><path d="M341 522m-150 0a150 150 0 1 0 300 0 150 150 0 1 0-300 0Z" p-id="1112"></path></svg>

After

Width:  |  Height:  |  Size: 679 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802855098" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2984" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 160H128c-35.2 0-64 28.8-64 64v576c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64z m0 608c0 16-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V256c0-16 12.8-32 32-32h704c19.2 0 32 12.8 32 32v512z" p-id="2985"></path><path d="M224 288c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32s32-12.8 32-32V320c0-16-12.8-32-32-32z m608 480c19.2 0 32-12.8 32-32V608L704 768h128z" p-id="2986"></path></svg>

After

Width:  |  Height:  |  Size: 787 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774825624" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1248" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M498.595712 482.290351 345.420077 482.290351l0 57.307194 210.477712 0L555.897789 274.196942l-57.301054 0L498.596735 482.290351zM498.595712 482.290351" p-id="1249"></path><path d="M577.685002 644.98478l379.879913 0 0 57.302077L577.685002 702.286858 577.685002 644.98478 577.685002 644.98478zM577.685002 644.98478" p-id="1250"></path><path d="M577.685002 773.764795l379.879913 0 0 57.307194L577.685002 831.071989 577.685002 773.764795 577.685002 773.764795zM577.685002 773.764795" p-id="1251"></path><path d="M577.685002 902.549927l379.879913 0 0 57.307194L577.685002 959.857121 577.685002 902.549927 577.685002 902.549927zM577.685002 902.549927" p-id="1252"></path><path d="M102.523001 382.290823c4.450359 2.615571 9.470699 3.954055 14.530948 3.954055 2.969635 0 5.952572-0.461511 8.836249-1.394766l190.809767-61.886489c15.052834-4.882194 23.297612-21.040199 18.415418-36.08894-4.882194-15.052834-21.040199-23.297612-36.093033-18.415418L175.676092 308.458257c15.994276-26.115797 35.170011-50.537 57.370639-72.743768 73.767074-73.767074 171.845857-114.388237 276.16783-114.388237 104.32095 0 202.39564 40.622186 276.16169 114.388237s114.393353 171.845857 114.393353 276.16783c0 26.427906-2.615571 52.449559-7.709589 77.780481l58.302871 0c4.464685-25.499767 6.708795-51.470255 6.708795-77.780481 0-60.449767-11.845793-119.102608-35.204803-174.336584-22.559808-53.334719-54.850236-101.226472-95.968725-142.349055-41.122583-41.122583-89.017406-73.408917-142.348032-95.968725C628.317169 75.866898 569.659211 64.021106 509.215584 64.021106c-60.448744 0-119.106702 11.845793-174.336584 35.207873-53.334719 22.559808-101.230566 54.846142-142.349055 95.968725-23.980157 23.980157-44.934398 50.278103-62.727647 78.601172l-20.738323-105.655342c-3.043313-15.527648-18.105357-25.642007-33.631982-22.599717-15.527648 3.048429-25.64303 18.105357-22.599717 33.637098l36.102243 183.932126C90.51348 371.153158 95.460142 378.13313 102.523001 382.290823L102.523001 382.290823zM102.523001 382.290823" p-id="1253"></path><path d="M126.020158 587.9416 67.768453 587.9416c5.759167 33.679054 15.368012 66.544579 28.789697 98.278327 22.559808 53.333696 54.850236 101.225449 95.971795 142.348032 41.122583 41.122583 89.014336 73.408917 142.349055 95.968725 54.112432 22.88829 111.517863 34.71157 170.668031 35.18229L505.547031 902.395408c-102.94972-0.941442-199.594851-41.445948-272.499277-114.349351C177.545672 732.543975 140.810003 663.275355 126.020158 587.9416L126.020158 587.9416zM126.020158 587.9416" p-id="1254"></path></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577099827399" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1008" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M520 559h204c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32H488c-17.673 0-32-14.327-32-32 0-0.167 0.001-0.334 0.004-0.5a32.65 32.65 0 0 1-0.004-0.5V277c0-17.673 14.327-32 32-32 17.673 0 32 14.327 32 32v282z m-8 401C264.576 960 64 759.424 64 512S264.576 64 512 64s448 200.576 448 448-200.576 448-448 448z m0-64c212.077 0 384-171.923 384-384S724.077 128 512 128 128 299.923 128 512s171.923 384 384 384z" p-id="1009"></path></svg>

After

Width:  |  Height:  |  Size: 805 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577540289643" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7922" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M530.944 458.24l4.8 3.456 122.176 106.816a32 32 0 0 1-37.44 51.584l-4.672-3.392L546.56 556.16v280.704a32 32 0 0 1-26.24 31.488l-5.76 0.512a32 32 0 0 1-31.424-26.24l-0.512-5.76-0.064-280.704-69.12 60.48a32 32 0 0 1-40.96 0.896l-4.16-3.968a32 32 0 0 1-0.96-40.96l4.032-4.16 122.176-106.816a32 32 0 0 1 37.312-3.456zM497.92 128c128.128 0 239.168 82.304 275.52 199.04 123.968 11.264 221.312 113.088 221.312 237.44 0 128.128-103.68 232.96-234.88 238.272h-5.888l-35.52 0.192a32 32 0 0 1-0.192-64l35.264-0.128 4.672-0.064c96.384-3.84 172.544-80.896 172.544-174.272 0-96.128-80.512-174.464-179.584-174.464h-1.984a32 32 0 0 1-32-25.28C695.872 264.96 604.736 192 497.92 192 381.824 192 285.44 277.76 274.816 388.48a32 32 0 0 1-28.352 28.8c-83.968 9.152-147.84 78.208-147.84 159.552l0.192 7.936c3.84 85.76 77.056 154.112 166.592 154.112h45.632a32 32 0 0 1 0 64h-45.632C142.016 802.944 40.32 708.032 34.88 586.88l-0.192-9.28c0-106.88 76.352-197.184 179.968-219.904C239.488 226.112 357.76 128 497.856 128z" p-id="7923"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -77,3 +77,8 @@
.el-range-editor.el-input__inner { .el-range-editor.el-input__inner {
display: inline-flex !important; display: inline-flex !important;
} }
// to fix el-date-picker css style
.el-range-separator {
box-sizing: content-box;
}

View File

@ -3,6 +3,60 @@
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
/** 基础通用 **/
.pt5 {
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
}
.mt5 {
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
}
.mb8 {
margin-bottom: 8px;
}
.ml5 {
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
}
.ml0 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
}
.m20 {
margin-left: 20px;
}
.el-dialog {
margin-top: 6vh !important;
}
.el-table .el-table__header-wrapper th { .el-table .el-table__header-wrapper th {
word-break: break-word; word-break: break-word;
background-color: #f8f8f9; background-color: #f8f8f9;
@ -11,6 +65,16 @@
font-size: 13px; font-size: 13px;
} }
/** 表单布局 **/
.form-header {
font-size:15px;
color:#6379bb;
border-bottom:1px solid #ddd;
margin:8px 10px 25px 10px;
padding-bottom:5px
}
/** 表格布局 **/
.pagination-container { .pagination-container {
position: relative; position: relative;
height: 25px; height: 25px;

View File

@ -149,7 +149,7 @@ export default {
line-height: normal !important; line-height: normal !important;
height: 192px; height: 192px;
} }
.el-upload { .quill-img {
display: none; display: none;
} }
.ql-snow .ql-tooltip[data-mode="link"]::before { .ql-snow .ql-tooltip[data-mode="link"]::before {

View File

@ -0,0 +1,21 @@
<template>
<div>
<svg-icon icon-class="question" @click="goto"/>
</div>
</template>
<script>
export default {
name: 'RuoYiDoc',
data() {
return {
url: 'http://doc.ruoyi.vip/ruoyi-vue'
}
},
methods: {
goto() {
window.open(this.url)
}
}
}
</script>

View File

@ -1,19 +1,19 @@
<template> <template>
<div> <div>
<svg-icon icon-class="download" @click="handleDownload"/> <svg-icon icon-class="github" @click="goto"/>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'RuoYi', name: 'RuoYiGit',
data() { data() {
return { return {
url: 'https://gitee.com/y_project/RuoYi-Vue' url: 'https://gitee.com/y_project/RuoYi-Vue'
} }
}, },
methods: { methods: {
handleDownload() { goto() {
window.open(this.url) window.open(this.url)
} }
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" /> <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"> <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
<use :xlink:href="iconName" /> <use :href="iconName" />
</svg> </svg>
</template> </template>

View File

@ -8,8 +8,12 @@
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<el-tooltip content="下载源码" effect="dark" placement="bottom"> <el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi id="ruoyi" class="right-menu-item hover-effect" /> <ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
@ -32,8 +36,8 @@
<el-dropdown-item> <el-dropdown-item>
<span @click="setting = true">布局设置</span> <span @click="setting = true">布局设置</span>
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item divided> <el-dropdown-item divided @click.native="logout">
<span @click="logout">退出登录</span> <span>退出登录</span>
</el-dropdown-item> </el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</el-dropdown> </el-dropdown>
@ -48,7 +52,8 @@ import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch' import Search from '@/components/HeaderSearch'
import RuoYi from '@/components/RuoYi' import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
export default { export default {
components: { components: {
@ -57,7 +62,8 @@ export default {
Screenfull, Screenfull,
SizeSelect, SizeSelect,
Search, Search,
RuoYi RuoYiGit,
RuoYiDoc
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="!item.hidden" class="menu-wrapper"> <div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">

View File

@ -9,16 +9,16 @@
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }" :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
tag="span" tag="span"
class="tags-view-item" class="tags-view-item"
@click.middle.native="closeSelectedTag(tag)" @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)" @contextmenu.prevent.native="openMenu(tag,$event)"
> >
{{ tag.title }} {{ tag.title }}
<span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /> <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link> </router-link>
</scroll-pane> </scroll-pane>
<ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"> <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
<li @click="refreshSelectedTag(selectedTag)">刷新页面</li> <li @click="refreshSelectedTag(selectedTag)">刷新页面</li>
<li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">关闭当前</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前</li>
<li @click="closeOthersTags">关闭其他</li> <li @click="closeOthersTags">关闭其他</li>
<li @click="closeAllTags(selectedTag)">关闭所有</li> <li @click="closeAllTags(selectedTag)">关闭所有</li>
</ul> </ul>
@ -69,6 +69,9 @@ export default {
isActive(route) { isActive(route) {
return route.path === this.$route.path return route.path === this.$route.path
}, },
isAffix(tag) {
return tag.meta && tag.meta.affix
},
filterAffixTags(routes, basePath = '/') { filterAffixTags(routes, basePath = '/') {
let tags = [] let tags = []
routes.forEach(route => { routes.forEach(route => {
@ -155,7 +158,7 @@ export default {
toLastView(visitedViews, view) { toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0] const latestView = visitedViews.slice(-1)[0]
if (latestView) { if (latestView) {
this.$router.push(latestView) this.$router.push(latestView.fullPath)
} else { } else {
// now the default is to redirect to the home page if there is no tags-view, // now the default is to redirect to the home page if there is no tags-view,
// you can adjust it according to your needs. // you can adjust it according to your needs.

View File

@ -18,16 +18,18 @@ import './assets/icons' // icon
import './permission' // permission control import './permission' // permission control
import { getDicts } from "@/api/system/dict/data"; import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config"; import { getConfigKey } from "@/api/system/config";
import { dateFormat, resetForm, addDateRange, selectDictLabel } from "@/utils/ruoyi"; import { parseTime, resetForm, addDateRange, selectDictLabel, download, handleTree } from "@/utils/ruoyi";
import Pagination from "@/components/Pagination"; import Pagination from "@/components/Pagination";
// 全局方法挂载 // 全局方法挂载
Vue.prototype.getDicts = getDicts Vue.prototype.getDicts = getDicts
Vue.prototype.getConfigKey = getConfigKey Vue.prototype.getConfigKey = getConfigKey
Vue.prototype.dateFormat = dateFormat Vue.prototype.parseTime = parseTime
Vue.prototype.resetForm = resetForm Vue.prototype.resetForm = resetForm
Vue.prototype.addDateRange = addDateRange Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree
Vue.prototype.msgSuccess = function (msg) { Vue.prototype.msgSuccess = function (msg) {
this.$message({ showClose: true, message: msg, type: "success" }); this.$message({ showClose: true, message: msg, type: "success" });

View File

@ -32,7 +32,7 @@ export const constantRoutes = [
hidden: true, hidden: true,
children: [ children: [
{ {
path: '/redirect/:path*', path: '/redirect/:path(.*)',
component: () => import('@/views/redirect') component: () => import('@/views/redirect')
} }
] ]
@ -74,7 +74,7 @@ export const constantRoutes = [
{ {
path: 'profile', path: 'profile',
component: () => import('@/views/system/user/profile/index'), component: () => import('@/views/system/user/profile/index'),
name: '个人中心', name: 'Profile',
meta: { title: '个人中心', icon: 'user' } meta: { title: '个人中心', icon: 'user' }
} }
] ]
@ -87,10 +87,36 @@ export const constantRoutes = [
{ {
path: 'type/data/:dictId(\\d+)', path: 'type/data/:dictId(\\d+)',
component: () => import('@/views/system/dict/data'), component: () => import('@/views/system/dict/data'),
name: '字典数据', name: 'Data',
meta: { title: '字典数据', icon: '' } meta: { title: '字典数据', icon: '' }
} }
] ]
},
{
path: '/job',
component: Layout,
hidden: true,
children: [
{
path: 'log',
component: () => import('@/views/monitor/job/log'),
name: 'JobLog',
meta: { title: '调度日志' }
}
]
},
{
path: '/gen',
component: Layout,
hidden: true,
children: [
{
path: 'edit',
component: () => import('@/views/tool/gen/editTable'),
name: 'GenEdit',
meta: { title: '修改生成配置' }
}
]
} }
] ]

View File

@ -20,6 +20,7 @@ const permission = {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(res => {
const accessedRoutes = filterAsyncRouter(res.data) const accessedRoutes = filterAsyncRouter(res.data)
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', accessedRoutes) commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes) resolve(accessedRoutes)
}) })

View File

@ -28,13 +28,8 @@ const mutations = {
} }
}, },
DEL_CACHED_VIEW: (state, view) => { DEL_CACHED_VIEW: (state, view) => {
for (const i of state.cachedViews) { const index = state.cachedViews.indexOf(view.name)
if (i === view.name) { index > -1 && state.cachedViews.splice(index, 1)
const index = state.cachedViews.indexOf(i)
state.cachedViews.splice(index, 1)
break
}
}
}, },
DEL_OTHERS_VISITED_VIEWS: (state, view) => { DEL_OTHERS_VISITED_VIEWS: (state, view) => {
@ -43,12 +38,10 @@ const mutations = {
}) })
}, },
DEL_OTHERS_CACHED_VIEWS: (state, view) => { DEL_OTHERS_CACHED_VIEWS: (state, view) => {
for (const i of state.cachedViews) { if (index > -1) {
if (i === view.name) { state.cachedViews = state.cachedViews.slice(index, index + 1)
const index = state.cachedViews.indexOf(i) } else {
state.cachedViews = state.cachedViews.slice(index, index + 1) state.cachedViews = []
break
}
} }
}, },

View File

@ -0,0 +1,423 @@
export const formConf = {
formRef: 'elForm',
formModel: 'formData',
size: 'medium',
labelPosition: 'right',
labelWidth: 100,
formRules: 'rules',
gutter: 15,
disabled: false,
span: 24,
formBtns: true
}
export const inputComponents = [
{
label: '单行文本',
tag: 'el-input',
tagIcon: 'input',
placeholder: '请输入',
defaultValue: undefined,
span: 24,
labelWidth: null,
style: { width: '100%' },
clearable: true,
prepend: '',
append: '',
'prefix-icon': '',
'suffix-icon': '',
maxlength: null,
'show-word-limit': false,
readonly: false,
disabled: false,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/input'
},
{
label: '多行文本',
tag: 'el-input',
tagIcon: 'textarea',
type: 'textarea',
placeholder: '请输入',
defaultValue: undefined,
span: 24,
labelWidth: null,
autosize: {
minRows: 4,
maxRows: 4
},
style: { width: '100%' },
maxlength: null,
'show-word-limit': false,
readonly: false,
disabled: false,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/input'
},
{
label: '密码',
tag: 'el-input',
tagIcon: 'password',
placeholder: '请输入',
defaultValue: undefined,
span: 24,
'show-password': true,
labelWidth: null,
style: { width: '100%' },
clearable: true,
prepend: '',
append: '',
'prefix-icon': '',
'suffix-icon': '',
maxlength: null,
'show-word-limit': false,
readonly: false,
disabled: false,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/input'
},
{
label: '计数器',
tag: 'el-input-number',
tagIcon: 'number',
placeholder: '',
defaultValue: undefined,
span: 24,
labelWidth: null,
min: undefined,
max: undefined,
step: undefined,
'step-strictly': false,
precision: undefined,
'controls-position': '',
disabled: false,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
}
]
export const selectComponents = [
{
label: '下拉选择',
tag: 'el-select',
tagIcon: 'select',
placeholder: '请选择',
defaultValue: undefined,
span: 24,
labelWidth: null,
style: { width: '100%' },
clearable: true,
disabled: false,
required: true,
filterable: false,
multiple: false,
options: [{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/select'
},
{
label: '级联选择',
tag: 'el-cascader',
tagIcon: 'cascader',
placeholder: '请选择',
defaultValue: [],
span: 24,
labelWidth: null,
style: { width: '100%' },
props: {
props: {
multiple: false
}
},
'show-all-levels': true,
disabled: false,
clearable: true,
filterable: false,
required: true,
options: [{
id: 1,
value: 1,
label: '选项1',
children: [{
id: 2,
value: 2,
label: '选项1-1'
}]
}],
dataType: 'dynamic',
labelKey: 'label',
valueKey: 'value',
childrenKey: 'children',
separator: '/',
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
},
{
label: '单选框组',
tag: 'el-radio-group',
tagIcon: 'radio',
defaultValue: undefined,
span: 24,
labelWidth: null,
style: {},
optionType: 'default',
border: false,
size: 'medium',
disabled: false,
required: true,
options: [{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/radio'
},
{
label: '多选框组',
tag: 'el-checkbox-group',
tagIcon: 'checkbox',
defaultValue: [],
span: 24,
labelWidth: null,
style: {},
optionType: 'default',
border: false,
size: 'medium',
disabled: false,
required: true,
options: [{
label: '选项一',
value: 1
}, {
label: '选项二',
value: 2
}],
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
},
{
label: '开关',
tag: 'el-switch',
tagIcon: 'switch',
defaultValue: false,
span: 24,
labelWidth: null,
style: {},
disabled: false,
required: true,
'active-text': '',
'inactive-text': '',
'active-color': null,
'inactive-color': null,
'active-value': true,
'inactive-value': false,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/switch'
},
{
label: '滑块',
tag: 'el-slider',
tagIcon: 'slider',
defaultValue: null,
span: 24,
labelWidth: null,
disabled: false,
required: true,
min: 0,
max: 100,
step: 1,
'show-stops': false,
range: false,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/slider'
},
{
label: '时间选择',
tag: 'el-time-picker',
tagIcon: 'time',
placeholder: '请选择',
defaultValue: null,
span: 24,
labelWidth: null,
style: { width: '100%' },
disabled: false,
clearable: true,
required: true,
'picker-options': {
selectableRange: '00:00:00-23:59:59'
},
format: 'HH:mm:ss',
'value-format': 'HH:mm:ss',
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
},
{
label: '时间范围',
tag: 'el-time-picker',
tagIcon: 'time-range',
defaultValue: null,
span: 24,
labelWidth: null,
style: { width: '100%' },
disabled: false,
clearable: true,
required: true,
'is-range': true,
'range-separator': '至',
'start-placeholder': '开始时间',
'end-placeholder': '结束时间',
format: 'HH:mm:ss',
'value-format': 'HH:mm:ss',
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
},
{
label: '日期选择',
tag: 'el-date-picker',
tagIcon: 'date',
placeholder: '请选择',
defaultValue: null,
type: 'date',
span: 24,
labelWidth: null,
style: { width: '100%' },
disabled: false,
clearable: true,
required: true,
format: 'yyyy-MM-dd',
'value-format': 'yyyy-MM-dd',
readonly: false,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
},
{
label: '日期范围',
tag: 'el-date-picker',
tagIcon: 'date-range',
defaultValue: null,
span: 24,
labelWidth: null,
style: { width: '100%' },
type: 'daterange',
'range-separator': '至',
'start-placeholder': '开始日期',
'end-placeholder': '结束日期',
disabled: false,
clearable: true,
required: true,
format: 'yyyy-MM-dd',
'value-format': 'yyyy-MM-dd',
readonly: false,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
},
{
label: '评分',
tag: 'el-rate',
tagIcon: 'rate',
defaultValue: 0,
span: 24,
labelWidth: null,
style: {},
max: 5,
'allow-half': false,
'show-text': false,
'show-score': false,
disabled: false,
required: true,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/rate'
},
{
label: '颜色选择',
tag: 'el-color-picker',
tagIcon: 'color',
defaultValue: null,
labelWidth: null,
'show-alpha': false,
'color-format': '',
disabled: false,
required: true,
size: 'medium',
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
},
{
label: '上传',
tag: 'el-upload',
tagIcon: 'upload',
action: 'https://jsonplaceholder.typicode.com/posts/',
defaultValue: null,
labelWidth: null,
disabled: false,
required: true,
accept: '',
name: 'file',
'auto-upload': true,
showTip: false,
buttonText: '点击上传',
fileSize: 2,
sizeUnit: 'MB',
'list-type': 'text',
multiple: false,
regList: [],
changeTag: true,
document: 'https://element.eleme.cn/#/zh-CN/component/upload'
}
]
export const layoutComponents = [
{
layout: 'rowFormItem',
tagIcon: 'row',
type: 'default',
justify: 'start',
align: 'top',
label: '行容器',
layoutTree: true,
children: [],
document: 'https://element.eleme.cn/#/zh-CN/component/layout'
}
]
// 组件rule的触发方式无触发方式的组件不生成rule
export const trigger = {
'el-input': 'blur',
'el-input-number': 'blur',
'el-select': 'change',
'el-radio-group': 'change',
'el-checkbox-group': 'change',
'el-cascader': 'change',
'el-time-picker': 'change',
'el-date-picker': 'change',
'el-rate': 'change'
}

View File

@ -0,0 +1,18 @@
const styles = {
'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}',
'el-upload': '.el-upload__tip{line-height: 1.2;}'
}
function addCss(cssList, el) {
const css = styles[el.tag]
css && cssList.indexOf(css) === -1 && cssList.push(css)
if (el.children) {
el.children.forEach(el2 => addCss(cssList, el2))
}
}
export function makeUpCss(conf) {
const cssList = []
conf.fields.forEach(el => addCss(cssList, el))
return cssList.join('\n')
}

View File

@ -0,0 +1,29 @@
export default [
{
layout: 'colFormItem',
tagIcon: 'input',
label: '手机号',
vModel: 'mobile',
formId: 6,
tag: 'el-input',
placeholder: '请输入手机号',
defaultValue: '',
span: 24,
style: { width: '100%' },
clearable: true,
prepend: '',
append: '',
'prefix-icon': 'el-icon-mobile',
'suffix-icon': '',
maxlength: 11,
'show-word-limit': true,
readonly: false,
disabled: false,
required: true,
changeTag: true,
regList: [{
pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
message: '手机号格式错误'
}]
}
]

View File

@ -0,0 +1,338 @@
/* eslint-disable max-len */
import { trigger } from './config'
let confGlobal
let someSpanIsNot24
export function dialogWrapper(str) {
return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Titile">
${str}
<div slot="footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="handelConfirm">确定</el-button>
</div>
</el-dialog>`
}
export function vueTemplate(str) {
return `<template>
<div>
${str}
</div>
</template>`
}
export function vueScript(str) {
return `<script>
${str}
</script>`
}
export function cssStyle(cssStr) {
return `<style>
${cssStr}
</style>`
}
function buildFormTemplate(conf, child, type) {
let labelPosition = ''
if (conf.labelPosition !== 'right') {
labelPosition = `label-position="${conf.labelPosition}"`
}
const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>
${child}
${buildFromBtns(conf, type)}
</el-form>`
if (someSpanIsNot24) {
str = `<el-row :gutter="${conf.gutter}">
${str}
</el-row>`
}
return str
}
function buildFromBtns(conf, type) {
let str = ''
if (conf.formBtns && type === 'file') {
str = `<el-form-item size="large">
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>`
if (someSpanIsNot24) {
str = `<el-col :span="24">
${str}
</el-col>`
}
}
return str
}
// span不为24的用el-col包裹
function colWrapper(element, str) {
if (someSpanIsNot24 || element.span !== 24) {
return `<el-col :span="${element.span}">
${str}
</el-col>`
}
return str
}
const layouts = {
colFormItem(element) {
let labelWidth = ''
if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
labelWidth = `label-width="${element.labelWidth}px"`
}
const required = !trigger[element.tag] && element.required ? 'required' : ''
const tagDom = tags[element.tag] ? tags[element.tag](element) : null
let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>
${tagDom}
</el-form-item>`
str = colWrapper(element, str)
return str
},
rowFormItem(element) {
const type = element.type === 'default' ? '' : `type="${element.type}"`
const justify = element.type === 'default' ? '' : `justify="${element.justify}"`
const align = element.type === 'default' ? '' : `align="${element.align}"`
const gutter = element.gutter ? `gutter="${element.gutter}"` : ''
const children = element.children.map(el => layouts[el.layout](el))
let str = `<el-row ${type} ${justify} ${align} ${gutter}>
${children.join('\n')}
</el-row>`
str = colWrapper(element, str)
return str
}
}
const tags = {
'el-input': el => {
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
const readonly = el.readonly ? 'readonly' : ''
const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''
const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''
const showPassword = el['show-password'] ? 'show-password' : ''
const type = el.type ? `type="${el.type}"` : ''
const autosize = el.autosize && el.autosize.minRows
? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`
: ''
let child = buildElInputChild(el)
if (child) child = `\n${child}\n` // 换行
return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`
},
'el-input-number': el => {
const { disabled, vModel, placeholder } = attrBuilder(el)
const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
const min = el.min ? `:min='${el.min}'` : ''
const max = el.max ? `:max='${el.max}'` : ''
const step = el.step ? `:step='${el.step}'` : ''
const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
const precision = el.precision ? `:precision='${el.precision}'` : ''
return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`
},
'el-select': el => {
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const filterable = el.filterable ? 'filterable' : ''
const multiple = el.multiple ? 'multiple' : ''
let child = buildElSelectChild(el)
if (child) child = `\n${child}\n` // 换行
return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`
},
'el-radio-group': el => {
const { disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
let child = buildElRadioGroupChild(el)
if (child) child = `\n${child}\n` // 换行
return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`
},
'el-checkbox-group': el => {
const { disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
const min = el.min ? `:min="${el.min}"` : ''
const max = el.max ? `:max="${el.max}"` : ''
let child = buildElCheckboxGroupChild(el)
if (child) child = `\n${child}\n` // 换行
return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`
},
'el-switch': el => {
const { disabled, vModel } = attrBuilder(el)
const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''
const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`
},
'el-cascader': el => {
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const options = el.options ? `:options="${el.vModel}Options"` : ''
const props = el.props ? `:props="${el.vModel}Props"` : ''
const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
const filterable = el.filterable ? 'filterable' : ''
const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`
},
'el-slider': el => {
const { disabled, vModel } = attrBuilder(el)
const min = el.min ? `:min='${el.min}'` : ''
const max = el.max ? `:max='${el.max}'` : ''
const step = el.step ? `:step='${el.step}'` : ''
const range = el.range ? 'range' : ''
const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`
},
'el-time-picker': el => {
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
const isRange = el['is-range'] ? 'is-range' : ''
const format = el.format ? `format="${el.format}"` : ''
const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`
},
'el-date-picker': el => {
const {
disabled, vModel, clearable, placeholder, width
} = attrBuilder(el)
const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
const format = el.format ? `format="${el.format}"` : ''
const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
const type = el.type === 'date' ? '' : `type="${el.type}"`
const readonly = el.readonly ? 'readonly' : ''
return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`
},
'el-rate': el => {
const { disabled, vModel } = attrBuilder(el)
const max = el.max ? `:max='${el.max}'` : ''
const allowHalf = el['allow-half'] ? 'allow-half' : ''
const showText = el['show-text'] ? 'show-text' : ''
const showScore = el['show-score'] ? 'show-score' : ''
return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`
},
'el-color-picker': el => {
const { disabled, vModel } = attrBuilder(el)
const size = `size="${el.size}"`
const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`
},
'el-upload': el => {
const disabled = el.disabled ? ':disabled=\'true\'' : ''
const action = el.action ? `:action="${el.vModel}Action"` : ''
const multiple = el.multiple ? 'multiple' : ''
const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''
const accept = el.accept ? `accept="${el.accept}"` : ''
const name = el.name !== 'file' ? `name="${el.name}"` : ''
const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''
const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`
const fileList = `:file-list="${el.vModel}fileList"`
const ref = `ref="${el.vModel}"`
let child = buildElUploadChild(el)
if (child) child = `\n${child}\n` // 换行
return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`
}
}
function attrBuilder(el) {
return {
vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
clearable: el.clearable ? 'clearable' : '',
placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
disabled: el.disabled ? ':disabled=\'true\'' : ''
}
}
// el-input innerHTML
function buildElInputChild(conf) {
const children = []
if (conf.prepend) {
children.push(`<template slot="prepend">${conf.prepend}</template>`)
}
if (conf.append) {
children.push(`<template slot="append">${conf.append}</template>`)
}
return children.join('\n')
}
function buildElSelectChild(conf) {
const children = []
if (conf.options && conf.options.length) {
children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)
}
return children.join('\n')
}
function buildElRadioGroupChild(conf) {
const children = []
if (conf.options && conf.options.length) {
const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
const border = conf.border ? 'border' : ''
children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
}
return children.join('\n')
}
function buildElCheckboxGroupChild(conf) {
const children = []
if (conf.options && conf.options.length) {
const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
const border = conf.border ? 'border' : ''
children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
}
return children.join('\n')
}
function buildElUploadChild(conf) {
const list = []
if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')
else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)
if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">只能上传不超过 ${conf.fileSize}${conf.sizeUnit}${conf.accept}文件</div>`)
return list.join('\n')
}
export function makeUpHtml(conf, type) {
const htmlList = []
confGlobal = conf
someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
conf.fields.forEach(el => {
htmlList.push(layouts[el.layout](el))
})
const htmlStr = htmlList.join('\n')
let temp = buildFormTemplate(conf, htmlStr, type)
if (type === 'dialog') {
temp = dialogWrapper(temp)
}
confGlobal = null
return temp
}

View File

@ -0,0 +1 @@
["platform-eleme","eleme","delete-solid","delete","s-tools","setting","user-solid","user","phone","phone-outline","more","more-outline","star-on","star-off","s-goods","goods","warning","warning-outline","question","info","remove","circle-plus","success","error","zoom-in","zoom-out","remove-outline","circle-plus-outline","circle-check","circle-close","s-help","help","minus","plus","check","close","picture","picture-outline","picture-outline-round","upload","upload2","download","camera-solid","camera","video-camera-solid","video-camera","message-solid","bell","s-cooperation","s-order","s-platform","s-fold","s-unfold","s-operation","s-promotion","s-home","s-release","s-ticket","s-management","s-open","s-shop","s-marketing","s-flag","s-comment","s-finance","s-claim","s-custom","s-opportunity","s-data","s-check","s-grid","menu","share","d-caret","caret-left","caret-right","caret-bottom","caret-top","bottom-left","bottom-right","back","right","bottom","top","top-left","top-right","arrow-left","arrow-right","arrow-down","arrow-up","d-arrow-left","d-arrow-right","video-pause","video-play","refresh","refresh-right","refresh-left","finished","sort","sort-up","sort-down","rank","loading","view","c-scale-to-original","date","edit","edit-outline","folder","folder-opened","folder-add","folder-remove","folder-delete","folder-checked","tickets","document-remove","document-delete","document-copy","document-checked","document","document-add","printer","paperclip","takeaway-box","search","monitor","attract","mobile","scissors","umbrella","headset","brush","mouse","coordinate","magic-stick","reading","data-line","data-board","pie-chart","data-analysis","collection-tag","film","suitcase","suitcase-1","receiving","collection","files","notebook-1","notebook-2","toilet-paper","office-building","school","table-lamp","house","no-smoking","smoking","shopping-cart-full","shopping-cart-1","shopping-cart-2","shopping-bag-1","shopping-bag-2","sold-out","sell","present","box","bank-card","money","coin","wallet","discount","price-tag","news","guide","male","female","thumb","cpu","link","connection","open","turn-off","set-up","chat-round","chat-line-round","chat-square","chat-dot-round","chat-dot-square","chat-line-square","message","postcard","position","turn-off-microphone","microphone","close-notification","bangzhu","time","odometer","crop","aim","switch-button","full-screen","copy-document","mic","stopwatch","medal-1","medal","trophy","trophy-1","first-aid-kit","discover","place","location","location-outline","location-information","add-location","delete-location","map-location","alarm-clock","timer","watch-1","watch","lock","unlock","key","service","mobile-phone","bicycle","truck","ship","basketball","football","soccer","baseball","wind-power","light-rain","lightning","heavy-rain","sunrise","sunrise-1","sunset","sunny","cloudy","partly-cloudy","cloudy-and-sunny","moon","moon-night","dish","dish-1","food","chicken","fork-spoon","knife-fork","burger","tableware","sugar","dessert","ice-cream","hot-water","water-cup","coffee-cup","cold-drink","goblet","goblet-full","goblet-square","goblet-square-full","refrigerator","grape","watermelon","cherry","apple","pear","orange","coffee","ice-tea","ice-drink","milk-tea","potato-strips","lollipop","ice-cream-square","ice-cream-round"]

View File

@ -0,0 +1,236 @@
import { isArray } from 'util'
import { exportDefault, titleCase } from '@/utils/index'
import { trigger } from './config'
const units = {
KB: '1024',
MB: '1024 / 1024',
GB: '1024 / 1024 / 1024'
}
let confGlobal
const inheritAttrs = {
file: '',
dialog: 'inheritAttrs: false,'
}
export function makeUpJs(conf, type) {
confGlobal = conf = JSON.parse(JSON.stringify(conf))
const dataList = []
const ruleList = []
const optionsList = []
const propsList = []
const methodList = mixinMethod(type)
const uploadVarList = []
conf.fields.forEach(el => {
buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
})
const script = buildexport(
conf,
type,
dataList.join('\n'),
ruleList.join('\n'),
optionsList.join('\n'),
uploadVarList.join('\n'),
propsList.join('\n'),
methodList.join('\n')
)
confGlobal = null
return script
}
function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
buildData(el, dataList)
buildRules(el, ruleList)
if (el.options && el.options.length) {
buildOptions(el, optionsList)
if (el.dataType === 'dynamic') {
const model = `${el.vModel}Options`
const options = titleCase(model)
buildOptionMethod(`get${options}`, model, methodList)
}
}
if (el.props && el.props.props) {
buildProps(el, propsList)
}
if (el.action && el.tag === 'el-upload') {
uploadVarList.push(
`${el.vModel}Action: '${el.action}',
${el.vModel}fileList: [],`
)
methodList.push(buildBeforeUpload(el))
if (!el['auto-upload']) {
methodList.push(buildSubmitUpload(el))
}
}
if (el.children) {
el.children.forEach(el2 => {
buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
})
}
}
function mixinMethod(type) {
const list = []; const
minxins = {
file: confGlobal.formBtns ? {
submitForm: `submitForm() {
this.$refs['${confGlobal.formRef}'].validate(valid => {
if(!valid) return
// TODO 提交表单
})
},`,
resetForm: `resetForm() {
this.$refs['${confGlobal.formRef}'].resetFields()
},`
} : null,
dialog: {
onOpen: 'onOpen() {},',
onClose: `onClose() {
this.$refs['${confGlobal.formRef}'].resetFields()
},`,
close: `close() {
this.$emit('update:visible', false)
},`,
handelConfirm: `handelConfirm() {
this.$refs['${confGlobal.formRef}'].validate(valid => {
if(!valid) return
this.close()
})
},`
}
}
const methods = minxins[type]
if (methods) {
Object.keys(methods).forEach(key => {
list.push(methods[key])
})
}
return list
}
function buildData(conf, dataList) {
if (conf.vModel === undefined) return
let defaultValue
if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {
defaultValue = `'${conf.defaultValue}'`
} else {
defaultValue = `${JSON.stringify(conf.defaultValue)}`
}
dataList.push(`${conf.vModel}: ${defaultValue},`)
}
function buildRules(conf, ruleList) {
if (conf.vModel === undefined) return
const rules = []
if (trigger[conf.tag]) {
if (conf.required) {
const type = isArray(conf.defaultValue) ? 'type: \'array\',' : ''
let message = isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder
if (message === undefined) message = `${conf.label}不能为空`
rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)
}
if (conf.regList && isArray(conf.regList)) {
conf.regList.forEach(item => {
if (item.pattern) {
rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
}
})
}
ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
}
}
function buildOptions(conf, optionsList) {
if (conf.vModel === undefined) return
if (conf.dataType === 'dynamic') { conf.options = [] }
const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`
optionsList.push(str)
}
function buildProps(conf, propsList) {
if (conf.dataType === 'dynamic') {
conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)
conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)
conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)
}
const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`
propsList.push(str)
}
function buildBeforeUpload(conf) {
const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
returnList = []
if (conf.fileSize) {
rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
if(!isRightSize){
this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}')
}`
returnList.push('isRightSize')
}
if (conf.accept) {
acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
if(!isAccept){
this.$message.error('应该选择${conf.accept}类型的文件')
}`
returnList.push('isAccept')
}
const str = `${conf.vModel}BeforeUpload(file) {
${rightSizeCode}
${acceptCode}
return ${returnList.join('&&')}
},`
return returnList.length ? str : ''
}
function buildSubmitUpload(conf) {
const str = `submitUpload() {
this.$refs['${conf.vModel}'].submit()
},`
return str
}
function buildOptionMethod(methodName, model, methodList) {
const str = `${methodName}() {
// TODO 发起请求获取数据
this.${model}
},`
methodList.push(str)
}
function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
const str = `${exportDefault}{
${inheritAttrs[type]}
components: {},
props: [],
data () {
return {
${conf.formModel}: {
${data}
},
${conf.formRules}: {
${rules}
},
${uploadVar}
${selectOptions}
${props}
}
},
computed: {},
watch: {},
created () {},
mounted () {},
methods: {
${methods}
}
}`
return str
}

View File

@ -0,0 +1,121 @@
import { makeMap } from '@/utils/index'
// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
const isAttr = makeMap(
'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
+ 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
+ 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
+ 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
+ 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
+ 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
+ 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
+ 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
+ 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
+ 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
+ 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
+ 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
+ 'target,title,type,usemap,value,width,wrap'
)
function vModel(self, dataObject, defaultValue) {
dataObject.props.value = defaultValue
dataObject.on.input = val => {
self.$emit('input', val)
}
}
const componentChild = {
'el-input': {
prepend(h, conf, key) {
return <template slot="prepend">{conf[key]}</template>
},
append(h, conf, key) {
return <template slot="append">{conf[key]}</template>
}
},
'el-select': {
options(h, conf, key) {
const list = []
conf.options.forEach(item => {
list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
})
return list
}
},
'el-radio-group': {
options(h, conf, key) {
const list = []
conf.options.forEach(item => {
if (conf.optionType === 'button') list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
else list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
})
return list
}
},
'el-checkbox-group': {
options(h, conf, key) {
const list = []
conf.options.forEach(item => {
if (conf.optionType === 'button') {
list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
} else {
list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
}
})
return list
}
},
'el-upload': {
'list-type': (h, conf, key) => {
const list = []
if (conf['list-type'] === 'picture-card') {
list.push(<i class="el-icon-plus"></i>)
} else {
list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
}
if (conf.showTip) {
list.push(<div slot="tip" class="el-upload__tip">只能上传不超过 {conf.fileSize}{conf.sizeUnit} {conf.accept}文件</div>)
}
return list
}
}
}
export default {
render(h) {
const dataObject = {
attrs: {},
props: {},
on: {},
style: {}
}
const confClone = JSON.parse(JSON.stringify(this.conf))
const children = []
const childObjs = componentChild[confClone.tag]
if (childObjs) {
Object.keys(childObjs).forEach(key => {
const childFunc = childObjs[key]
if (confClone[key]) {
children.push(childFunc(h, confClone, key))
}
})
}
Object.keys(confClone).forEach(key => {
const val = confClone[key]
if (key === 'vModel') {
vModel(this, dataObject, confClone.defaultValue)
} else if (dataObject[key]) {
dataObject[key] = val
} else if (!isAttr(key)) {
dataObject.props[key] = val
} else {
dataObject.attrs[key] = val
}
})
return h(this.conf.tag, dataObject, children)
},
props: ['conf']
}

View File

@ -315,3 +315,72 @@ export function removeClass(ele, cls) {
ele.className = ele.className.replace(reg, ' ') ele.className = ele.className.replace(reg, ' ')
} }
} }
export function makeMap(str, expectsLowerCase) {
const map = Object.create(null)
const list = str.split(',')
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}
export const exportDefault = 'export default '
export const beautifierConf = {
html: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'separate',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: false,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
},
js: {
indent_size: '2',
indent_char: ' ',
max_preserve_newlines: '-1',
preserve_newlines: false,
keep_array_indentation: false,
break_chained_methods: false,
indent_scripts: 'normal',
brace_style: 'end-expand',
space_before_conditional: true,
unescape_strings: false,
jslint_happy: true,
end_with_newline: true,
wrap_line_length: '110',
indent_inner_html: true,
comma_first: false,
e4x: true,
indent_empty_lines: true
}
}
// 首字母大小
export function titleCase(str) {
return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}
// 下划转驼峰
export function camelCase(str) {
return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}

View File

@ -0,0 +1,30 @@
import JSEncrypt from 'jsencrypt/bin/jsencrypt'
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD\n' +
'2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=='
const privateKey = 'MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8\n' +
'mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9p\n' +
'B6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue\n' +
'/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZ\n' +
'UBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6\n' +
'vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha\n' +
'4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3\n' +
'tTbklZkD2A=='
// 加密
export function encrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 设置公钥
return encryptor.encrypt(txt) // 对需要加密的数据进行加密
}
// 解密
export function decrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey)
return encryptor.decrypt(txt)
}

View File

@ -1,16 +1,17 @@
import store from '@/store' import store from '@/store'
/** /**
* @param {Array} value * 字符权限校验
* @param {Array} value 校验值
* @returns {Boolean} * @returns {Boolean}
*/ */
export default function checkPermission(value) { export function checkPermi(value) {
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles const permissions = store.getters && store.getters.permissions
const permissionRoles = value const permissionDatas = value
const hasPermission = roles.some(role => { const hasPermission = permissions.some(permission => {
return permissionRoles.includes(role) return permissionDatas.includes(permission)
}) })
if (!hasPermission) { if (!hasPermission) {
@ -18,7 +19,31 @@ export default function checkPermission(value) {
} }
return true return true
} else { } else {
console.error(`need roles! Like v-permission="['admin','editor']"`) console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
return false
}
}
/**
* 角色权限校验
* @param {Array} value 校验值
* @returns {Boolean}
*/
export function checkRole(value) {
if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles
const permissionRoles = value
const hasRole = roles.some(role => {
return permissionRoles.includes(role)
})
if (!hasRole) {
return false
}
return true
} else {
console.error(`need roles! Like checkRole="['admin','editor']"`)
return false return false
} }
} }

View File

@ -1,5 +1,5 @@
import axios from 'axios' import axios from 'axios'
import { Notification, MessageBox } from 'element-ui' import { Notification, MessageBox, Message } from 'element-ui'
import store from '@/store' import store from '@/store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'

View File

@ -3,18 +3,50 @@
* Copyright (c) 2019 ruoyi * Copyright (c) 2019 ruoyi
*/ */
const baseURL = process.env.VUE_APP_BASE_API
// 日期格式化 // 日期格式化
export function dateFormat(date, pattern) { export function parseTime(time, pattern) {
var d = new Date(date).Format("yyyy-MM-dd hh:mm:ss"); if (arguments.length === 0 || !time) {
if (pattern) { return null
d = new Date(date).Format(pattern);
} }
return d.toLocaleString(); const format = pattern || '{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
} }
// 表单重置 // 表单重置
export function resetForm(refName) { export function resetForm(refName) {
if (this.$refs[refName] !== undefined) { if (this.$refs[refName]) {
this.$refs[refName].resetFields(); this.$refs[refName].resetFields();
} }
} }
@ -22,11 +54,11 @@ export function resetForm(refName) {
// 添加日期范围 // 添加日期范围
export function addDateRange(params, dateRange) { export function addDateRange(params, dateRange) {
var search = params; var search = params;
if (null != dateRange) { search.beginTime = "";
search.params = { search.endTime = "";
beginTime: this.dateRange[0], if (null != dateRange && '' != dateRange) {
endTime: this.dateRange[1] search.beginTime = this.dateRange[0];
}; search.endTime = this.dateRange[1];
} }
return search; return search;
} }
@ -43,6 +75,11 @@ export function selectDictLabel(datas, value) {
return actions.join(''); return actions.join('');
} }
// 通用下载方法
export function download(fileName) {
window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
}
// 字符串格式化(%s ) // 字符串格式化(%s )
export function sprintf(str) { export function sprintf(str) {
var args = arguments, flag = true, i = 1; var args = arguments, flag = true, i = 1;
@ -57,20 +94,39 @@ export function sprintf(str) {
return flag ? str : ''; return flag ? str : '';
} }
Date.prototype.Format = function (fmt) { // 转换字符串undefined,null等转化为""
var o = { export function praseStrEmpty(str) {
"M+": this.getMonth() + 1, // 月份 if (!str || str == "undefined" || str == "null") {
"d+": this.getDate(), // 日 return "";
"h+": this.getHours(), // 小时 }
"m+": this.getMinutes(), // 分 return str;
"s+": this.getSeconds(), // 秒
"q+": Math.floor((this.getMonth() + 3) / 3), // 季度
"S": this.getMilliseconds() // 毫秒
};
if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
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;
} }
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
* @param {*} rootId 根Id 默认 0
*/
export function handleTree(data, id, parentId, children, rootId) {
id = id || 'id'
parentId = parentId || 'parentId'
children = children || 'children'
rootId = rootId || 0
//对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
//循环所有项
const treeData = cloneData.filter(father => {
let branchArr = cloneData.filter(child => {
//返回每一项的子级数组
return father[id] === child[parentId]
});
branchArr.length > 0 ? father.children = branchArr : '';
//返回第一层
return father[parentId] === rootId;
});
return treeData != '' ? treeData : data;
}

View File

@ -0,0 +1,40 @@
import axios from 'axios'
import { getToken } from '@/utils/auth'
const mimeMap = {
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
zip: 'application/zip'
}
const baseUrl = process.env.VUE_APP_BASE_API
export function downLoadZip(str, filename) {
var url = baseUrl + str
axios({
method: 'get',
url: url,
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then(res => {
resolveBlob(res, mimeMap.zip)
})
}
/**
* 解析blob响应内容并下载
* @param {*} res blob响应内容
* @param {String} mimeType MIME类型
*/
export function resolveBlob(res, mimeType) {
const aLink = document.createElement('a')
var blob = new Blob([res.data], { type: mimeType })
// //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
var contentDisposition = decodeURI(res.headers['content-disposition'])
var result = patt.exec(contentDisposition)
var fileName = result[1]
fileName = fileName.replace(/\"/g, '')
aLink.href = URL.createObjectURL(blob)
aLink.setAttribute('download', fileName) // 设置下载文件名称
document.body.appendChild(aLink)
aLink.click()
document.body.appendChild(aLink)
}

View File

@ -1,74 +1,3 @@
const elementIcons = [ const elementIcons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round']
'info',
'error',
'success',
'warning',
'question',
'back',
'arrow-left',
'arrow-down',
'arrow-right',
'arrow-up',
'caret-left',
'caret-bottom',
'caret-top',
'caret-right',
'd-arrow-left',
'd-arrow-right',
'minus',
'plus',
'remove',
'circle-plus',
'remove-outline',
'circle-plus-outline',
'close',
'check',
'circle-close',
'circle-check',
'circle-close-outline',
'circle-check-outline',
'zoom-out',
'zoom-in',
'd-caret',
'sort',
'sort-down',
'sort-up',
'tickets',
'document',
'goods',
'sold-out',
'news',
'message',
'date',
'printer',
'time',
'bell',
'mobile-phone',
'service',
'view',
'menu',
'more',
'more-outline',
'star-on',
'star-off',
'location',
'location-outline',
'phone',
'phone-outline',
'picture',
'picture-outline',
'delete',
'search',
'edit',
'edit-outline',
'rank',
'refresh',
'share',
'setting',
'upload',
'upload2',
'download',
'loading'
]
export default elementIcons export default elementIcons

View File

@ -3,50 +3,54 @@ import { debounce } from '@/utils'
export default { export default {
data() { data() {
return { return {
$_sidebarElm: null $_sidebarElm: null,
$_resizeHandler: null
} }
}, },
mounted() { mounted() {
this.$_initResizeEvent() this.initListener()
this.$_initSidebarResizeEvent()
},
beforeDestroy() {
this.$_destroyResizeEvent()
this.$_destroySidebarResizeEvent()
}, },
activated() { activated() {
this.$_initResizeEvent() if (!this.$_resizeHandler) {
this.$_initSidebarResizeEvent() // avoid duplication init
this.initListener()
}
// when keep-alive chart activated, auto resize
this.resize()
},
beforeDestroy() {
this.destroyListener()
}, },
deactivated() { deactivated() {
this.$_destroyResizeEvent() this.destroyListener()
this.$_destroySidebarResizeEvent()
}, },
methods: { methods: {
$_resizeHandler() { // use $_ for mixins properties
return debounce(() => { // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
if (this.chart) {
this.chart.resize()
}
}, 100)()
},
$_initResizeEvent() {
window.addEventListener('resize', this.$_resizeHandler)
},
$_destroyResizeEvent() {
window.removeEventListener('resize', this.$_resizeHandler)
},
$_sidebarResizeHandler(e) { $_sidebarResizeHandler(e) {
if (e.propertyName === 'width') { if (e.propertyName === 'width') {
this.$_resizeHandler() this.$_resizeHandler()
} }
}, },
$_initSidebarResizeEvent() { initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
}, },
$_destroySidebarResizeEvent() { destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
resize() {
const { chart } = this
chart && chart.resize()
} }
} }
} }

View File

@ -6,31 +6,22 @@
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<h1 class="text-jumbo text-ginormous"> <h1 class="text-jumbo text-ginormous">
Oops! 401错误!
</h1> </h1>
gif来源<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 页面 <h2>您没有访问权限</h2>
<h2>你没有权限去该页面</h2> <h6>对不起您没有访问权限请不要进行非法操作您可以返回主页面</h6>
<h6>如有不满请联系你领导</h6>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li>或者你可以去:</li>
<li class="link-type"> <li class="link-type">
<router-link to="/dashboard"> <router-link to="/">
回首页 回首页
</router-link> </router-link>
</li> </li>
<li class="link-type">
<a href="https://www.taobao.com/">随便看看</a>
</li>
<li><a href="#" @click.prevent="dialogVisible=true">点我看图</a></li>
</ul> </ul>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream."> <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
</el-col> </el-col>
</el-row> </el-row>
<el-dialog :visible.sync="dialogVisible" title="随便看">
<img :src="ewizardClap" class="pan-img">
</el-dialog>
</div> </div>
</template> </template>
@ -41,15 +32,13 @@ export default {
name: 'Page401', name: 'Page401',
data() { data() {
return { return {
errGif: errGif + '?' + +new Date(), errGif: errGif + '?' + +new Date()
ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
dialogVisible: false
} }
}, },
methods: { methods: {
back() { back() {
if (this.$route.query.noGoBack) { if (this.$route.query.noGoBack) {
this.$router.push({ path: '/dashboard' }) this.$router.push({ path: '/' })
} else { } else {
this.$router.go(-1) this.$router.go(-1)
} }

View File

@ -8,13 +8,18 @@
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
</div> </div>
<div class="bullshit"> <div class="bullshit">
<div class="bullshit__oops">OOPS!</div> <div class="bullshit__oops">
<div class="bullshit__info">All rights reserved 404错误!
<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
</div> </div>
<div class="bullshit__headline">{{ message }}</div> <div class="bullshit__headline">
<div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div> {{ message }}
<a href="" class="bullshit__return-home">Back to home</a> </div>
<div class="bullshit__info">
对不起您正在寻找的页面不存在尝试检查URL的错误然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容
</div>
<router-link to="/" class="bullshit__return-home">
返回首页
</router-link>
</div> </div>
</div> </div>
</div> </div>
@ -26,7 +31,7 @@ export default {
name: 'Page404', name: 'Page404',
computed: { computed: {
message() { message() {
return 'The webmaster said that you can not enter this page...' return '找不到网页!'
} }
} }
} }

View File

@ -56,6 +56,7 @@
<script> <script>
import { getCodeImg } from "@/api/login"; import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
import { encrypt, decrypt } from '@/utils/jsencrypt'
export default { export default {
name: "Login", name: "Login",
@ -108,7 +109,7 @@ export default {
const rememberMe = Cookies.get('rememberMe') const rememberMe = Cookies.get('rememberMe')
this.loginForm = { this.loginForm = {
username: username === undefined ? this.loginForm.username : username, username: username === undefined ? this.loginForm.username : username,
password: password === undefined ? this.loginForm.password : password, password: password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe) rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
}; };
}, },
@ -118,7 +119,7 @@ export default {
this.loading = true; this.loading = true;
if (this.loginForm.rememberMe) { if (this.loginForm.rememberMe) {
Cookies.set("username", this.loginForm.username, { expires: 30 }); Cookies.set("username", this.loginForm.username, { expires: 30 });
Cookies.set("password", this.loginForm.password, { expires: 30 }); Cookies.set("password", encrypt(this.loginForm.password), { expires: 30 });
Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 }); Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
} else { } else {
Cookies.remove("username"); Cookies.remove("username");
@ -128,7 +129,6 @@ export default {
this.$store this.$store
.dispatch("Login", this.loginForm) .dispatch("Login", this.loginForm)
.then(() => { .then(() => {
this.loading = false;
this.$router.push({ path: this.redirect || "/" }); this.$router.push({ path: this.redirect || "/" });
}) })
.catch(() => { .catch(() => {

View File

@ -1,15 +0,0 @@
<script>
export default {
name: 'AuthRedirect',
created() {
const hash = window.location.search.slice(1)
if (window.localStorage) {
window.localStorage.setItem('x-admin-oauth-code', hash)
window.close()
}
},
render: function(h) {
return h() // avoid warning message
}
}
</script>

View File

@ -1,72 +0,0 @@
<template>
<div class="social-signup-container">
<div class="sign-btn" @click="wechatHandleClick('wechat')">
<span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon" /></span>
WeChat
</div>
<div class="sign-btn" @click="tencentHandleClick('tencent')">
<span class="qq-svg-container"><svg-icon icon-class="qq" class="icon" /></span>
QQ
</div>
</div>
</template>
<script>
// import openWindow from '@/utils/open-window'
export default {
name: 'SocialSignin',
methods: {
wechatHandleClick(thirdpart) {
alert('ok')
// this.$store.commit('SET_AUTH_TYPE', thirdpart)
// const appid = 'xxxxx'
// const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
// const url = 'https://open.weixin.qq.com/connect/qrconnect?appid=' + appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=snsapi_login#wechat_redirect'
// openWindow(url, thirdpart, 540, 540)
},
tencentHandleClick(thirdpart) {
alert('ok')
// this.$store.commit('SET_AUTH_TYPE', thirdpart)
// const client_id = 'xxxxx'
// const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
// const url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri
// openWindow(url, thirdpart, 540, 540)
}
}
}
</script>
<style lang="scss" scoped>
.social-signup-container {
margin: 20px 0;
.sign-btn {
display: inline-block;
cursor: pointer;
}
.icon {
color: #fff;
font-size: 24px;
margin-top: 8px;
}
.wx-svg-container,
.qq-svg-container {
display: inline-block;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
padding-top: 1px;
border-radius: 4px;
margin-bottom: 20px;
margin-right: 5px;
}
.wx-svg-container {
background-color: #24da70;
}
.qq-svg-container {
background-color: #6BA2D6;
margin-left: 50px;
}
}
</style>

View File

@ -5,6 +5,7 @@
</template> </template>
<script> <script>
export default { export default {
name: "Druid",
data() { data() {
return { return {
src: process.env.VUE_APP_BASE_API + "/druid/index.html", src: process.env.VUE_APP_BASE_API + "/druid/index.html",

View File

@ -1,5 +1,488 @@
<template> <template>
<div class="app-container"> <div class="app-container">
定时任务 <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable size="small">
<el-option
v-for="dict in jobGroupOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="任务状态" prop="status">
<el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable size="small">
<el-option
v-for="dict in statusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['monitor:job:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['monitor:job:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['monitor:job:export']"
>导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
icon="el-icon-s-operation"
size="mini"
@click="handleJobLog"
v-hasPermi="['monitor:job:query']"
>日志</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="任务编号" align="center" prop="jobId" />
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
<el-table-column label="任务组名" align="center" prop="jobGroup" :formatter="jobGroupFormat" />
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
<el-table-column label="状态" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-value="0"
inactive-value="1"
@change="handleStatusChange(scope.row)"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-caret-right"
@click="handleRun(scope.row)"
v-hasPermi="['monitor:job:edit']"
>执行一次</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
v-hasPermi="['monitor:job:query']"
>详细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改定时任务对话框 -->
<el-dialog :title="title" :visible.sync="open" width="700px">
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="12">
<el-form-item label="任务名称" prop="jobName">
<el-input v-model="form.jobName" placeholder="请输入任务名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组" prop="jobGroup">
<el-select v-model="form.jobGroup" placeholder="请选择">
<el-option
v-for="dict in jobGroupOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item prop="invokeTarget">
<span slot="label">
调用方法
<el-tooltip placement="top">
<div slot="content">
Bean调用示例ryTask.ryParams('ry')
<br />Class类调用示例com.ruoyi.quartz.task.RyTask.ryParams('ry')
<br />参数说明支持字符串布尔类型长整型浮点型整型
</div>
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="cron表达式" prop="cronExpression">
<el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否并发" prop="concurrent">
<el-radio-group v-model="form.concurrent" size="small">
<el-radio-button label="0">允许</el-radio-button>
<el-radio-button label="1">禁止</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="错误策略" prop="misfirePolicy">
<el-radio-group v-model="form.misfirePolicy" size="small">
<el-radio-button label="1">立即执行</el-radio-button>
<el-radio-button label="2">执行一次</el-radio-button>
<el-radio-button label="3">放弃执行</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in statusOptions"
:key="dict.dictValue"
:label="dict.dictValue"
>{{dict.dictLabel}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 任务日志详细 -->
<el-dialog title="任务详细" :visible.sync="openView" width="700px">
<el-form ref="form" :model="form" label-width="120px" size="mini">
<el-row>
<el-col :span="12">
<el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
<el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="cron表达式">{{ form.cronExpression }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务状态:">
<div v-if="form.status == 0">正常</div>
<div v-else-if="form.status == 1">失败</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否并发:">
<div v-if="form.status == 0">允许</div>
<div v-else-if="form.status == 1">禁止</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行策略:">
<div v-if="form.misfirePolicy == 0">默认策略</div>
<div v-else-if="form.misfirePolicy == 1">立即执行</div>
<div v-else-if="form.misfirePolicy == 2">执行一次</div>
<div v-else-if="form.misfirePolicy == 3">放弃执行</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="openView = false"> </el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script>
import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, changeJobStatus } from "@/api/monitor/job";
export default {
name: "Job",
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 定时任务表格数据
jobList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 是否显示详细弹出层
openView: false,
// 任务组名字典
jobGroupOptions: [],
// 状态字典
statusOptions: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
jobName: undefined,
jobGroup: undefined,
status: undefined
},
// 表单参数
form: {},
// 表单校验
rules: {
jobName: [
{ required: true, message: "任务名称不能为空", trigger: "blur" }
],
invokeTarget: [
{ required: true, message: "调用目标字符串不能为空", trigger: "blur" }
],
cronExpression: [
{ required: true, message: "cron执行表达式不能为空", trigger: "blur" }
]
}
};
},
created() {
this.getList();
this.getDicts("sys_job_group").then(response => {
this.jobGroupOptions = response.data;
});
this.getDicts("sys_job_status").then(response => {
this.statusOptions = response.data;
});
},
methods: {
/** 查询定时任务列表 */
getList() {
this.loading = true;
listJob(this.queryParams).then(response => {
this.jobList = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 任务组名字典翻译
jobGroupFormat(row, column) {
return this.selectDictLabel(this.jobGroupOptions, row.jobGroup);
},
// 状态字典翻译
statusFormat(row, column) {
return this.selectDictLabel(this.statusOptions, row.status);
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
jobId: undefined,
jobName: undefined,
jobGroup: undefined,
invokeTarget: undefined,
cronExpression: undefined,
misfirePolicy: 1,
concurrent: 1,
status: "0"
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.jobId);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
// 任务状态修改
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用";
this.$confirm('确认要"' + text + '""' + row.jobName + '"任务吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return changeJobStatus(row.jobId, row.status);
}).then(() => {
this.msgSuccess(text + "成功");
}).catch(function() {
row.status = row.status === "0" ? "1" : "0";
});
},
/* 立即执行一次 */
handleRun(row) {
this.$confirm('确认要立即执行一次"' + row.jobName + '"任务吗?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return runJob(row.jobId, row.jobGroup);
}).then(function() {
this.msgSuccess("执行成功");
}).catch(function() {});
},
/** 任务详细信息 */
handleView(row) {
getJob(row.jobId).then(response => {
this.form = response.data;
this.openView = true;
});
},
/** 任务日志列表查询 */
handleJobLog() {
this.$router.push("/job/log");
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加任务";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const jobId = row.jobId || this.ids;
getJob(jobId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改任务";
});
},
/** 提交按钮 */
submitForm: function() {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.jobId != undefined) {
updateJob(this.form).then(response => {
if (response.code === 200) {
this.msgSuccess("修改成功");
this.open = false;
this.getList();
} else {
this.msgError(response.msg);
}
});
} else {
addJob(this.form).then(response => {
if (response.code === 200) {
this.msgSuccess("新增成功");
this.open = false;
this.getList();
} else {
this.msgError(response.msg);
}
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const jobIds = row.jobId || this.ids;
this.$confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return delJob(jobIds);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
}).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm("是否确认导出所有定时任务数据项?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportJob(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
}
}
};
</script>

View File

@ -0,0 +1,295 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
placeholder="请输入任务名称"
clearable
size="small"
style="width: 240px"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="任务组名" prop="jobGroup">
<el-select
v-model="queryParams.jobGroup"
placeholder="请任务组名"
clearable
size="small"
style="width: 240px"
>
<el-option
v-for="dict in jobGroupOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="执行状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择执行状态"
clearable
size="small"
style="width: 240px"
>
<el-option
v-for="dict in statusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="执行时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:job:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="handleClean"
v-hasPermi="['monitor:job:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['monitor:jobLog:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
<el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
<el-table-column label="任务组名" align="center" prop="jobGroup" :formatter="jobGroupFormat" :show-overflow-tooltip="true" />
<el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
<el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
<el-table-column label="执行状态" align="center" prop="status" :formatter="statusFormat" />
<el-table-column label="执行时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
v-hasPermi="['monitor:job:query']"
>详细</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 调度日志详细 -->
<el-dialog title="调度日志详细" :visible.sync="open" width="700px">
<el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row>
<el-col :span="12">
<el-form-item label="日志序号:">{{ form.jobLogId }}</el-form-item>
<el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务分组:">{{ form.jobGroup }}</el-form-item>
<el-form-item label="执行时间:">{{ form.createTime }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="调用方法:">{{ form.invokeTarget }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="日志信息:">{{ form.jobMessage }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="执行状态:">
<div v-if="form.status == 0">正常</div>
<div v-else-if="form.status == 1">失败</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status == 1">{{ form.exceptionInfo }}</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="open = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/jobLog";
export default {
name: "JobLog",
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 调度日志表格数据
jobLogList: [],
// 是否显示弹出层
open: false,
// 日期范围
dateRange: [],
// 表单参数
form: {},
// 执行状态字典
statusOptions: [],
// 任务组名字典
jobGroupOptions: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
jobName: undefined,
jobGroup: undefined,
status: undefined
},
// 表单参数
form: {}
};
},
created() {
this.getList();
this.getDicts("sys_job_status").then(response => {
this.statusOptions = response.data;
});
this.getDicts("sys_job_group").then(response => {
this.jobGroupOptions = response.data;
});
},
methods: {
/** 查询调度日志列表 */
getList() {
this.loading = true;
listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.jobLogList = response.rows;
this.total = response.total;
this.loading = false;
}
);
},
// 执行状态字典翻译
statusFormat(row, column) {
return this.selectDictLabel(this.statusOptions, row.status);
},
// 任务组名字典翻译
jobGroupFormat(row, column) {
return this.selectDictLabel(this.jobGroupOptions, row.jobGroup);
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.jobLogId);
this.multiple = !selection.length;
},
/** 详细按钮操作 */
handleView(row) {
this.open = true;
this.form = row;
},
/** 删除按钮操作 */
handleDelete(row) {
const jobLogIds = this.ids;
this.$confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return delJobLog(jobLogIds);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
}).catch(function() {});
},
/** 清空按钮操作 */
handleClean() {
this.$confirm("是否确认清空所有调度日志数据项?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return cleanJobLog();
}).then(() => {
this.getList();
this.msgSuccess("清空成功");
}).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm("是否确认导出所有调度日志数据项?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportJobLog(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
}
}
};
</script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="登录地址"> <el-form-item label="登录地址" prop="ipaddr">
<el-input <el-input
v-model="queryParams.ipaddr" v-model="queryParams.ipaddr"
placeholder="请输入登录地址" placeholder="请输入登录地址"
@ -11,7 +11,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="用户名称"> <el-form-item label="用户名称" prop="userName">
<el-input <el-input
v-model="queryParams.userName" v-model="queryParams.userName"
placeholder="请输入用户名称" placeholder="请输入用户名称"
@ -21,7 +21,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="登录状态" placeholder="登录状态"
@ -51,10 +51,43 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="list" style="width: 100%;"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:logininfor:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="handleClean"
v-hasPermi="['monitor:logininfor:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:logininfor:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="访问编号" align="center" prop="infoId" /> <el-table-column label="访问编号" align="center" prop="infoId" />
<el-table-column label="用户名称" align="center" prop="userName" /> <el-table-column label="用户名称" align="center" prop="userName" />
<el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" /> <el-table-column label="登录地址" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
@ -65,7 +98,7 @@
<el-table-column label="操作信息" align="center" prop="msg" /> <el-table-column label="操作信息" align="center" prop="msg" />
<el-table-column label="登录日期" align="center" prop="loginTime" width="180"> <el-table-column label="登录日期" align="center" prop="loginTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.loginTime) }}</span> <span>{{ parseTime(scope.row.loginTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -81,13 +114,18 @@
</template> </template>
<script> <script>
import { list } from "@/api/monitor/logininfor"; import { list, delLogininfor, cleanLogininfor, exportLogininfor } from "@/api/monitor/logininfor";
export default { export default {
name: "Logininfor",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 表格数据 // 表格数据
@ -131,6 +169,57 @@ export default {
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.infoId)
this.multiple = !selection.length
},
/** 删除按钮操作 */
handleDelete(row) {
const infoIds = row.infoId || this.ids;
this.$confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return delLogininfor(infoIds);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
}).catch(function() {});
},
/** 清空按钮操作 */
handleClean() {
this.$confirm('是否确认清空所有登录日志数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return cleanLogininfor();
}).then(() => {
this.getList();
this.msgSuccess("清空成功");
}).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportLogininfor(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -1,5 +1,128 @@
<template> <template>
<div class="app-container"> <div class="app-container">
在线用户 <el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
placeholder="请输入登录地址"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
placeholder="请输入用户名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="loading"
:data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
style="width: 100%;"
>
<el-table-column label="序号" type="index" align="center">
<template slot-scope="scope">
<span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
</template>
</el-table-column>
<el-table-column label="会话编号" align="center" prop="tokenId" :show-overflow-tooltip="true" />
<el-table-column label="登录名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="部门名称" align="center" prop="deptName" />
<el-table-column label="主机" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
<el-table-column label="登录地点" align="center" prop="loginLocation" />
<el-table-column label="浏览器" align="center" prop="browser" />
<el-table-column label="操作系统" align="center" prop="os" />
<el-table-column label="登录时间" align="center" prop="loginTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.loginTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleForceLogout(scope.row)"
v-hasPermi="['monitor:online:forceLogout']"
>强退</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
</div> </div>
</template> </template>
<script>
import { list, forceLogout } from "@/api/monitor/online";
export default {
name: "Online",
data() {
return {
// 遮罩层
loading: true,
// 总条数
total: 0,
// 表格数据
list: [],
pageNum: 1,
pageSize: 10,
// 查询参数
queryParams: {
ipaddr: undefined,
userName: undefined
}
};
},
created() {
this.getList();
},
methods: {
/** 查询登录日志列表 */
getList() {
this.loading = true;
list(this.queryParams).then(response => {
this.list = response.rows;
this.total = response.total;
this.loading = false;
});
},
/** 搜索按钮操作 */
handleQuery() {
this.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 强退按钮操作 */
handleForceLogout(row) {
this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return forceLogout(row.tokenId);
}).then(() => {
this.getList();
this.msgSuccess("强退成功");
}).catch(function() {});
}
}
};
</script>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="系统模块"> <el-form-item label="系统模块" prop="title">
<el-input <el-input
v-model="queryParams.title" v-model="queryParams.title"
placeholder="请输入系统模块" placeholder="请输入系统模块"
@ -11,7 +11,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="操作人员"> <el-form-item label="操作人员" prop="operName">
<el-input <el-input
v-model="queryParams.operName" v-model="queryParams.operName"
placeholder="请输入操作人员" placeholder="请输入操作人员"
@ -21,7 +21,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="类型"> <el-form-item label="类型" prop="businessType">
<el-select <el-select
v-model="queryParams.businessType" v-model="queryParams.businessType"
placeholder="操作类型" placeholder="操作类型"
@ -37,7 +37,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="操作状态" placeholder="操作状态"
@ -67,10 +67,43 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="list" style="width: 100%;"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['monitor:operlog:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="handleClean"
v-hasPermi="['monitor:operlog:remove']"
>清空</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:config:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="日志编号" align="center" prop="operId" /> <el-table-column label="日志编号" align="center" prop="operId" />
<el-table-column label="系统模块" align="center" prop="title" /> <el-table-column label="系统模块" align="center" prop="title" />
<el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" /> <el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
@ -81,7 +114,7 @@
<el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" /> <el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" />
<el-table-column label="操作日期" align="center" prop="operTime" width="180"> <el-table-column label="操作日期" align="center" prop="operTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.operTime) }}</span> <span>{{ parseTime(scope.row.operTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -110,7 +143,7 @@
<el-form ref="form" :model="form" label-width="100px" size="mini"> <el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / 修改</el-form-item> <el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item <el-form-item
label="登录信息:" label="登录信息:"
>{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item> >{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
@ -135,7 +168,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="操作时间:">{{ dateFormat(form.operTime) }}</el-form-item> <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item> <el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
@ -150,13 +183,18 @@
</template> </template>
<script> <script>
import { list } from "@/api/monitor/operlog"; import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/operlog";
export default { export default {
name: "Operlog",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 表格数据 // 表格数据
@ -215,10 +253,61 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.operId)
this.multiple = !selection.length
},
/** 详细按钮操作 */ /** 详细按钮操作 */
handleView(row) { handleView(row) {
this.open = true; this.open = true;
this.form = row; this.form = row;
},
/** 删除按钮操作 */
handleDelete(row) {
const operIds = row.operId || this.ids;
this.$confirm('是否确认删除日志编号为"' + operIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return delOperlog(operIds);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
}).catch(function() {});
},
/** 清空按钮操作 */
handleClean() {
this.$confirm('是否确认清空所有操作日志数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return cleanOperlog();
}).then(() => {
this.getList();
this.msgSuccess("清空成功");
}).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportOperlog(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -175,6 +175,7 @@
import { getServer } from "@/api/monitor/server"; import { getServer } from "@/api/monitor/server";
export default { export default {
name: "Server",
data() { data() {
return { return {
// 加载层信息 // 加载层信息

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="参数名称"> <el-form-item label="参数名称" prop="configName">
<el-input <el-input
v-model="queryParams.configName" v-model="queryParams.configName"
placeholder="请输入参数名称" placeholder="请输入参数名称"
@ -11,7 +11,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="参数键名"> <el-form-item label="参数键名" prop="configKey">
<el-input <el-input
v-model="queryParams.configKey" v-model="queryParams.configKey"
placeholder="请输入参数键名" placeholder="请输入参数键名"
@ -21,7 +21,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="系统内置"> <el-form-item label="系统内置" prop="configType">
<el-select v-model="queryParams.configType" placeholder="系统内置" clearable size="small"> <el-select v-model="queryParams.configType" placeholder="系统内置" clearable size="small">
<el-option <el-option
v-for="dict in typeOptions" v-for="dict in typeOptions"
@ -45,11 +45,53 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:config:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="configList"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:config:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:config:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:config:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:config:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="参数主键" align="center" prop="configId" /> <el-table-column label="参数主键" align="center" prop="configId" />
<el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" /> <el-table-column label="参数名称" align="center" prop="configName" :show-overflow-tooltip="true" />
<el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" /> <el-table-column label="参数键名" align="center" prop="configKey" :show-overflow-tooltip="true" />
@ -58,7 +100,7 @@
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" /> <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -123,13 +165,20 @@
</template> </template>
<script> <script>
import { listConfig, getConfig, delConfig, addConfig, updateConfig } from "@/api/system/config"; import { listConfig, getConfig, delConfig, addConfig, updateConfig, exportConfig } from "@/api/system/config";
export default { export default {
name: "Config",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 参数表格数据 // 参数表格数据
@ -209,16 +258,29 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
this.open = true; this.open = true;
this.title = "添加参数"; this.title = "添加参数";
}, },
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.configId)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
getConfig(row.configId).then(response => { const configId = row.configId || this.ids
getConfig(configId).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改参数"; this.title = "修改参数";
@ -254,16 +316,30 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除名称为"' + row.configName + '"的数据项?', "警告", { const configIds = row.configId || this.ids;
this.$confirm('是否确认删除参数编号为"' + configIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delConfig(row.configId); return delConfig(configIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有参数数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportConfig(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -46,12 +46,12 @@
default-expand-all default-expand-all
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
<el-table-column prop="deptName" label="部门名称" width="200"></el-table-column> <el-table-column prop="deptName" label="部门名称" width="260"></el-table-column>
<el-table-column prop="orderNum" label="排序" width="200"></el-table-column> <el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
<el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"></el-table-column> <el-table-column prop="status" label="状态" :formatter="statusFormat" width="100"></el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="200"> <el-table-column label="创建时间" align="center" prop="createTime" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -88,7 +88,7 @@
<el-row> <el-row>
<el-col :span="24" v-if="form.parentId !== 0"> <el-col :span="24" v-if="form.parentId !== 0">
<el-form-item label="上级部门" prop="parentId"> <el-form-item label="上级部门" prop="parentId">
<treeselect v-model="form.parentId" :options="deptOptions" placeholder="选择上级部门" /> <treeselect v-model="form.parentId" :options="deptOptions" :normalizer="normalizer" placeholder="选择上级部门" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
@ -138,11 +138,12 @@
</template> </template>
<script> <script>
import { listDept, getDept, treeselect, delDept, addDept, updateDept } from "@/api/system/dept"; import { listDept, getDept, delDept, addDept, updateDept } from "@/api/system/dept";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default { export default {
name: "Dept",
components: { Treeselect }, components: { Treeselect },
data() { data() {
return { return {
@ -150,8 +151,8 @@ export default {
loading: true, loading: true,
// 表格树数据 // 表格树数据
deptList: [], deptList: [],
// 部门部门树选项 // 部门树选项
deptOptions: undefined, deptOptions: [],
// 弹出层标题 // 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
@ -204,14 +205,25 @@ export default {
getList() { getList() {
this.loading = true; this.loading = true;
listDept(this.queryParams).then(response => { listDept(this.queryParams).then(response => {
this.deptList = response.data; this.deptList = this.handleTree(response.data, "deptId");
this.loading = false; this.loading = false;
}); });
}, },
/** 转换部门数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.deptId,
label: node.deptName,
children: node.children
};
},
/** 查询部门下拉树结构 */ /** 查询部门下拉树结构 */
getTreeselect() { getTreeselect() {
treeselect().then(response => { listDept().then(response => {
this.deptOptions = response.data; this.deptOptions = this.handleTree(response.data, "deptId");
}); });
}, },
// 字典状态字典翻译 // 字典状态字典翻译
@ -227,7 +239,7 @@ export default {
reset() { reset() {
this.form = { this.form = {
deptId: undefined, deptId: undefined,
parentId: 100, parentId: undefined,
deptName: undefined, deptName: undefined,
orderNum: undefined, orderNum: undefined,
leader: undefined, leader: undefined,

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true"> <el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="字典名称"> <el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" size="small"> <el-select v-model="queryParams.dictType" size="small">
<el-option <el-option
v-for="item in typeOptions" v-for="item in typeOptions"
@ -11,7 +11,7 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="字典标签"> <el-form-item label="字典标签" prop="dictLabel">
<el-input <el-input
v-model="queryParams.dictLabel" v-model="queryParams.dictLabel"
placeholder="请输入字典标签" placeholder="请输入字典标签"
@ -20,7 +20,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small"> <el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
<el-option <el-option
v-for="dict in statusOptions" v-for="dict in statusOptions"
@ -32,11 +32,53 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="dataList" style="width: 100%;"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:dict:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:dict:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编码" align="center" prop="dictCode" /> <el-table-column label="字典编码" align="center" prop="dictCode" />
<el-table-column label="字典标签" align="center" prop="dictLabel" /> <el-table-column label="字典标签" align="center" prop="dictLabel" />
<el-table-column label="字典键值" align="center" prop="dictValue" /> <el-table-column label="字典键值" align="center" prop="dictValue" />
@ -45,7 +87,7 @@
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" /> <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -113,18 +155,27 @@
</template> </template>
<script> <script>
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data"; import { listData, getData, delData, addData, updateData, exportData } from "@/api/system/dict/data";
import { listType, getType } from "@/api/system/dict/type"; import { listType, getType } from "@/api/system/dict/type";
export default { export default {
name: "Data",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 字典表格数据 // 字典表格数据
dataList: [], dataList: [],
// 默认字典类型
defaultDictType: "",
// 弹出层标题 // 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
@ -170,6 +221,7 @@ export default {
getType(dictId) { getType(dictId) {
getType(dictId).then(response => { getType(dictId).then(response => {
this.queryParams.dictType = response.data.dictType; this.queryParams.dictType = response.data.dictType;
this.defaultDictType = response.data.dictType;
this.getList(); this.getList();
}); });
}, },
@ -214,6 +266,12 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.queryParams.dictType = this.defaultDictType;
this.handleQuery();
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
@ -221,10 +279,17 @@ export default {
this.title = "添加字典数据"; this.title = "添加字典数据";
this.form.dictType = this.queryParams.dictType; this.form.dictType = this.queryParams.dictType;
}, },
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.dictCode)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
getData(row.dictCode).then(response => { const dictCode = row.dictCode || this.ids
getData(dictCode).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改字典数据"; this.title = "修改字典数据";
@ -260,16 +325,30 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除名称为"' + row.dictLabel + '"的数据项?', "警告", { const dictCodes = row.dictCode || this.ids;
this.$confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delData(row.dictCode); return delData(dictCodes);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportData(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="字典名称"> <el-form-item label="字典名称" prop="dictName">
<el-input <el-input
v-model="queryParams.dictName" v-model="queryParams.dictName"
placeholder="请输入字典名称" placeholder="请输入字典名称"
@ -11,7 +11,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="字典类型"> <el-form-item label="字典类型" prop="dictType">
<el-input <el-input
v-model="queryParams.dictType" v-model="queryParams.dictType"
placeholder="请输入字典类型" placeholder="请输入字典类型"
@ -21,7 +21,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="字典状态" placeholder="字典状态"
@ -39,7 +39,7 @@
</el-form-item> </el-form-item>
<el-form-item label="创建时间"> <el-form-item label="创建时间">
<el-date-picker <el-date-picker
v-model="queryParams.createTime" v-model="dateRange"
size="small" size="small"
style="width: 240px" style="width: 240px"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -51,14 +51,56 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="typeList" style="width: 100%;"> <el-row :gutter="10" class="mb8">
<el-table-column label="字典主键" align="center" prop="dictId" /> <el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:dict:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:dict:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:dict:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:dict:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="字典编号" align="center" prop="dictId" />
<el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" /> <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
<el-table-column label="字典类型" align="center"> <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
<template slot-scope="scope"> <template slot-scope="scope">
<router-link :to="'/dict/type/data/' + scope.row.dictId" class="link-type"> <router-link :to="'/dict/type/data/' + scope.row.dictId" class="link-type">
<span>{{ scope.row.dictType }}</span> <span>{{ scope.row.dictType }}</span>
@ -69,7 +111,7 @@
<el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" /> <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -131,13 +173,20 @@
</template> </template>
<script> <script>
import { listType, getType, delType, addType, updateType } from "@/api/system/dict/type"; import { listType, getType, delType, addType, updateType, exportType } from "@/api/system/dict/type";
export default { export default {
name: "Dict",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 字典表格数据 // 字典表格数据
@ -181,8 +230,7 @@ export default {
/** 查询字典类型列表 */ /** 查询字典类型列表 */
getList() { getList() {
this.loading = true; this.loading = true;
listType(this.addDateRange(this.queryParams, this.dateRange)).then( listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
response => {
this.typeList = response.rows; this.typeList = response.rows;
this.total = response.total; this.total = response.total;
this.loading = false; this.loading = false;
@ -214,16 +262,29 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
this.open = true; this.open = true;
this.title = "添加字典类型"; this.title = "添加字典类型";
}, },
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.dictId)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
getType(row.dictId).then(response => { const dictId = row.dictId || this.ids
getType(dictId).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改字典类型"; this.title = "修改字典类型";
@ -259,16 +320,30 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除名称为"' + row.dictName + '"的数据项?', "警告", { const dictIds = row.dictId || this.ids;
this.$confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delType(row.dictId); return delType(dictIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有类型数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportType(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -32,22 +32,22 @@
row-key="menuId" row-key="menuId"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}" :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
> >
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="130px"></el-table-column> <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
<el-table-column prop="icon" label="图标" align="center" width="100px"> <el-table-column prop="icon" label="图标" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<svg-icon :icon-class="scope.row.icon" /> <svg-icon :icon-class="scope.row.icon" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="orderNum" label="排序" width="60px"></el-table-column> <el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
<el-table-column prop="perms" label="权限标识" width="130px" :show-overflow-tooltip="true"></el-table-column> <el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="component" label="组件路径" width="180px" :show-overflow-tooltip="true"></el-table-column> <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
<el-table-column prop="visible" label=" 可见" :formatter="visibleFormat" width="80px"></el-table-column> <el-table-column prop="visible" label="可见" :formatter="visibleFormat" width="80"></el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" width="180" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button size="mini" <el-button size="mini"
type="text" type="text"
@ -63,7 +63,6 @@
v-hasPermi="['system:menu:add']" v-hasPermi="['system:menu:add']"
>新增</el-button> >新增</el-button>
<el-button <el-button
v-if="scope.row.parentId != 0"
size="mini" size="mini"
type="text" type="text"
icon="el-icon-delete" icon="el-icon-delete"
@ -78,11 +77,12 @@
<el-dialog :title="title" :visible.sync="open" width="600px"> <el-dialog :title="title" :visible.sync="open" width="600px">
<el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-row> <el-row>
<el-col :span="24" v-if="form.parentId !== 0"> <el-col :span="24">
<el-form-item label="上级菜单" prop="parentId"> <el-form-item label="上级菜单">
<treeselect <treeselect
v-model="form.parentId" v-model="form.parentId"
:options="menuOptions" :options="menuOptions"
:normalizer="normalizer"
:show-count="true" :show-count="true"
placeholder="选择上级菜单" placeholder="选择上级菜单"
/> />
@ -148,7 +148,7 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item v-if="form.menuType == 'C'" label="权限标识"> <el-form-item v-if="form.menuType != 'M'" label="权限标识">
<el-input v-model="form.perms" placeholder="请权限标识" maxlength="50" /> <el-input v-model="form.perms" placeholder="请权限标识" maxlength="50" />
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -174,12 +174,13 @@
</template> </template>
<script> <script>
import { listMenu, getMenu, treeselect, delMenu, addMenu, updateMenu } from "@/api/system/menu"; import { listMenu, getMenu, delMenu, addMenu, updateMenu } from "@/api/system/menu";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import IconSelect from "@/components/IconSelect"; import IconSelect from "@/components/IconSelect";
export default { export default {
name: "Menu",
components: { Treeselect, IconSelect }, components: { Treeselect, IconSelect },
data() { data() {
return { return {
@ -188,7 +189,7 @@ export default {
// 菜单表格树数据 // 菜单表格树数据
menuList: [], menuList: [],
// 菜单树选项 // 菜单树选项
menuOptions: undefined, menuOptions: [],
// 弹出层标题 // 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
@ -204,14 +205,14 @@ export default {
form: {}, form: {},
// 表单校验 // 表单校验
rules: { rules: {
parentId: [
{ required: true, message: "上级菜单不能为空", trigger: "blur" }
],
menuName: [ menuName: [
{ required: true, message: "菜单名称不能为空", trigger: "blur" } { required: true, message: "菜单名称不能为空", trigger: "blur" }
], ],
orderNum: [ orderNum: [
{ required: true, message: "菜单顺序不能为空", trigger: "blur" } { required: true, message: "菜单顺序不能为空", trigger: "blur" }
],
path: [
{ required: true, message: "路由地址不能为空", trigger: "blur" }
] ]
} }
}; };
@ -231,14 +232,28 @@ export default {
getList() { getList() {
this.loading = true; this.loading = true;
listMenu(this.queryParams).then(response => { listMenu(this.queryParams).then(response => {
this.menuList = response.data; this.menuList = this.handleTree(response.data, "menuId");
this.loading = false; this.loading = false;
}); });
}, },
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.menuId,
label: node.menuName,
children: node.children
};
},
/** 查询菜单下拉树结构 */ /** 查询菜单下拉树结构 */
getTreeselect() { getTreeselect() {
treeselect().then(response => { listMenu().then(response => {
this.menuOptions = response.data; this.menuOptions = [];
const menu = { menuId: 0, menuName: '主类目', children: [] };
menu.children = this.handleTree(response.data, "menuId");
this.menuOptions.push(menu);
}); });
}, },
// 菜单显示状态字典翻译 // 菜单显示状态字典翻译

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="公告标题"> <el-form-item label="公告标题" prop="noticeTitle">
<el-input <el-input
v-model="queryParams.noticeTitle" v-model="queryParams.noticeTitle"
placeholder="请输入公告标题" placeholder="请输入公告标题"
@ -10,7 +10,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="操作人员"> <el-form-item label="操作人员" prop="createBy">
<el-input <el-input
v-model="queryParams.createBy" v-model="queryParams.createBy"
placeholder="请输入操作人员" placeholder="请输入操作人员"
@ -19,7 +19,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="类型"> <el-form-item label="类型" prop="noticeType">
<el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable size="small"> <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable size="small">
<el-option <el-option
v-for="dict in typeOptions" v-for="dict in typeOptions"
@ -31,11 +31,44 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:notice:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="noticeList"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:notice:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:notice:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:notice:remove']"
>删除</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" prop="noticeId" width="100" /> <el-table-column label="序号" align="center" prop="noticeId" width="100" />
<el-table-column <el-table-column
label="公告标题" label="公告标题"
@ -60,7 +93,7 @@
<el-table-column label="创建者" align="center" prop="createBy" width="100" /> <el-table-column label="创建者" align="center" prop="createBy" width="100" />
<el-table-column label="创建时间" align="center" prop="createTime" width="100"> <el-table-column label="创建时间" align="center" prop="createTime" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime, 'yyyy-MM-dd') }}</span> <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -125,7 +158,7 @@
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="内容"> <el-form-item label="内容">
<Editor v-model="form.noticeContent"/> <Editor v-model="form.noticeContent" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -139,10 +172,11 @@
</template> </template>
<script> <script>
import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice"; import { listNotice, getNotice, delNotice, addNotice, updateNotice, exportNotice } from "@/api/system/notice";
import Editor from '@/components/Editor'; import Editor from '@/components/Editor';
export default { export default {
name: "Notice",
components: { components: {
Editor Editor
}, },
@ -150,6 +184,12 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 公告表格数据 // 公告表格数据
@ -231,6 +271,17 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.noticeId)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
@ -240,7 +291,8 @@ export default {
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
getNotice(row.noticeId).then(response => { const noticeId = row.noticeId || this.ids
getNotice(noticeId).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改公告"; this.title = "修改公告";
@ -276,12 +328,13 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除公告标题为"' + row.noticeTitle + '"的数据项?', "警告", { const noticeIds = row.noticeId || this.ids
this.$confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delNotice(row.noticeId); return delNotice(noticeIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="岗位编码"> <el-form-item label="岗位编码" prop="postCode">
<el-input <el-input
v-model="queryParams.postCode" v-model="queryParams.postCode"
placeholder="请输入岗位编码" placeholder="请输入岗位编码"
@ -10,7 +10,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="岗位名称"> <el-form-item label="岗位名称" prop="postName">
<el-input <el-input
v-model="queryParams.postName" v-model="queryParams.postName"
placeholder="请输入岗位名称" placeholder="请输入岗位名称"
@ -19,7 +19,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small"> <el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small">
<el-option <el-option
v-for="dict in statusOptions" v-for="dict in statusOptions"
@ -31,11 +31,53 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:post:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="postList"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:post:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:post:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:post:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:post:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="岗位编号" align="center" prop="postId" /> <el-table-column label="岗位编号" align="center" prop="postId" />
<el-table-column label="岗位编码" align="center" prop="postCode" /> <el-table-column label="岗位编码" align="center" prop="postCode" />
<el-table-column label="岗位名称" align="center" prop="postName" /> <el-table-column label="岗位名称" align="center" prop="postName" />
@ -43,7 +85,7 @@
<el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" /> <el-table-column label="状态" align="center" prop="status" :formatter="statusFormat" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -108,13 +150,20 @@
</template> </template>
<script> <script>
import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post"; import { listPost, getPost, delPost, addPost, updatePost, exportPost } from "@/api/system/post";
export default { export default {
name: "Post",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 岗位表格数据 // 岗位表格数据
@ -191,6 +240,17 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.postId)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
@ -200,7 +260,8 @@ export default {
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
getPost(row.postId).then(response => { const postId = row.postId || this.ids
getPost(postId).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改岗位"; this.title = "修改岗位";
@ -236,16 +297,30 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除岗位名称为"' + row.postName + '"的数据项?', "警告", { const postIds = row.postId || this.ids;
this.$confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delPost(row.postId); return delPost(postIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有岗位数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportPost(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :inline="true"> <el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="角色名称"> <el-form-item label="角色名称" prop="roleName">
<el-input <el-input
v-model="queryParams.roleName" v-model="queryParams.roleName"
placeholder="请输入角色名称" placeholder="请输入角色名称"
@ -11,7 +11,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="权限字符"> <el-form-item label="权限字符" prop="roleKey">
<el-input <el-input
v-model="queryParams.roleKey" v-model="queryParams.roleKey"
placeholder="请输入权限字符" placeholder="请输入权限字符"
@ -21,7 +21,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="角色状态" placeholder="角色状态"
@ -51,6 +51,12 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button <el-button
type="primary" type="primary"
icon="el-icon-plus" icon="el-icon-plus"
@ -58,15 +64,45 @@
@click="handleAdd" @click="handleAdd"
v-hasPermi="['system:role:add']" v-hasPermi="['system:role:add']"
>新增</el-button> >新增</el-button>
</el-form-item> </el-col>
</el-form> <el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:role:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:role:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:post:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="roleList"> <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="角色编号" prop="roleId" width="120" /> <el-table-column label="角色编号" prop="roleId" width="120" />
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" /> <el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="180" /> <el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="150" />
<el-table-column label="显示顺序" prop="roleSort" width="120" /> <el-table-column label="显示顺序" prop="roleSort" width="100" />
<el-table-column label="状态" align="center" width="120"> <el-table-column label="状态" align="center" width="100">
<template slot-scope="scope"> <template slot-scope="scope">
<el-switch <el-switch
v-model="scope.row.status" v-model="scope.row.status"
@ -78,7 +114,7 @@
</el-table-column> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="180"> <el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
@ -197,15 +233,22 @@
</template> </template>
<script> <script>
import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from "@/api/system/role"; import { listRole, getRole, delRole, addRole, updateRole, exportRole, dataScope, changeRoleStatus } from "@/api/system/role";
import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu"; import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept"; import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept";
export default { export default {
name: "Role",
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 角色表格数据 // 角色表格数据
@ -326,15 +369,15 @@ export default {
/** 根据角色ID查询菜单树结构 */ /** 根据角色ID查询菜单树结构 */
getRoleMenuTreeselect(roleId) { getRoleMenuTreeselect(roleId) {
roleMenuTreeselect(roleId).then(response => { roleMenuTreeselect(roleId).then(response => {
this.getMenuTreeselect(); this.menuOptions = response.menus;
this.$refs.menu.setCheckedKeys(response.data); this.$refs.menu.setCheckedKeys(response.checkedKeys);
}); });
}, },
/** 根据角色ID查询部门树结构 */ /** 根据角色ID查询部门树结构 */
getRoleDeptTreeselect(roleId) { getRoleDeptTreeselect(roleId) {
roleDeptTreeselect(roleId).then(response => { roleDeptTreeselect(roleId).then(response => {
this.getDeptTreeselect(); this.deptOptions = response.depts;
this.$refs.dept.setCheckedKeys(response.data); this.$refs.dept.setCheckedKeys(response.checkedKeys);
}); });
}, },
// 角色状态修改 // 角色状态修改
@ -364,8 +407,8 @@ export default {
}, },
// 表单重置 // 表单重置
reset() { reset() {
if (this.$refs.tree != undefined) { if (this.$refs.menu != undefined) {
this.$refs.tree.setCheckedKeys([]); this.$refs.menu.setCheckedKeys([]);
} }
this.form = { this.form = {
roleId: undefined, roleId: undefined,
@ -384,6 +427,18 @@ export default {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.roleId)
this.single = selection.length!=1
this.multiple = !selection.length
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
@ -394,10 +449,11 @@ export default {
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
const roleId = row.roleId || this.ids
this.$nextTick(() => { this.$nextTick(() => {
this.getRoleMenuTreeselect(row.roleId); this.getRoleMenuTreeselect(roleId);
}); });
getRole(row.roleId).then(response => { getRole(roleId).then(response => {
this.form = response.data; this.form = response.data;
this.open = true; this.open = true;
this.title = "修改角色"; this.title = "修改角色";
@ -462,16 +518,30 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除名称为"' + row.roleName + '"的数据项?', "警告", { const roleIds = row.roleId || this.ids;
this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delRole(row.roleId); return delRole(roleIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有角色数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportRole(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
} }
} }
}; };

View File

@ -27,8 +27,8 @@
</el-col> </el-col>
<!--用户数据--> <!--用户数据-->
<el-col :span="20" :xs="24"> <el-col :span="20" :xs="24">
<el-form :inline="true" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="用户名称"> <el-form-item label="用户名称" prop="userName">
<el-input <el-input
v-model="queryParams.userName" v-model="queryParams.userName"
placeholder="请输入用户名称" placeholder="请输入用户名称"
@ -38,7 +38,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="手机号码"> <el-form-item label="手机号码" prop="phonenumber">
<el-input <el-input
v-model="queryParams.phonenumber" v-model="queryParams.phonenumber"
placeholder="请输入手机号码" placeholder="请输入手机号码"
@ -48,7 +48,7 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="状态"> <el-form-item label="状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.status"
placeholder="用户状态" placeholder="用户状态"
@ -78,15 +78,66 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<el-table v-loading="loading" :data="userList"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:user:add']"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleUpdate"
v-hasPermi="['system:user:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['system:user:remove']"
>删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
icon="el-icon-upload2"
size="mini"
@click="handleImport"
v-hasPermi="['system:user:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:user:export']"
>导出</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="40" align="center" />
<el-table-column label="用户编号" align="center" prop="userId" /> <el-table-column label="用户编号" align="center" prop="userId" />
<el-table-column label="用户名称" align="center" prop="userName" /> <el-table-column label="用户名称" align="center" prop="userName" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" prop="nickName" /> <el-table-column label="用户昵称" align="center" prop="nickName" :show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" prop="dept.deptName" /> <el-table-column label="部门" align="center" prop="dept.deptName" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" prop="phonenumber" width="120" /> <el-table-column label="手机号码" align="center" prop="phonenumber" width="120" />
<el-table-column label="状态" align="center"> <el-table-column label="状态" align="center">
<template slot-scope="scope"> <template slot-scope="scope">
@ -100,7 +151,7 @@
</el-table-column> </el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" width="160"> <el-table-column label="创建时间" align="center" prop="createTime" width="160">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ dateFormat(scope.row.createTime) }}</span> <span>{{ parseTime(scope.row.createTime) }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
@ -242,23 +293,60 @@
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px">
<el-upload
ref="upload"
:limit="1"
accept=".xlsx, .xls"
:headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport"
:disabled="upload.isUploading"
:on-progress="handleFileUploadProgress"
:on-success="handleFileSuccess"
:auto-upload="false"
drag
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处
<em>点击上传</em>
</div>
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
<el-link type="info" style="font-size:12px" @click="importTemplate">下载模板</el-link>
</div>
<div class="el-upload__tip" style="color:red" slot="tip">提示仅允许导入xlsxlsx格式文件</div>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitFileForm"> </el-button>
<el-button @click="upload.open = false"> </el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user"; import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus, importTemplate } from "@/api/system/user";
import { getToken } from "@/utils/auth";
import { treeselect } from "@/api/system/dept"; import { treeselect } from "@/api/system/dept";
import { listPost } from "@/api/system/post";
import { listRole } from "@/api/system/role";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default { export default {
name: "User",
components: { Treeselect }, components: { Treeselect },
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数 // 总条数
total: 0, total: 0,
// 用户表格数据 // 用户表格数据
@ -289,6 +377,21 @@ export default {
children: "children", children: "children",
label: "label" label: "label"
}, },
// 用户导入参数
upload: {
// 是否显示弹出层(用户导入)
open: false,
// 弹出层标题(用户导入)
title: "",
// 是否禁用上传
isUploading: false,
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
// 查询参数 // 查询参数
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
@ -313,6 +416,7 @@ export default {
{ required: true, message: "用户密码不能为空", trigger: "blur" } { required: true, message: "用户密码不能为空", trigger: "blur" }
], ],
email: [ email: [
{ required: true, message: "邮箱地址不能为空", trigger: "blur" },
{ {
type: "email", type: "email",
message: "'请输入正确的邮箱地址", message: "'请输入正确的邮箱地址",
@ -320,6 +424,7 @@ export default {
} }
], ],
phonenumber: [ phonenumber: [
{ required: true, message: "手机号码不能为空", trigger: "blur" },
{ {
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码", message: "请输入正确的手机号码",
@ -345,7 +450,7 @@ export default {
this.sexOptions = response.data; this.sexOptions = response.data;
}); });
this.getConfigKey("sys.user.initPassword").then(response => { this.getConfigKey("sys.user.initPassword").then(response => {
this.initPassword = response.data; this.initPassword = response.msg;
}); });
}, },
methods: { methods: {
@ -375,18 +480,6 @@ export default {
this.queryParams.deptId = data.id; this.queryParams.deptId = data.id;
this.getList(); this.getList();
}, },
/** 查询岗位列表 */
getPosts() {
listPost().then(response => {
this.postOptions = response.rows;
});
},
/** 查询角色列表 */
getRoles() {
listRole().then(response => {
this.roleOptions = response.rows;
});
},
// 用户状态修改 // 用户状态修改
handleStatusChange(row) { handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"; let text = row.status === "0" ? "启用" : "停用";
@ -411,9 +504,10 @@ export default {
reset() { reset() {
this.form = { this.form = {
userId: undefined, userId: undefined,
deptId: 100, deptId: undefined,
userName: undefined, userName: undefined,
nickName: undefined, nickName: undefined,
password: undefined,
phonenumber: undefined, phonenumber: undefined,
email: undefined, email: undefined,
sex: undefined, sex: undefined,
@ -429,24 +523,39 @@ export default {
this.queryParams.page = 1; this.queryParams.page = 1;
this.getList(); this.getList();
}, },
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.userId);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
this.getPosts(); getUser().then(response => {
this.getRoles(); this.postOptions = response.posts;
this.open = true; this.roleOptions = response.roles;
this.title = "添加用户"; this.open = true;
this.form.password = this.initPassword; this.title = "添加用户";
this.form.password = this.initPassword;
});
}, },
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
this.getPosts(); const userId = row.userId || this.ids;
this.getRoles(); getUser(userId).then(response => {
getUser(row.userId).then(response => {
this.form = response.data; this.form = response.data;
this.postOptions = response.posts;
this.roleOptions = response.roles;
this.form.postIds = response.postIds; this.form.postIds = response.postIds;
this.form.roleIds = response.roleIds; this.form.roleIds = response.roleIds;
this.open = true; this.open = true;
@ -499,16 +608,57 @@ export default {
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.$confirm('是否确认删除名称为"' + row.userName + '"的数据项?', "警告", { const userIds = row.userId || this.ids;
this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(function() {
return delUser(row.userId); return delUser(userIds);
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); }).catch(function() {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm('是否确认导出所有用户数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return exportUser(queryParams);
}).then(response => {
this.download(response.msg);
}).catch(function() {});
},
/** 导入按钮操作 */
handleImport() {
this.upload.title = "用户导入";
this.upload.open = true;
},
/** 下载模板操作 */
importTemplate() {
importTemplate().then(response => {
this.download(response.msg);
});
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.upload.open = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
this.getList();
},
// 提交上传文件
submitFileForm() {
this.$refs.upload.submit();
} }
} }
}; };

View File

@ -33,7 +33,7 @@
</li> </li>
<li class="list-group-item"> <li class="list-group-item">
<svg-icon icon-class="date" />创建日期 <svg-icon icon-class="date" />创建日期
<div class="pull-right">2018-08-23 09:11:56</div> <div class="pull-right">{{ user.createTime }}</div>
</li> </li>
</ul> </ul>
</div> </div>
@ -89,13 +89,3 @@ export default {
} }
}; };
</script> </script>
<style rel="stylesheet/scss" lang="scss">
.avatar-uploader-icon {
font-size: 28px;
width: 120px;
height: 120px;
line-height: 120px;
text-align: center;
}
</style>

View File

@ -24,7 +24,7 @@
<br /> <br />
<el-row> <el-row>
<el-col :lg="2" :md="2"> <el-col :lg="2" :md="2">
<el-upload :show-file-list="false" :before-upload="beforeUpload"> <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
<el-button size="small"> <el-button size="small">
上传 上传
<i class="el-icon-upload el-icon--right"></i> <i class="el-icon-upload el-icon--right"></i>
@ -44,7 +44,7 @@
<el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button> <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
</el-col> </el-col>
<el-col :lg="{span: 2, offset: 6}" :md="2"> <el-col :lg="{span: 2, offset: 6}" :md="2">
<el-button type="primary" size="small" @click="uploadImg()"> </el-button> <el-button type="primary" size="small" @click="uploadImg()"> </el-button>
</el-col> </el-col>
</el-row> </el-row>
</el-dialog> </el-dialog>
@ -84,6 +84,9 @@ export default {
editCropper() { editCropper() {
this.open = true; this.open = true;
}, },
// 覆盖默认的上传行为
requestUpload() {
},
// 向左旋转 // 向左旋转
rotateLeft() { rotateLeft() {
this.$refs.cropper.rotateLeft(); this.$refs.cropper.rotateLeft();

View File

@ -0,0 +1,106 @@
<template>
<div>
<el-dialog
v-bind="$attrs"
width="500px"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="15">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="medium"
label-width="100px"
>
<el-col :span="24">
<el-form-item label="生成类型" prop="type">
<el-radio-group v-model="formData.type">
<el-radio-button
v-for="(item, index) in typeOptions"
:key="index"
:label="item.value"
:disabled="item.disabled"
>
{{ item.label }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="showFileName" label="文件名" prop="fileName">
<el-input v-model="formData.fileName" placeholder="请输入文件名" clearable />
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button @click="close">
取消
</el-button>
<el-button type="primary" @click="handelConfirm">
确定
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: ['showFileName'],
data() {
return {
formData: {
fileName: undefined,
type: 'file'
},
rules: {
fileName: [{
required: true,
message: '请输入文件名',
trigger: 'blur'
}],
type: [{
required: true,
message: '生成类型不能为空',
trigger: 'change'
}]
},
typeOptions: [{
label: '页面',
value: 'file'
}, {
label: '弹窗',
value: 'dialog'
}]
}
},
computed: {
},
watch: {},
mounted() {},
methods: {
onOpen() {
if (this.showFileName) {
this.formData.fileName = `${+new Date()}.vue`
}
},
onClose() {
},
close(e) {
this.$emit('update:visible', false)
},
handelConfirm() {
this.$refs.elForm.validate(valid => {
if (!valid) return
this.$emit('confirm', { ...this.formData })
this.close()
})
}
}
}
</script>

View File

@ -0,0 +1,100 @@
<script>
import draggable from 'vuedraggable'
import render from '@/utils/generator/render'
const components = {
itemBtns(h, element, index, parent) {
const { copyItem, deleteItem } = this.$listeners
return [
<span class="drawing-item-copy" title="复制" onClick={event => {
copyItem(element, parent); event.stopPropagation()
}}>
<i class="el-icon-copy-document" />
</span>,
<span class="drawing-item-delete" title="删除" onClick={event => {
deleteItem(index, parent); event.stopPropagation()
}}>
<i class="el-icon-delete" />
</span>
]
}
}
const layouts = {
colFormItem(h, element, index, parent) {
const { activeItem } = this.$listeners
let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
return (
<el-col span={element.span} class={className}
nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
<el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
label={element.label} required={element.required}>
<render key={element.renderKey} conf={element} onInput={ event => {
this.$set(element, 'defaultValue', event)
}} />
</el-form-item>
{components.itemBtns.apply(this, arguments)}
</el-col>
)
},
rowFormItem(h, element, index, parent) {
const { activeItem } = this.$listeners
const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
let child = renderChildren.apply(this, arguments)
if (element.type === 'flex') {
child = <el-row type={element.type} justify={element.justify} align={element.align}>
{child}
</el-row>
}
return (
<el-col span={element.span}>
<el-row gutter={element.gutter} class={className}
nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
<span class="component-name">{element.componentName}</span>
<draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
{child}
</draggable>
{components.itemBtns.apply(this, arguments)}
</el-row>
</el-col>
)
}
}
function renderChildren(h, element, index, parent) {
if (!Array.isArray(element.children)) return null
return element.children.map((el, i) => {
const layout = layouts[el.layout]
if (layout) {
return layout.call(this, h, el, i, element.children)
}
return layoutIsNotFound()
})
}
function layoutIsNotFound() {
throw new Error(`没有与${this.element.layout}匹配的layout`)
}
export default {
components: {
render,
draggable
},
props: [
'element',
'index',
'drawingList',
'activeId',
'formConf'
],
render(h) {
const layout = layouts[this.element.layout]
if (layout) {
return layout.call(this, h, this.element, this.index, this.drawingList)
}
return layoutIsNotFound()
}
}
</script>

View File

@ -0,0 +1,123 @@
<template>
<div class="icon-dialog">
<el-dialog
v-bind="$attrs"
width="980px"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<div slot="title">
选择图标
<el-input
v-model="key"
size="mini"
:style="{width: '260px'}"
placeholder="请输入图标名称"
prefix-icon="el-icon-search"
clearable
/>
</div>
<ul class="icon-ul">
<li
v-for="icon in iconList"
:key="icon"
:class="active===icon?'active-item':''"
@click="onSelect(icon)"
>
<i :class="icon" />
<div>{{ icon }}</div>
</li>
</ul>
</el-dialog>
</div>
</template>
<script>
import iconList from '@/utils/generator/icon.json'
const originList = iconList.map(name => `el-icon-${name}`)
export default {
inheritAttrs: false,
props: ['current'],
data() {
return {
iconList: originList,
active: null,
key: ''
}
},
watch: {
key(val) {
if (val) {
this.iconList = originList.filter(name => name.indexOf(val) > -1)
} else {
this.iconList = originList
}
}
},
methods: {
onOpen() {
this.active = this.current
this.key = ''
},
onClose() {},
onSelect(icon) {
this.active = icon
this.$emit('select', icon)
this.$emit('update:visible', false)
}
}
}
</script>
<style lang="scss" scoped>
.icon-ul {
margin: 0;
padding: 0;
font-size: 0;
li {
list-style-type: none;
text-align: center;
font-size: 14px;
display: inline-block;
width: 16.66%;
box-sizing: border-box;
height: 108px;
padding: 15px 6px 6px 6px;
cursor: pointer;
overflow: hidden;
&:hover {
background: #f2f2f2;
}
&.active-item{
background: #e1f3fb;
color: #7a6df0
}
> i {
font-size: 30px;
line-height: 50px;
}
}
}
.icon-dialog {
::v-deep .el-dialog {
border-radius: 8px;
margin-bottom: 0;
margin-top: 4vh !important;
display: flex;
flex-direction: column;
max-height: 92vh;
overflow: hidden;
box-sizing: border-box;
.el-dialog__header {
padding-top: 14px;
}
.el-dialog__body {
margin: 0 20px 20px 20px;
padding: 0;
overflow: auto;
}
}
}
</style>

View File

@ -0,0 +1,944 @@
<template>
<div class="right-board">
<el-tabs v-model="currentTab" class="center-tabs">
<el-tab-pane label="组件属性" name="field" />
<el-tab-pane label="表单属性" name="form" />
</el-tabs>
<div class="field-box">
<a class="document-link" target="_blank" :href="documentLink" title="查看组件文档">
<i class="el-icon-link" />
</a>
<el-scrollbar class="right-scrollbar">
<!-- 组件属性 -->
<el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
<el-form-item v-if="activeData.changeTag" label="组件类型">
<el-select
v-model="activeData.tagIcon"
placeholder="请选择组件类型"
:style="{width: '100%'}"
@change="tagChange"
>
<el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
<el-option
v-for="item in group.options"
:key="item.label"
:label="item.label"
:value="item.tagIcon"
>
<svg-icon class="node-icon" :icon-class="item.tagIcon" />
<span> {{ item.label }}</span>
</el-option>
</el-option-group>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.vModel!==undefined" label="字段名">
<el-input v-model="activeData.vModel" placeholder="请输入字段名v-model" />
</el-form-item>
<el-form-item v-if="activeData.componentName!==undefined" label="组件名">
{{ activeData.componentName }}
</el-form-item>
<el-form-item v-if="activeData.label!==undefined" label="标题">
<el-input v-model="activeData.label" placeholder="请输入标题" />
</el-form-item>
<el-form-item v-if="activeData.placeholder!==undefined" label="占位提示">
<el-input v-model="activeData.placeholder" placeholder="请输入占位提示" />
</el-form-item>
<el-form-item v-if="activeData['start-placeholder']!==undefined" label="开始占位">
<el-input v-model="activeData['start-placeholder']" placeholder="请输入占位提示" />
</el-form-item>
<el-form-item v-if="activeData['end-placeholder']!==undefined" label="结束占位">
<el-input v-model="activeData['end-placeholder']" placeholder="请输入占位提示" />
</el-form-item>
<el-form-item v-if="activeData.span!==undefined" label="表单栅格">
<el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
</el-form-item>
<el-form-item v-if="activeData.layout==='rowFormItem'" label="栅格间隔">
<el-input-number v-model="activeData.gutter" :min="0" placeholder="栅格间隔" />
</el-form-item>
<el-form-item v-if="activeData.layout==='rowFormItem'" label="布局模式">
<el-radio-group v-model="activeData.type">
<el-radio-button label="default" />
<el-radio-button label="flex" />
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="水平排列">
<el-select v-model="activeData.justify" placeholder="请选择水平排列" :style="{width: '100%'}">
<el-option
v-for="(item, index) in justifyOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="垂直排列">
<el-radio-group v-model="activeData.align">
<el-radio-button label="top" />
<el-radio-button label="middle" />
<el-radio-button label="bottom" />
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.labelWidth!==undefined" label="标签宽度">
<el-input v-model.number="activeData.labelWidth" type="number" placeholder="请输入标签宽度" />
</el-form-item>
<el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="组件宽度">
<el-input v-model="activeData.style.width" placeholder="请输入组件宽度" clearable />
</el-form-item>
<el-form-item v-if="activeData.vModel!==undefined" label="默认值">
<el-input
:value="setDefaultValue(activeData.defaultValue)"
placeholder="请输入默认值"
@input="onDefaultValueInput"
/>
</el-form-item>
<el-form-item v-if="activeData.tag==='el-checkbox-group'" label="至少应选">
<el-input-number
:value="activeData.min"
:min="0"
placeholder="至少应选"
@input="$set(activeData, 'min', $event?$event:undefined)"
/>
</el-form-item>
<el-form-item v-if="activeData.tag==='el-checkbox-group'" label="最多可选">
<el-input-number
:value="activeData.max"
:min="0"
placeholder="最多可选"
@input="$set(activeData, 'max', $event?$event:undefined)"
/>
</el-form-item>
<el-form-item v-if="activeData.prepend!==undefined" label="前缀">
<el-input v-model="activeData.prepend" placeholder="请输入前缀" />
</el-form-item>
<el-form-item v-if="activeData.append!==undefined" label="后缀">
<el-input v-model="activeData.append" placeholder="请输入后缀" />
</el-form-item>
<el-form-item v-if="activeData['prefix-icon']!==undefined" label="前图标">
<el-input v-model="activeData['prefix-icon']" placeholder="请输入前图标名称">
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')">
选择
</el-button>
</el-input>
</el-form-item>
<el-form-item v-if="activeData['suffix-icon'] !== undefined" label="后图标">
<el-input v-model="activeData['suffix-icon']" placeholder="请输入后图标名称">
<el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')">
选择
</el-button>
</el-input>
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-cascader'" label="选项分隔符">
<el-input v-model="activeData.separator" placeholder="请输入选项分隔符" />
</el-form-item>
<el-form-item v-if="activeData.autosize !== undefined" label="最小行数">
<el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="最小行数" />
</el-form-item>
<el-form-item v-if="activeData.autosize !== undefined" label="最大行数">
<el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="最大行数" />
</el-form-item>
<el-form-item v-if="activeData.min !== undefined" label="最小值">
<el-input-number v-model="activeData.min" placeholder="最小值" />
</el-form-item>
<el-form-item v-if="activeData.max !== undefined" label="最大值">
<el-input-number v-model="activeData.max" placeholder="最大值" />
</el-form-item>
<el-form-item v-if="activeData.step !== undefined" label="步长">
<el-input-number v-model="activeData.step" placeholder="步数" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-input-number'" label="精度">
<el-input-number v-model="activeData.precision" :min="0" placeholder="精度" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-input-number'" label="按钮位置">
<el-radio-group v-model="activeData['controls-position']">
<el-radio-button label="">
默认
</el-radio-button>
<el-radio-button label="right">
右侧
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData.maxlength !== undefined" label="最多输入">
<el-input v-model="activeData.maxlength" placeholder="请输入字符长度">
<template slot="append">
个字符
</template>
</el-input>
</el-form-item>
<el-form-item v-if="activeData['active-text'] !== undefined" label="开启提示">
<el-input v-model="activeData['active-text']" placeholder="请输入开启提示" />
</el-form-item>
<el-form-item v-if="activeData['inactive-text'] !== undefined" label="关闭提示">
<el-input v-model="activeData['inactive-text']" placeholder="请输入关闭提示" />
</el-form-item>
<el-form-item v-if="activeData['active-value'] !== undefined" label="开启值">
<el-input
:value="setDefaultValue(activeData['active-value'])"
placeholder="请输入开启值"
@input="onSwitchValueInput($event, 'active-value')"
/>
</el-form-item>
<el-form-item v-if="activeData['inactive-value'] !== undefined" label="关闭值">
<el-input
:value="setDefaultValue(activeData['inactive-value'])"
placeholder="请输入关闭值"
@input="onSwitchValueInput($event, 'inactive-value')"
/>
</el-form-item>
<el-form-item
v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
label="时间类型"
>
<el-select
v-model="activeData.type"
placeholder="请选择时间类型"
:style="{ width: '100%' }"
@change="dateTypeChange"
>
<el-option
v-for="(item, index) in dateOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item v-if="activeData.name !== undefined" label="文件字段名">
<el-input v-model="activeData.name" placeholder="请输入上传文件字段名" />
</el-form-item>
<el-form-item v-if="activeData.accept !== undefined" label="文件类型">
<el-select
v-model="activeData.accept"
placeholder="请选择文件类型"
:style="{ width: '100%' }"
clearable
>
<el-option label="图片" value="image/*" />
<el-option label="视频" value="video/*" />
<el-option label="音频" value="audio/*" />
<el-option label="excel" value=".xls,.xlsx" />
<el-option label="word" value=".doc,.docx" />
<el-option label="pdf" value=".pdf" />
<el-option label="txt" value=".txt" />
</el-select>
</el-form-item>
<el-form-item v-if="activeData.fileSize !== undefined" label="文件大小">
<el-input v-model.number="activeData.fileSize" placeholder="请输入文件大小">
<el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
<el-option label="KB" value="KB" />
<el-option label="MB" value="MB" />
<el-option label="GB" value="GB" />
</el-select>
</el-input>
</el-form-item>
<el-form-item v-if="activeData.action !== undefined" label="上传地址">
<el-input v-model="activeData.action" placeholder="请输入上传地址" clearable />
</el-form-item>
<el-form-item v-if="activeData['list-type'] !== undefined" label="列表类型">
<el-radio-group v-model="activeData['list-type']" size="small">
<el-radio-button label="text">
text
</el-radio-button>
<el-radio-button label="picture">
picture
</el-radio-button>
<el-radio-button label="picture-card">
picture-card
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="activeData.buttonText !== undefined"
v-show="'picture-card' !== activeData['list-type']"
label="按钮文字"
>
<el-input v-model="activeData.buttonText" placeholder="请输入按钮文字" />
</el-form-item>
<el-form-item v-if="activeData['range-separator'] !== undefined" label="分隔符">
<el-input v-model="activeData['range-separator']" placeholder="请输入分隔符" />
</el-form-item>
<el-form-item v-if="activeData['picker-options'] !== undefined" label="时间段">
<el-input
v-model="activeData['picker-options'].selectableRange"
placeholder="请输入时间段"
/>
</el-form-item>
<el-form-item v-if="activeData.format !== undefined" label="时间格式">
<el-input
:value="activeData.format"
placeholder="请输入时间格式"
@input="setTimeValue($event)"
/>
</el-form-item>
<template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
<el-divider>选项</el-divider>
<draggable
:list="activeData.options"
:animation="340"
group="selectItem"
handle=".option-drag"
>
<div v-for="(item, index) in activeData.options" :key="index" class="select-item">
<div class="select-line-icon option-drag">
<i class="el-icon-s-operation" />
</div>
<el-input v-model="item.label" placeholder="选项名" size="small" />
<el-input
placeholder="选项值"
size="small"
:value="item.value"
@input="setOptionValue(item, $event)"
/>
<div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
<i class="el-icon-remove-outline" />
</div>
</div>
</draggable>
<div style="margin-left: 20px;">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addSelectItem"
>
添加选项
</el-button>
</div>
<el-divider />
</template>
<template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
<el-divider>选项</el-divider>
<el-form-item label="数据类型">
<el-radio-group v-model="activeData.dataType" size="small">
<el-radio-button label="dynamic">
动态数据
</el-radio-button>
<el-radio-button label="static">
静态数据
</el-radio-button>
</el-radio-group>
</el-form-item>
<template v-if="activeData.dataType === 'dynamic'">
<el-form-item label="标签键名">
<el-input v-model="activeData.labelKey" placeholder="请输入标签键名" />
</el-form-item>
<el-form-item label="值键名">
<el-input v-model="activeData.valueKey" placeholder="请输入值键名" />
</el-form-item>
<el-form-item label="子级键名">
<el-input v-model="activeData.childrenKey" placeholder="请输入子级键名" />
</el-form-item>
</template>
<el-tree
v-if="activeData.dataType === 'static'"
draggable
:data="activeData.options"
node-key="id"
:expand-on-click-node="false"
:render-content="renderContent"
/>
<div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
<el-button
style="padding-bottom: 0"
icon="el-icon-circle-plus-outline"
type="text"
@click="addTreeItem"
>
添加父级
</el-button>
</div>
<el-divider />
</template>
<el-form-item v-if="activeData.optionType !== undefined" label="选项样式">
<el-radio-group v-model="activeData.optionType">
<el-radio-button label="default">
默认
</el-radio-button>
<el-radio-button label="button">
按钮
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData['active-color'] !== undefined" label="开启颜色">
<el-color-picker v-model="activeData['active-color']" />
</el-form-item>
<el-form-item v-if="activeData['inactive-color'] !== undefined" label="关闭颜色">
<el-color-picker v-model="activeData['inactive-color']" />
</el-form-item>
<el-form-item v-if="activeData['allow-half'] !== undefined" label="允许半选">
<el-switch v-model="activeData['allow-half']" />
</el-form-item>
<el-form-item v-if="activeData['show-text'] !== undefined" label="辅助文字">
<el-switch v-model="activeData['show-text']" @change="rateTextChange" />
</el-form-item>
<el-form-item v-if="activeData['show-score'] !== undefined" label="显示分数">
<el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
</el-form-item>
<el-form-item v-if="activeData['show-stops'] !== undefined" label="显示间断点">
<el-switch v-model="activeData['show-stops']" />
</el-form-item>
<el-form-item v-if="activeData.range !== undefined" label="范围选择">
<el-switch v-model="activeData.range" @change="rangeChange" />
</el-form-item>
<el-form-item
v-if="activeData.border !== undefined && activeData.optionType === 'default'"
label="是否带边框"
>
<el-switch v-model="activeData.border" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-color-picker'" label="颜色格式">
<el-select
v-model="activeData['color-format']"
placeholder="请选择颜色格式"
:style="{ width: '100%' }"
@change="colorFormatChange"
>
<el-option
v-for="(item, index) in colorFormatOptions"
:key="index"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="activeData.size !== undefined &&
(activeData.optionType === 'button' ||
activeData.border ||
activeData.tag === 'el-color-picker')"
label="选项尺寸"
>
<el-radio-group v-model="activeData.size">
<el-radio-button label="medium">
中等
</el-radio-button>
<el-radio-button label="small">
较小
</el-radio-button>
<el-radio-button label="mini">
迷你
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="activeData['show-word-limit'] !== undefined" label="输入统计">
<el-switch v-model="activeData['show-word-limit']" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-input-number'" label="严格步数">
<el-switch v-model="activeData['step-strictly']" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-cascader'" label="是否多选">
<el-switch v-model="activeData.props.props.multiple" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-cascader'" label="展示全路径">
<el-switch v-model="activeData['show-all-levels']" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-cascader'" label="可否筛选">
<el-switch v-model="activeData.filterable" />
</el-form-item>
<el-form-item v-if="activeData.clearable !== undefined" label="能否清空">
<el-switch v-model="activeData.clearable" />
</el-form-item>
<el-form-item v-if="activeData.showTip !== undefined" label="显示提示">
<el-switch v-model="activeData.showTip" />
</el-form-item>
<el-form-item v-if="activeData.multiple !== undefined" label="多选文件">
<el-switch v-model="activeData.multiple" />
</el-form-item>
<el-form-item v-if="activeData['auto-upload'] !== undefined" label="自动上传">
<el-switch v-model="activeData['auto-upload']" />
</el-form-item>
<el-form-item v-if="activeData.readonly !== undefined" label="是否只读">
<el-switch v-model="activeData.readonly" />
</el-form-item>
<el-form-item v-if="activeData.disabled !== undefined" label="是否禁用">
<el-switch v-model="activeData.disabled" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-select'" label="是否可搜索">
<el-switch v-model="activeData.filterable" />
</el-form-item>
<el-form-item v-if="activeData.tag === 'el-select'" label="是否多选">
<el-switch v-model="activeData.multiple" @change="multipleChange" />
</el-form-item>
<el-form-item v-if="activeData.required !== undefined" label="是否必填">
<el-switch v-model="activeData.required" />
</el-form-item>
<template v-if="activeData.layoutTree">
<el-divider>布局结构树</el-divider>
<el-tree
:data="[activeData]"
:props="layoutTreeProps"
node-key="renderKey"
default-expand-all
draggable
>
<span slot-scope="{ node, data }">
<span class="node-label">
<svg-icon class="node-icon" :icon-class="data.tagIcon" />
{{ node.label }}
</span>
</span>
</el-tree>
</template>
<template v-if="activeData.layout === 'colFormItem'">
<el-divider>正则校验</el-divider>
<div
v-for="(item, index) in activeData.regList"
:key="index"
class="reg-item"
>
<span class="close-btn" @click="activeData.regList.splice(index, 1)">
<i class="el-icon-close" />
</span>
<el-form-item label="表达式">
<el-input v-model="item.pattern" placeholder="请输入正则" />
</el-form-item>
<el-form-item label="错误提示" style="margin-bottom:0">
<el-input v-model="item.message" placeholder="请输入错误提示" />
</el-form-item>
</div>
<div style="margin-left: 20px">
<el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
添加规则
</el-button>
</div>
</template>
</el-form>
<!-- 表单属性 -->
<el-form v-show="currentTab === 'form'" size="small" label-width="90px">
<el-form-item label="表单名">
<el-input v-model="formConf.formRef" placeholder="请输入表单名ref" />
</el-form-item>
<el-form-item label="表单模型">
<el-input v-model="formConf.formModel" placeholder="请输入数据模型" />
</el-form-item>
<el-form-item label="校验模型">
<el-input v-model="formConf.formRules" placeholder="请输入校验模型" />
</el-form-item>
<el-form-item label="表单尺寸">
<el-radio-group v-model="formConf.size">
<el-radio-button label="medium">
中等
</el-radio-button>
<el-radio-button label="small">
较小
</el-radio-button>
<el-radio-button label="mini">
迷你
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签对齐">
<el-radio-group v-model="formConf.labelPosition">
<el-radio-button label="left">
左对齐
</el-radio-button>
<el-radio-button label="right">
右对齐
</el-radio-button>
<el-radio-button label="top">
顶部对齐
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="标签宽度">
<el-input-number v-model="formConf.labelWidth" placeholder="标签宽度" />
</el-form-item>
<el-form-item label="栅格间隔">
<el-input-number v-model="formConf.gutter" :min="0" placeholder="栅格间隔" />
</el-form-item>
<el-form-item label="禁用表单">
<el-switch v-model="formConf.disabled" />
</el-form-item>
<el-form-item label="表单按钮">
<el-switch v-model="formConf.formBtns" />
</el-form-item>
<el-form-item label="显示未选中组件边框">
<el-switch v-model="formConf.unFocusedComponentBorder" />
</el-form-item>
</el-form>
</el-scrollbar>
</div>
<treeNode-dialog :visible.sync="dialogVisible" title="添加选项" @commit="addNode" />
<icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
</div>
</template>
<script>
import { isArray } from 'util'
import TreeNodeDialog from './TreeNodeDialog'
import { isNumberStr } from '@/utils/index'
import IconsDialog from './IconsDialog'
import {
inputComponents,
selectComponents,
layoutComponents
} from '@/utils/generator/config'
const dateTimeFormat = {
date: 'yyyy-MM-dd',
week: 'yyyy 第 WW 周',
month: 'yyyy-MM',
year: 'yyyy',
datetime: 'yyyy-MM-dd HH:mm:ss',
daterange: 'yyyy-MM-dd',
monthrange: 'yyyy-MM',
datetimerange: 'yyyy-MM-dd HH:mm:ss'
}
export default {
components: {
TreeNodeDialog,
IconsDialog
},
props: ['showField', 'activeData', 'formConf'],
data() {
return {
currentTab: 'field',
currentNode: null,
dialogVisible: false,
iconsVisible: false,
currentIconModel: null,
dateTypeOptions: [
{
label: '日(date)',
value: 'date'
},
{
label: '周(week)',
value: 'week'
},
{
label: '月(month)',
value: 'month'
},
{
label: '年(year)',
value: 'year'
},
{
label: '日期时间(datetime)',
value: 'datetime'
}
],
dateRangeTypeOptions: [
{
label: '日期范围(daterange)',
value: 'daterange'
},
{
label: '月范围(monthrange)',
value: 'monthrange'
},
{
label: '日期时间范围(datetimerange)',
value: 'datetimerange'
}
],
colorFormatOptions: [
{
label: 'hex',
value: 'hex'
},
{
label: 'rgb',
value: 'rgb'
},
{
label: 'rgba',
value: 'rgba'
},
{
label: 'hsv',
value: 'hsv'
},
{
label: 'hsl',
value: 'hsl'
}
],
justifyOptions: [
{
label: 'start',
value: 'start'
},
{
label: 'end',
value: 'end'
},
{
label: 'center',
value: 'center'
},
{
label: 'space-around',
value: 'space-around'
},
{
label: 'space-between',
value: 'space-between'
}
],
layoutTreeProps: {
label(data, node) {
return data.componentName || `${data.label}: ${data.vModel}`
}
}
}
},
computed: {
documentLink() {
return (
this.activeData.document
|| 'https://element.eleme.cn/#/zh-CN/component/installation'
)
},
dateOptions() {
if (
this.activeData.type !== undefined
&& this.activeData.tag === 'el-date-picker'
) {
if (this.activeData['start-placeholder'] === undefined) {
return this.dateTypeOptions
}
return this.dateRangeTypeOptions
}
return []
},
tagList() {
return [
{
label: '输入型组件',
options: inputComponents
},
{
label: '选择型组件',
options: selectComponents
}
]
}
},
methods: {
addReg() {
this.activeData.regList.push({
pattern: '',
message: ''
})
},
addSelectItem() {
this.activeData.options.push({
label: '',
value: ''
})
},
addTreeItem() {
++this.idGlobal
this.dialogVisible = true
this.currentNode = this.activeData.options
},
renderContent(h, { node, data, store }) {
return (
<div class="custom-tree-node">
<span>{node.label}</span>
<span class="node-operation">
<i on-click={() => this.append(data)}
class="el-icon-plus"
title="添加"
></i>
<i on-click={() => this.remove(node, data)}
class="el-icon-delete"
title="删除"
></i>
</span>
</div>
)
},
append(data) {
if (!data.children) {
this.$set(data, 'children', [])
}
this.dialogVisible = true
this.currentNode = data.children
},
remove(node, data) {
const { parent } = node
const children = parent.data.children || parent.data
const index = children.findIndex(d => d.id === data.id)
children.splice(index, 1)
},
addNode(data) {
this.currentNode.push(data)
},
setOptionValue(item, val) {
item.value = isNumberStr(val) ? +val : val
},
setDefaultValue(val) {
if (Array.isArray(val)) {
return val.join(',')
}
if (['string', 'number'].indexOf(val) > -1) {
return val
}
if (typeof val === 'boolean') {
return `${val}`
}
return val
},
onDefaultValueInput(str) {
if (isArray(this.activeData.defaultValue)) {
// 数组
this.$set(
this.activeData,
'defaultValue',
str.split(',').map(val => (isNumberStr(val) ? +val : val))
)
} else if (['true', 'false'].indexOf(str) > -1) {
// 布尔
this.$set(this.activeData, 'defaultValue', JSON.parse(str))
} else {
// 字符串和数字
this.$set(
this.activeData,
'defaultValue',
isNumberStr(str) ? +str : str
)
}
},
onSwitchValueInput(val, name) {
if (['true', 'false'].indexOf(val) > -1) {
this.$set(this.activeData, name, JSON.parse(val))
} else {
this.$set(this.activeData, name, isNumberStr(val) ? +val : val)
}
},
setTimeValue(val, type) {
const valueFormat = type === 'week' ? dateTimeFormat.date : val
this.$set(this.activeData, 'defaultValue', null)
this.$set(this.activeData, 'value-format', valueFormat)
this.$set(this.activeData, 'format', val)
},
spanChange(val) {
this.formConf.span = val
},
multipleChange(val) {
this.$set(this.activeData, 'defaultValue', val ? [] : '')
},
dateTypeChange(val) {
this.setTimeValue(dateTimeFormat[val], val)
},
rangeChange(val) {
this.$set(
this.activeData,
'defaultValue',
val ? [this.activeData.min, this.activeData.max] : this.activeData.min
)
},
rateTextChange(val) {
if (val) this.activeData['show-score'] = false
},
rateScoreChange(val) {
if (val) this.activeData['show-text'] = false
},
colorFormatChange(val) {
this.activeData.defaultValue = null
this.activeData['show-alpha'] = val.indexOf('a') > -1
this.activeData.renderKey = +new Date() // 更新renderKey,重新渲染该组件
},
openIconsDialog(model) {
this.iconsVisible = true
this.currentIconModel = model
},
setIcon(val) {
this.activeData[this.currentIconModel] = val
},
tagChange(tagIcon) {
let target = inputComponents.find(item => item.tagIcon === tagIcon)
if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
this.$emit('tag-change', target)
}
}
}
</script>
<style lang="scss" scoped>
.right-board {
width: 350px;
position: absolute;
right: 0;
top: 0;
padding-top: 3px;
.field-box {
position: relative;
height: calc(100vh - 42px);
box-sizing: border-box;
overflow: hidden;
}
.el-scrollbar {
height: 100%;
}
}
.select-item {
display: flex;
border: 1px dashed #fff;
box-sizing: border-box;
& .close-btn {
cursor: pointer;
color: #f56c6c;
}
& .el-input + .el-input {
margin-left: 4px;
}
}
.select-item + .select-item {
margin-top: 4px;
}
.select-item.sortable-chosen {
border: 1px dashed #409eff;
}
.select-line-icon {
line-height: 32px;
font-size: 22px;
padding: 0 4px;
color: #777;
}
.option-drag {
cursor: move;
}
.time-range {
.el-date-editor {
width: 227px;
}
::v-deep .el-icon-time {
display: none;
}
}
.document-link {
position: absolute;
display: block;
width: 26px;
height: 26px;
top: 0;
left: 0;
cursor: pointer;
background: #409eff;
z-index: 1;
border-radius: 0 0 6px 0;
text-align: center;
line-height: 26px;
color: #fff;
font-size: 18px;
}
.node-label{
font-size: 14px;
}
.node-icon{
color: #bebfc3;
}
</style>

View File

@ -0,0 +1,149 @@
<template>
<div>
<el-dialog
v-bind="$attrs"
:close-on-click-modal="false"
:modal-append-to-body="false"
v-on="$listeners"
@open="onOpen"
@close="onClose"
>
<el-row :gutter="0">
<el-form
ref="elForm"
:model="formData"
:rules="rules"
size="small"
label-width="100px"
>
<el-col :span="24">
<el-form-item
label="选项名"
prop="label"
>
<el-input
v-model="formData.label"
placeholder="请输入选项名"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item
label="选项值"
prop="value"
>
<el-input
v-model="formData.value"
placeholder="请输入选项值"
clearable
>
<el-select
slot="append"
v-model="dataType"
:style="{width: '100px'}"
>
<el-option
v-for="(item, index) in dataTypeOptions"
:key="index"
:label="item.label"
:value="item.value"
:disabled="item.disabled"
/>
</el-select>
</el-input>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer">
<el-button
type="primary"
@click="handelConfirm"
>
确定
</el-button>
<el-button @click="close">
取消
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { isNumberStr } from '@/utils/index'
export default {
components: {},
inheritAttrs: false,
props: [],
data() {
return {
id: 100,
formData: {
label: undefined,
value: undefined
},
rules: {
label: [
{
required: true,
message: '请输入选项名',
trigger: 'blur'
}
],
value: [
{
required: true,
message: '请输入选项值',
trigger: 'blur'
}
]
},
dataType: 'string',
dataTypeOptions: [
{
label: '字符串',
value: 'string'
},
{
label: '数字',
value: 'number'
}
]
}
},
computed: {},
watch: {
// eslint-disable-next-line func-names
'formData.value': function (val) {
this.dataType = isNumberStr(val) ? 'number' : 'string'
}
},
created() {},
mounted() {},
methods: {
onOpen() {
this.formData = {
label: undefined,
value: undefined
}
},
onClose() {},
close() {
this.$emit('update:visible', false)
},
handelConfirm() {
this.$refs.elForm.validate(valid => {
if (!valid) return
if (this.dataType === 'number') {
this.formData.value = parseFloat(this.formData.value)
}
this.formData.id = this.id++
this.$emit('commit', this.formData)
this.close()
})
}
}
}
</script>

View File

@ -1,5 +1,789 @@
<template> <template>
<div class="app-container"> <div class="container">
构建工具 <div class="left-board">
<div class="logo-wrapper">
<div class="logo">
<img :src="logo" alt="logo"> Form Generator
</div>
</div>
<el-scrollbar class="left-scrollbar">
<div class="components-list">
<div class="components-title">
<svg-icon icon-class="component" />输入型组件
</div>
<draggable
class="components-draggable"
:list="inputComponents"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@end="onEnd"
>
<div
v-for="(element, index) in inputComponents" :key="index" class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<svg-icon :icon-class="element.tagIcon" />
{{ element.label }}
</div>
</div>
</draggable>
<div class="components-title">
<svg-icon icon-class="component" />选择型组件
</div>
<draggable
class="components-draggable"
:list="selectComponents"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }"
:clone="cloneComponent"
draggable=".components-item"
:sort="false"
@end="onEnd"
>
<div
v-for="(element, index) in selectComponents"
:key="index"
class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<svg-icon :icon-class="element.tagIcon" />
{{ element.label }}
</div>
</div>
</draggable>
<div class="components-title">
<svg-icon icon-class="component" /> 布局型组件
</div>
<draggable
class="components-draggable" :list="layoutComponents"
:group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
draggable=".components-item" :sort="false" @end="onEnd"
>
<div
v-for="(element, index) in layoutComponents" :key="index" class="components-item"
@click="addComponent(element)"
>
<div class="components-body">
<svg-icon :icon-class="element.tagIcon" />
{{ element.label }}
</div>
</div>
</draggable>
</div>
</el-scrollbar>
</div>
<div class="center-board">
<div class="action-bar">
<el-button icon="el-icon-download" type="text" @click="download">
导出vue文件
</el-button>
<el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
复制代码
</el-button>
<el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
清空
</el-button>
</div>
<el-scrollbar class="center-scrollbar">
<el-row class="center-board-row" :gutter="formConf.gutter">
<el-form
:size="formConf.size"
:label-position="formConf.labelPosition"
:disabled="formConf.disabled"
:label-width="formConf.labelWidth + 'px'"
>
<draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
<draggable-item
v-for="(element, index) in drawingList"
:key="element.renderKey"
:drawing-list="drawingList"
:element="element"
:index="index"
:active-id="activeId"
:form-conf="formConf"
@activeItem="activeFormItem"
@copyItem="drawingItemCopy"
@deleteItem="drawingItemDelete"
/>
</draggable>
<div v-show="!drawingList.length" class="empty-info">
从左侧拖入或点选组件进行表单设计
</div>
</el-form>
</el-row>
</el-scrollbar>
</div>
<right-panel
:active-data="activeData"
:form-conf="formConf"
:show-field="!!drawingList.length"
@tag-change="tagChange"
/>
<code-type-dialog
:visible.sync="dialogVisible"
title="选择生成类型"
:show-file-name="showFileName"
@confirm="generate"
/>
<input id="copyNode" type="hidden">
</div> </div>
</template> </template>
<script>
import draggable from 'vuedraggable'
import { saveAs } from 'file-saver'
import beautifier from 'js-beautify'
import ClipboardJS from 'clipboard'
import render from '@/utils/generator/render'
import RightPanel from './RightPanel'
import {
inputComponents,
selectComponents,
layoutComponents,
formConf
} from '@/utils/generator/config'
import {
exportDefault, beautifierConf, isNumberStr, titleCase
} from '@/utils/index'
import {
makeUpHtml, vueTemplate, vueScript, cssStyle
} from '@/utils/generator/html'
import { makeUpJs } from '@/utils/generator/js'
import { makeUpCss } from '@/utils/generator/css'
import drawingDefalut from '@/utils/generator/drawingDefalut'
import logo from '@/assets/logo/logo.png'
import CodeTypeDialog from './CodeTypeDialog'
import DraggableItem from './DraggableItem'
const emptyActiveData = { style: {}, autosize: {} }
let oldActiveId
let tempActiveData
export default {
components: {
draggable,
render,
RightPanel,
CodeTypeDialog,
DraggableItem
},
data() {
return {
logo,
idGlobal: 100,
formConf,
inputComponents,
selectComponents,
layoutComponents,
labelWidth: 100,
drawingList: drawingDefalut,
drawingData: {},
activeId: drawingDefalut[0].formId,
drawerVisible: false,
formData: {},
dialogVisible: false,
generateConf: null,
showFileName: false,
activeData: drawingDefalut[0]
}
},
computed: {
},
watch: {
// eslint-disable-next-line func-names
'activeData.label': function (val, oldVal) {
if (
this.activeData.placeholder === undefined
|| !this.activeData.tag
|| oldActiveId !== this.activeId
) {
return
}
this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
},
activeId: {
handler(val) {
oldActiveId = val
},
immediate: true
}
},
mounted() {
const clipboard = new ClipboardJS('#copyNode', {
text: trigger => {
const codeStr = this.generateCode()
this.$notify({
title: '成功',
message: '代码已复制到剪切板,可粘贴。',
type: 'success'
})
return codeStr
}
})
clipboard.on('error', e => {
this.$message.error('代码复制失败')
})
},
methods: {
activeFormItem(element) {
this.activeData = element
this.activeId = element.formId
},
onEnd(obj, a) {
if (obj.from !== obj.to) {
this.activeData = tempActiveData
this.activeId = this.idGlobal
}
},
addComponent(item) {
const clone = this.cloneComponent(item)
this.drawingList.push(clone)
this.activeFormItem(clone)
},
cloneComponent(origin) {
const clone = JSON.parse(JSON.stringify(origin))
clone.formId = ++this.idGlobal
clone.span = formConf.span
clone.renderKey = +new Date() // 改变renderKey后可以实现强制更新组件
if (!clone.layout) clone.layout = 'colFormItem'
if (clone.layout === 'colFormItem') {
clone.vModel = `field${this.idGlobal}`
clone.placeholder !== undefined && (clone.placeholder += clone.label)
tempActiveData = clone
} else if (clone.layout === 'rowFormItem') {
delete clone.label
clone.componentName = `row${this.idGlobal}`
clone.gutter = this.formConf.gutter
tempActiveData = clone
}
return tempActiveData
},
AssembleFormData() {
this.formData = {
fields: JSON.parse(JSON.stringify(this.drawingList)),
...this.formConf
}
},
generate(data) {
const func = this[`exec${titleCase(this.operationType)}`]
this.generateConf = data
func && func(data)
},
execRun(data) {
this.AssembleFormData()
this.drawerVisible = true
},
execDownload(data) {
const codeStr = this.generateCode()
const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
saveAs(blob, data.fileName)
},
execCopy(data) {
document.getElementById('copyNode').click()
},
empty() {
this.$confirm('确定要清空所有组件吗?', '提示', { type: 'warning' }).then(
() => {
this.drawingList = []
}
)
},
drawingItemCopy(item, parent) {
let clone = JSON.parse(JSON.stringify(item))
clone = this.createIdAndKey(clone)
parent.push(clone)
this.activeFormItem(clone)
},
createIdAndKey(item) {
item.formId = ++this.idGlobal
item.renderKey = +new Date()
if (item.layout === 'colFormItem') {
item.vModel = `field${this.idGlobal}`
} else if (item.layout === 'rowFormItem') {
item.componentName = `row${this.idGlobal}`
}
if (Array.isArray(item.children)) {
item.children = item.children.map(childItem => this.createIdAndKey(childItem))
}
return item
},
drawingItemDelete(index, parent) {
parent.splice(index, 1)
this.$nextTick(() => {
const len = this.drawingList.length
if (len) {
this.activeFormItem(this.drawingList[len - 1])
}
})
},
generateCode() {
const { type } = this.generateConf
this.AssembleFormData()
const script = vueScript(makeUpJs(this.formData, type))
const html = vueTemplate(makeUpHtml(this.formData, type))
const css = cssStyle(makeUpCss(this.formData))
return beautifier.html(html + script + css, beautifierConf.html)
},
download() {
this.dialogVisible = true
this.showFileName = true
this.operationType = 'download'
},
run() {
this.dialogVisible = true
this.showFileName = false
this.operationType = 'run'
},
copy() {
this.dialogVisible = true
this.showFileName = false
this.operationType = 'copy'
},
tagChange(newTag) {
newTag = this.cloneComponent(newTag)
newTag.vModel = this.activeData.vModel
newTag.formId = this.activeId
newTag.span = this.activeData.span
delete this.activeData.tag
delete this.activeData.tagIcon
delete this.activeData.document
Object.keys(newTag).forEach(key => {
if (this.activeData[key] !== undefined
&& typeof this.activeData[key] === typeof newTag[key]) {
newTag[key] = this.activeData[key]
}
})
this.activeData = newTag
this.updateDrawingList(newTag, this.drawingList)
},
updateDrawingList(newTag, list) {
const index = list.findIndex(item => item.formId === this.activeId)
if (index > -1) {
list.splice(index, 1, newTag)
} else {
list.forEach(item => {
if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
})
}
}
}
}
</script>
<style lang='scss'>
body, html{
margin: 0;
padding: 0;
background: #fff;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
}
input, textarea{
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
}
.editor-tabs{
background: #121315;
.el-tabs__header{
margin: 0;
border-bottom-color: #121315;
.el-tabs__nav{
border-color: #121315;
}
}
.el-tabs__item{
height: 32px;
line-height: 32px;
color: #888a8e;
border-left: 1px solid #121315 !important;
background: #363636;
margin-right: 5px;
user-select: none;
}
.el-tabs__item.is-active{
background: #1e1e1e;
border-bottom-color: #1e1e1e!important;
color: #fff;
}
.el-icon-edit{
color: #f1fa8c;
}
.el-icon-document{
color: #a95812;
}
}
// home
.right-scrollbar {
.el-scrollbar__view {
padding: 12px 18px 15px 15px;
}
}
.el-scrollbar__wrap {
box-sizing: border-box;
overflow-x: hidden !important;
margin-bottom: 0 !important;
}
.center-tabs{
.el-tabs__header{
margin-bottom: 0!important;
}
.el-tabs__item{
width: 50%;
text-align: center;
}
.el-tabs__nav{
width: 100%;
}
}
.reg-item{
padding: 12px 6px;
background: #f8f8f8;
position: relative;
border-radius: 4px;
.close-btn{
position: absolute;
right: -6px;
top: -6px;
display: block;
width: 16px;
height: 16px;
line-height: 16px;
background: rgba(0, 0, 0, 0.2);
border-radius: 50%;
color: #fff;
text-align: center;
z-index: 1;
cursor: pointer;
font-size: 12px;
&:hover{
background: rgba(210, 23, 23, 0.5)
}
}
& + .reg-item{
margin-top: 18px;
}
}
.action-bar{
& .el-button+.el-button {
margin-left: 15px;
}
& i {
font-size: 20px;
vertical-align: middle;
position: relative;
top: -1px;
}
}
.custom-tree-node{
width: 100%;
font-size: 14px;
.node-operation{
float: right;
}
i[class*="el-icon"] + i[class*="el-icon"]{
margin-left: 6px;
}
.el-icon-plus{
color: #409EFF;
}
.el-icon-delete{
color: #157a0c;
}
}
.el-scrollbar__view{
overflow-x: hidden;
}
.el-rate{
display: inline-block;
vertical-align: text-top;
}
.el-upload__tip{
line-height: 1.2;
}
$selectedColor: #f6f7ff;
$lighterBlue: #409EFF;
.container {
position: relative;
width: 100%;
height: 100%;
}
.components-list {
padding: 8px;
box-sizing: border-box;
height: 100%;
.components-item {
display: inline-block;
width: 48%;
margin: 1%;
transition: transform 0ms !important;
}
}
.components-draggable{
padding-bottom: 20px;
}
.components-title{
font-size: 14px;
color: #222;
margin: 6px 2px;
.svg-icon{
color: #666;
font-size: 18px;
}
}
.components-body {
padding: 8px 10px;
background: $selectedColor;
font-size: 12px;
cursor: move;
border: 1px dashed $selectedColor;
border-radius: 3px;
.svg-icon{
color: #777;
font-size: 15px;
}
&:hover {
border: 1px dashed #787be8;
color: #787be8;
.svg-icon {
color: #787be8;
}
}
}
.left-board {
width: 260px;
position: absolute;
left: 0;
top: 0;
height: 100vh;
}
.left-scrollbar{
height: calc(100vh - 42px);
overflow: hidden;
}
.center-scrollbar {
height: calc(100vh - 42px);
overflow: hidden;
border-left: 1px solid #f1e8e8;
border-right: 1px solid #f1e8e8;
box-sizing: border-box;
}
.center-board {
height: 100vh;
width: auto;
margin: 0 350px 0 260px;
box-sizing: border-box;
}
.empty-info{
position: absolute;
top: 46%;
left: 0;
right: 0;
text-align: center;
font-size: 18px;
color: #ccb1ea;
letter-spacing: 4px;
}
.action-bar{
position: relative;
height: 42px;
text-align: right;
padding: 0 15px;
box-sizing: border-box;;
border: 1px solid #f1e8e8;
border-top: none;
border-left: none;
.delete-btn{
color: #F56C6C;
}
}
.logo-wrapper{
position: relative;
height: 42px;
background: #fff;
border-bottom: 1px solid #f1e8e8;
box-sizing: border-box;
}
.logo{
position: absolute;
left: 12px;
top: 6px;
line-height: 30px;
color: #00afff;
font-weight: 600;
font-size: 17px;
white-space: nowrap;
> img{
width: 30px;
height: 30px;
vertical-align: top;
}
.github{
display: inline-block;
vertical-align: sub;
margin-left: 15px;
> img{
height: 22px;
}
}
}
.center-board-row {
padding: 12px 12px 15px 12px;
box-sizing: border-box;
& > .el-form {
// 69 = 12+15+42
height: calc(100vh - 69px);
}
}
.drawing-board {
height: 100%;
position: relative;
.components-body {
padding: 0;
margin: 0;
font-size: 0;
}
.sortable-ghost {
position: relative;
display: block;
overflow: hidden;
&::before {
content: " ";
position: absolute;
left: 0;
right: 0;
top: 0;
height: 3px;
background: rgb(89, 89, 223);
z-index: 2;
}
}
.components-item.sortable-ghost {
width: 100%;
height: 60px;
background-color: $selectedColor;
}
.active-from-item {
& > .el-form-item{
background: $selectedColor;
border-radius: 6px;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
& > .component-name{
color: $lighterBlue;
}
}
.el-form-item{
margin-bottom: 15px;
}
}
.drawing-item{
position: relative;
cursor: move;
&.unfocus-bordered:not(.activeFromItem) > div:first-child {
border: 1px dashed #ccc;
}
.el-form-item{
padding: 12px 10px;
}
}
.drawing-row-item{
position: relative;
cursor: move;
box-sizing: border-box;
border: 1px dashed #ccc;
border-radius: 3px;
padding: 0 2px;
margin-bottom: 15px;
.drawing-row-item {
margin-bottom: 2px;
}
.el-col{
margin-top: 22px;
}
.el-form-item{
margin-bottom: 0;
}
.drag-wrapper{
min-height: 80px;
}
&.active-from-item{
border: 1px dashed $lighterBlue;
}
.component-name{
position: absolute;
top: 0;
left: 0;
font-size: 12px;
color: #bbb;
display: inline-block;
padding: 0 6px;
}
}
.drawing-item, .drawing-row-item{
&:hover {
& > .el-form-item{
background: $selectedColor;
border-radius: 6px;
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: initial;
}
}
& > .drawing-item-copy, & > .drawing-item-delete{
display: none;
position: absolute;
top: -10px;
width: 22px;
height: 22px;
line-height: 22px;
text-align: center;
border-radius: 50%;
font-size: 12px;
border: 1px solid;
cursor: pointer;
z-index: 1;
}
& > .drawing-item-copy{
right: 56px;
border-color: $lighterBlue;
color: $lighterBlue;
background: #fff;
&:hover{
background: $lighterBlue;
color: #fff;
}
}
& > .drawing-item-delete{
right: 24px;
border-color: #F56C6C;
color: #F56C6C;
background: #fff;
&:hover{
background: #F56C6C;
color: #fff;
}
}
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<el-form ref="basicInfoForm" :model="info" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item label="表名称" prop="tableName">
<el-input placeholder="请输入仓库名称" v-model="info.tableName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="表描述" prop="tableComment">
<el-input placeholder="请输入" v-model="info.tableComment" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="实体类名称" prop="className">
<el-input placeholder="请输入" v-model="info.className" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="作者" prop="functionAuthor">
<el-input placeholder="请输入" v-model="info.functionAuthor" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input type="textarea" :rows="3" v-model="info.remark"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: "BasicInfoForm",
props: {
info: {
type: Object,
default: null
}
},
data() {
return {
rules: {
tableName: [
{ required: true, message: "请输入表名称", trigger: "blur" }
],
tableComment: [
{ required: true, message: "请输入表描述", trigger: "blur" }
],
className: [
{ required: true, message: "请输入实体类名称", trigger: "blur" }
],
functionAuthor: [
{ required: true, message: "请输入作者", trigger: "blur" }
]
}
};
}
};
</script>

View File

@ -0,0 +1,203 @@
<template>
<el-card>
<el-tabs v-model="activeName">
<el-tab-pane label="基本信息" name="basic">
<basic-info-form ref="basicInfo" :info="info" />
</el-tab-pane>
<el-tab-pane label="字段信息" name="cloum">
<el-table :data="cloumns" :max-height="tableHeight">
<el-table-column label="序号" type="index" min-width="5%" />
<el-table-column
label="字段列名"
prop="columnName"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="字段描述" min-width="10%">
<template slot-scope="scope">
<el-input v-model="scope.row.columnComment"></el-input>
</template>
</el-table-column>
<el-table-column
label="物理类型"
prop="columnType"
min-width="10%"
:show-overflow-tooltip="true"
/>
<el-table-column label="Java类型" min-width="11%">
<template slot-scope="scope">
<el-select v-model="scope.row.javaType">
<el-option label="Long" value="Long" />
<el-option label="String" value="String" />
<el-option label="Integer" value="Integer" />
<el-option label="Double" value="Double" />
<el-option label="BigDecimal" value="BigDecimal" />
<el-option label="Date" value="Date" />
</el-select>
</template>
</el-table-column>
<el-table-column label="java属性" min-width="10%">
<template slot-scope="scope">
<el-input v-model="scope.row.javaField"></el-input>
</template>
</el-table-column>
<el-table-column label="插入" min-width="5%">
<template slot-scope="scope">
<el-checkbox true-label="1" v-model="scope.row.isInsert"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="编辑" min-width="5%">
<template slot-scope="scope">
<el-checkbox true-label="1" v-model="scope.row.isEdit"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="列表" min-width="5%">
<template slot-scope="scope">
<el-checkbox true-label="1" v-model="scope.row.isList"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询" min-width="5%">
<template slot-scope="scope">
<el-checkbox true-label="1" v-model="scope.row.isQuery"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="查询方式" min-width="10%">
<template slot-scope="scope">
<el-select v-model="scope.row.queryType">
<el-option label="=" value="EQ" />
<el-option label="!=" value="NE" />
<el-option label=">" value="GT" />
<el-option label=">=" value="GTE" />
<el-option label="<" value="LT" />
<el-option label="<=" value="LTE" />
<el-option label="LIKE" value="LIKE" />
<el-option label="BETWEEN" value="BETWEEN" />
</el-select>
</template>
</el-table-column>
<el-table-column label="必填" min-width="5%">
<template slot-scope="scope">
<el-checkbox true-label="1" v-model="scope.row.isRequired"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="显示类型" min-width="12%">
<template slot-scope="scope">
<el-select v-model="scope.row.htmlType">
<el-option label="文本框" value="input" />
<el-option label="文本域" value="textarea" />
<el-option label="下拉框" value="select" />
<el-option label="单选框" value="radio" />
<el-option label="复选框" value="checkbox" />
<el-option label="日期控件" value="datetime" />
</el-select>
</template>
</el-table-column>
<el-table-column label="字典类型" min-width="12%">
<template slot-scope="scope">
<el-select v-model="scope.row.dictType" clearable filterable placeholder="请选择">
<el-option
v-for="dict in dictOptions"
:key="dict.dictType"
:label="dict.dictName"
:value="dict.dictType">
<span style="float: left">{{ dict.dictName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
</el-option>
</el-select>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="生成信息" name="genInfo">
<gen-info-form ref="genInfo" :info="info" />
</el-tab-pane>
</el-tabs>
<el-form label-width="100px">
<el-form-item style="text-align: center;margin-left:-100px;margin-top:10px;">
<el-button type="primary" @click="submitForm()">提交</el-button>
<el-button @click="close()">返回</el-button>
</el-form-item>
</el-form>
</el-card>
</template>
<script>
import { getGenTable, updateGenTable } from "@/api/tool/gen";
import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
import basicInfoForm from "./basicInfoForm";
import genInfoForm from "./genInfoForm";
export default {
name: "GenEdit",
components: {
basicInfoForm,
genInfoForm
},
data() {
return {
// 选中选项卡的 name
activeName: "cloum",
// 表格的高度
tableHeight: document.documentElement.scrollHeight - 245 + "px",
// 表列信息
cloumns: [],
// 字典信息
dictOptions: [],
// 表详细信息
info: {}
};
},
beforeCreate() {
const { tableId } = this.$route.query;
if (tableId) {
// 获取表详细信息
getGenTable(tableId).then(res => {
this.cloumns = res.data.rows;
this.info = res.data.info;
});
/** 查询字典下拉列表 */
getDictOptionselect().then(response => {
this.dictOptions = response.data;
});
}
},
methods: {
/** 提交按钮 */
submitForm() {
const basicForm = this.$refs.basicInfo.$refs.basicInfoForm;
const genForm = this.$refs.genInfo.$refs.genInfoForm;
Promise.all([basicForm, genForm].map(this.getFormPromise)).then(res => {
const validateResult = res.every(item => !!item);
if (validateResult) {
const genTable = Object.assign({}, basicForm.model, genForm.model);
genTable.columns = this.cloumns;
genTable.params = {
treeCode: genTable.treeCode,
treeName: genTable.treeName,
treeParentCode: genTable.treeParentCode
};
updateGenTable(genTable).then(res => {
this.msgSuccess(res.msg);
if (res.code === 200) {
this.close();
}
});
} else {
this.msgError("表单校验未通过,请重新检查提交内容");
}
});
},
getFormPromise(form) {
return new Promise(resolve => {
form.validate(res => {
resolve(res);
});
});
},
/** 关闭按钮 */
close() {
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.push({ path: "/tool/gen", query: { t: Date.now()}})
}
}
};
</script>

View File

@ -0,0 +1,154 @@
<template>
<el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
<el-row>
<el-col :span="12">
<el-form-item prop="tplCategory">
<span slot="label">生成模板</span>
<el-select v-model="info.tplCategory">
<el-option label="单表(增删改查)" value="crud" />
<el-option label="树表(增删改查)" value="tree"/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="packageName">
<span slot="label">
生成包路径
<el-tooltip content="生成在哪个java包下例如 com.ruoyi.system" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="info.packageName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="moduleName">
<span slot="label">
生成模块名
<el-tooltip content="可理解为子系统名,例如 system" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="info.moduleName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="businessName">
<span slot="label">
生成业务名
<el-tooltip content="可理解为功能英文名,例如 user" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="info.businessName" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="functionName">
<span slot="label">
生成功能名
<el-tooltip content="用作类描述,例如 用户" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="info.functionName" />
</el-form-item>
</el-col>
</el-row>
<el-row v-show="info.tplCategory == 'tree'">
<h4 class="form-header">其他信息</h4>
<el-col :span="12">
<el-form-item>
<span slot="label">
树编码字段
<el-tooltip content="树显示的编码字段名, 如dept_id" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-select v-model="info.treeCode" placeholder="请选择">
<el-option
v-for="column in info.columns"
:key="column.columnName"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<span slot="label">
树父编码字段
<el-tooltip content="树显示的父编码字段名, 如parent_Id" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-select v-model="info.treeParentCode" placeholder="请选择">
<el-option
v-for="column in info.columns"
:key="column.columnName"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<span slot="label">
树名称字段
<el-tooltip content="树节点的显示名称字段名, 如dept_name" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-select v-model="info.treeName" placeholder="请选择">
<el-option
v-for="column in info.columns"
:key="column.columnName"
:label="column.columnName + '' + column.columnComment"
:value="column.columnName"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
</template>
<script>
export default {
name: "BasicInfoForm",
props: {
info: {
type: Object,
default: null
}
},
data() {
return {
rules: {
tplCategory: [
{ required: true, message: "请选择生成模板", trigger: "blur" }
],
packageName: [
{ required: true, message: "请输入生成包路径", trigger: "blur" }
],
moduleName: [
{ required: true, message: "请输入生成模块名", trigger: "blur" }
],
businessName: [
{ required: true, message: "请输入生成业务名", trigger: "blur" }
],
functionName: [
{ required: true, message: "请输入生成功能名", trigger: "blur" }
]
}
};
},
created() {}
};
</script>

View File

@ -0,0 +1,117 @@
<template>
<!-- 导入表 -->
<el-dialog title="导入表" :visible.sync="visible" width="800px" top="5vh">
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row>
<el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="tableName" label="表名称"></el-table-column>
<el-table-column prop="tableComment" label="表描述"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column prop="updateTime" label="更新时间"></el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="handleImportTable"> </el-button>
<el-button @click="visible = false"> </el-button>
</div>
</el-dialog>
</template>
<script>
import { listDbTable, importTable } from "@/api/tool/gen";
export default {
data() {
return {
// 遮罩层
visible: false,
// 选中数组值
tables: [],
// 总条数
total: 0,
// 表数据
dbTableList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
}
};
},
methods: {
// 显示弹框
show() {
this.getList();
this.visible = true;
},
clickRow(row) {
this.$refs.table.toggleRowSelection(row);
},
// 多选框选中数据
handleSelectionChange(selection) {
this.tables = selection.map(item => item.tableName);
},
// 查询表数据
getList() {
listDbTable(this.queryParams).then(res => {
if (res.code === 200) {
this.dbTableList = res.rows;
this.total = res.total;
}
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 导入按钮操作 */
handleImportTable() {
importTable({ tables: this.tables.join(",") }).then(res => {
this.msgSuccess(res.msg);
if (res.code === 200) {
this.visible = false;
this.$emit("ok");
}
});
}
}
};
</script>

View File

@ -1,5 +1,287 @@
<template> <template>
<div class="app-container"> <div class="app-container">
代码生成 <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
placeholder="请输入表名称"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表描述" prop="tableComment">
<el-input
v-model="queryParams.tableComment"
placeholder="请输入表描述"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker
v-model="dateRange"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-download"
size="mini"
@click="handleGenTable"
v-hasPermi="['tool:gen:code']"
>生成</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="info"
icon="el-icon-upload"
size="mini"
@click="openImportTable"
v-hasPermi="['tool:gen:import']"
>导入</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
icon="el-icon-edit"
size="mini"
:disabled="single"
@click="handleEditTable"
v-hasPermi="['tool:gen:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
:disabled="multiple"
@click="handleDelete"
v-hasPermi="['tool:gen:remove']"
>删除</el-button>
</el-col>
</el-row>
<el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column label="序号" align="center" prop="tableId" width="50px" />
<el-table-column
label="表名称"
align="center"
prop="tableName"
:show-overflow-tooltip="true"
width="130"
/>
<el-table-column
label="表描述"
align="center"
prop="tableComment"
:show-overflow-tooltip="true"
width="130"
/>
<el-table-column
label="实体"
align="center"
prop="className"
:show-overflow-tooltip="true"
width="130"
/>
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button
type="text"
size="small"
icon="el-icon-view"
@click="handlePreview(scope.row)"
v-hasPermi="['tool:gen:preview']"
>预览</el-button>
<el-button
type="text"
size="small"
icon="el-icon-edit"
@click="handleEditTable(scope.row)"
v-hasPermi="['tool:gen:edit']"
>编辑</el-button>
<el-button
type="text"
size="small"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['tool:gen:remove']"
>删除</el-button>
<el-button
type="text"
size="small"
icon="el-icon-download"
@click="handleGenTable(scope.row)"
v-hasPermi="['tool:gen:code']"
>生成代码</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 预览界面 -->
<el-dialog :title="preview.title" :visible.sync="preview.open" width="80%" top="5vh">
<el-tabs v-model="preview.activeName">
<el-tab-pane
v-for="(value, key) in preview.data"
:label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:key="key"
>
<pre>{{ value }}</pre>
</el-tab-pane>
</el-tabs>
</el-dialog>
<import-table ref="import" @ok="handleQuery" />
</div> </div>
</template> </template>
<script>
import { listTable, previewTable, delTable } from "@/api/tool/gen";
import importTable from "./importTable";
import { downLoadZip } from "@/utils/zipdownload";
export default {
name: "Gen",
components: { importTable },
data() {
return {
// 遮罩层
loading: true,
// 唯一标识符
uniqueId: "",
// 选中数组
ids: [],
// 选中表数组
tableNames: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 总条数
total: 0,
// 表数据
tableList: [],
// 日期范围
dateRange: "",
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
tableName: undefined,
tableComment: undefined
},
// 预览参数
preview: {
open: false,
title: "代码预览",
data: {},
activeName: "domain.java"
}
};
},
created() {
this.getList();
},
activated() {
const time = this.$route.query.t;
if (time != null && time != this.uniqueId) {
this.uniqueId = time;
this.resetQuery();
}
},
methods: {
/** 查询表集合 */
getList() {
this.loading = true;
listTable(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.tableList = response.rows;
this.total = response.total;
this.loading = false;
}
);
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 生成代码操作 */
handleGenTable(row) {
const tableNames = row.tableName || this.tableNames;
if (tableNames == "") {
this.msgError("请选择要生成的数据");
return;
}
downLoadZip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
},
/** 打开导入表弹窗 */
openImportTable() {
this.$refs.import.show();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 预览按钮 */
handlePreview(row) {
previewTable(row.tableId).then(response => {
this.preview.data = response.data;
this.preview.open = true;
});
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.tableId);
this.tableNames = selection.map(item => item.tableName);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
/** 修改按钮操作 */
handleEditTable(row) {
const tableId = row.tableId || this.ids[0];
this.$router.push({ path: "/gen/edit", query: { tableId: tableId } });
},
/** 删除按钮操作 */
handleDelete(row) {
const tableIds = row.tableId || this.ids;
this.$confirm('是否确认删除表编号为"' + tableIds + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(function() {
return delTable(tableIds);
}).then(() => {
this.getList();
this.msgSuccess("删除成功");
}).catch(function() {});
}
}
};
</script>

View File

@ -5,6 +5,7 @@
</template> </template>
<script> <script>
export default { export default {
name: "Swagger",
data() { data() {
return { return {
src: process.env.VUE_APP_BASE_API + "/swagger-ui.html", src: process.env.VUE_APP_BASE_API + "/swagger-ui.html",

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