mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2025-12-08 17:12:28 +08:00
Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b3d83ae0b | |||
| 081c2615be | |||
| f97c675771 | |||
| 1beddbf8e8 | |||
| 8921e84303 | |||
| 43329545d8 | |||
| 50333488a5 | |||
| 624444e3b9 | |||
| 1cd0f2627d | |||
| 18007b0524 | |||
| d92861ad77 | |||
| 8a6181b108 | |||
| 6840772959 | |||
| 1bc7ee3345 | |||
| 5f25f726c2 | |||
| 9b14d2d6a5 | |||
| 130f2bc4be | |||
| 832bc376be | |||
| 432385fc14 | |||
| 4d5ac2b518 | |||
| b83c26b8fd | |||
| b59fc67696 | |||
| af3afc7263 | |||
| 63c3dd26f5 | |||
| 892196fe9a | |||
| bbda918cde | |||
| 003ec82f48 | |||
| 4992faf66c | |||
| 34c612d9e4 | |||
| 844f1e228c | |||
| cf5fde80d4 | |||
| 49ea36c50f | |||
| f6e2b67c61 | |||
| 69a4a7df6d | |||
| 649f99664e | |||
| ef762ff21f | |||
| 02abd5c803 | |||
| 5e7342b27d | |||
| ca95d7090c | |||
| cdec71999a | |||
| 7990eff7a4 | |||
| 280f8c26ac | |||
| 4e05eaa4c5 | |||
| c6645ed800 | |||
| a674340c5e | |||
| cbd8890cb3 | |||
| b25fb55d10 | |||
| 88646bea1b | |||
| 9915b84808 | |||
| 35c1214de3 | |||
| 434b1a7e63 | |||
| 5c7d84117c | |||
| 4b9890205e | |||
| d5898139b5 | |||
| bf438069e2 | |||
| c5965b10d8 | |||
| da5ace3397 | |||
| 4674097078 | |||
| fea1607f1b | |||
| d2336bc5e1 | |||
| cf0d29557a | |||
| bb4c3c86b0 | |||
| 84a6e28677 | |||
| 5b70c1d8b8 | |||
| f942abe09b | |||
| ad4eb300f0 | |||
| 064a5c4a0e | |||
| 6d688a157b | |||
| d612af5e3b | |||
| e1c0b0fa38 | |||
| ac0979c824 | |||
| 78ba7ccba8 | |||
| b8ff5ebd43 | |||
| 5eb2541834 | |||
| 462b0d17b1 | |||
| 7cc54084dc | |||
| 32297110d9 | |||
| b7717d0461 | |||
| 97c078c46a | |||
| 17019e6261 | |||
| 4a49479985 | |||
| e49d76bc80 | |||
| d6cf2b502b | |||
| c741d779f2 | |||
| 7f847c9721 | |||
| fa2c5ecb73 | |||
| eb1578ada3 | |||
| 90758f3b2a | |||
| 766c48bdbf | |||
| d16520cc59 | |||
| 0252213b6e | |||
| ce44147e6e | |||
| 0ea4ac910a | |||
| 4f61f0ad48 | |||
| 4a5ff61ef7 | |||
| 88a0bb2d2d | |||
| b153669b69 | |||
| 449a7759be | |||
| 337920964d | |||
| 2a7946ae42 | |||
| c233f95f5f | |||
| f87cc2d97f | |||
| 02bb521b8f | |||
| 53e84ae34b | |||
| d6feeef7b5 | |||
| 18fc7b146a | |||
| 3792f46388 | |||
| f35236609c | |||
| e46b653bc4 | |||
| 4437c749ca | |||
| 74ebac4967 | |||
| a9f21795cb | |||
| a5ca8183cd | |||
| e7970e52bc | |||
| 74a9e10ce6 | |||
| df5c106d94 | |||
| ae0f9edb27 | |||
| 3d4bb704f1 | |||
| 85efec3730 | |||
| 8b0ee2d0a2 | |||
| 41c1572ad8 | |||
| 5d555158fe | |||
| 1fd0b5d4db | |||
| 693d86cf00 | |||
| 9a3f872d63 | |||
| 5b82a1aa06 | |||
| 3cb88452dc | |||
| 2fa1c7c17b | |||
| b6a3085083 | |||
| 8a7fc033cd | |||
| e0cf946d18 | |||
| c5b33b6bd1 | |||
| aec00d9ba2 | |||
| 341830c5a0 | |||
| ff45fe4858 | |||
| c13ed675a7 | |||
| 6917e91398 | |||
| 18a5c247d8 | |||
| 51bf9a7c14 | |||
| 8278041aeb | |||
| 39bb7a46fd | |||
| 1c234fbaff | |||
| ca1f5872be | |||
| 2ae3844d5e | |||
| 94c0610496 |
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -2,3 +2,4 @@
|
||||
*.css linguist-language=Java
|
||||
*.html linguist-language=Java
|
||||
*.vue linguist-language=Java
|
||||
*.sql linguist-language=Java
|
||||
|
||||
20
README.md
20
README.md
@ -7,12 +7,12 @@
|
||||
JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||
===============
|
||||
|
||||
当前最新版本: 2.4.0(发布日期:2020-12-01)
|
||||
当前最新版本: 2.4.5(发布日期:2021-06-07)
|
||||
|
||||
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||
[](http://www.jeecg.com)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
[](https://github.com/zhangdaiscott/jeecg-boot)
|
||||
|
||||
@ -23,7 +23,7 @@ JEECG BOOT 低代码开发平台(前后端分离版本)
|
||||
|
||||
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
|
||||
|
||||
JeecgBoot 是一款基于代码生成器的`低代码`开发平台!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
JeecgBoot 是一款基于代码生成器的`低代码平台`!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue,Mybatis-plus,Shiro,JWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
|
||||
|
||||
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`:Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力(可插拔)等等!
|
||||
|
||||
@ -61,7 +61,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
交流互动
|
||||
-----------------------------------
|
||||
|
||||
- QQ交流群 : ③816531124、②769925425(满)、①284271917(满)
|
||||
- QQ交流群 : ④774126647、③816531124(满)、②769925425(满)、①284271917(满)
|
||||
|
||||
- 反馈问题: [反馈问题,请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new)
|
||||
|
||||
@ -73,7 +73,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
为什么选择JEECG-BOOT?
|
||||
-----------------------------------
|
||||
* 1.采用最新主流前后分离框架(Springboot+Mybatis+antd),容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
|
||||
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywarking),提供切换机制支持单体和微服务自由切换
|
||||
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
|
||||
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
|
||||
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
|
||||
* 5.代码生成器非常智能,在线业务建模、在线配置、所见即所得支持23种类控件,一键生成前后端代码,大幅度提升开发效率,不再为重复工作发愁。
|
||||
@ -90,7 +90,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
|
||||
* 17.支持SAAS服务模式,提供SaaS多租户架构方案。
|
||||
* 18.分布式文件服务,集成minio、阿里OSS等优秀的第三方,提供便捷的文件上传与管理,同时也支持本地存储。
|
||||
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。
|
||||
* 19.主流数据库兼容,一套代码完全兼容Mysql、Postgresql、Oracle、Sqlserver、MariaDB、达梦等主流数据库。
|
||||
* 20.集成工作流activiti,并实现了只需在页面配置流程转向,可极大的简化bpm工作流的开发;用bpm的流程设计器画出了流程走向,一个工作流基本就完成了,只需写很少量的java代码;
|
||||
* 21.低代码能力:在线流程设计,采用开源Activiti流程引擎,实现在线画流程,自定义表单,表单挂靠,业务流转
|
||||
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
|
||||
@ -143,7 +143,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
- 安全框架:Apache Shiro 1.7.0,Jwt 3.11.0
|
||||
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywarking
|
||||
- 微服务技术栈:Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
|
||||
|
||||
- 数据库连接池:阿里巴巴Druid 1.1.22
|
||||
|
||||
@ -328,7 +328,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
8、服务监控 SpringBootAdmin√
|
||||
|
||||
9、链路跟踪 Skywarking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
|
||||
9、链路跟踪 Skywalking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
|
||||
|
||||
10、消息中间件 RabbitMQ √
|
||||
|
||||
@ -336,7 +336,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||
|
||||
12、分布式事务 Seata
|
||||
|
||||
13、分布式日志 elk + kafa
|
||||
13、分布式日志 elk + kafka
|
||||
|
||||
14、支持 docker-compose、k8s、jenkins
|
||||
|
||||
@ -349,7 +349,7 @@ Jeecg-Boot低代码开发平台,可以应用在任何J2EE项目的开发中,
|
||||

|
||||
|
||||
### Jeecg Boot 产品功能蓝图
|
||||

|
||||

|
||||
|
||||
|
||||
后台开发环境和依赖
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_PLATFORM_NAME=Jeecg-Boot 企业级快速开发平台
|
||||
VUE_APP_PLATFORM_NAME=JeecgBoot 企业级低代码平台
|
||||
VUE_APP_SSO=false
|
||||
@ -1,4 +1,4 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_API_BASE_URL=https://bootapi.jeecg.com
|
||||
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
|
||||
VUE_APP_CAS_BASE_URL=http://localhost:8888/cas
|
||||
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview
|
||||
@ -1,13 +1,13 @@
|
||||
Ant Design Jeecg Vue
|
||||
====
|
||||
|
||||
当前最新版本: 2.4.0(发布日期:20201201)
|
||||
当前最新版本: 2.4.5(发布日期:20210607)
|
||||
|
||||
Overview
|
||||
----
|
||||
|
||||
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版
|
||||
Jeecg-boot 的前段UI框架,采用前后端分离方案,提供强大代码生成器的快速开发平台。
|
||||
Jeecg-boot 的前端UI框架,采用前后端分离方案,提供强大代码生成器的低代码平台。
|
||||
前端页面代码和后端功能代码一键生成,不需要写任何代码,保持jeecg一贯的强大!!
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ Docker 镜像使用
|
||||
|
||||
```
|
||||
# 1.修改前端项目的后台域名
|
||||
public/index.html
|
||||
.env.development
|
||||
域名改成: http://jeecg-boot-system:8080/jeecg-boot
|
||||
|
||||
# 2.先进入打包前端项目
|
||||
|
||||
11002
ant-design-vue-jeecg/package-lock.json
generated
11002
ant-design-vue-jeecg/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-antd-jeecg",
|
||||
"version": "2.4.0",
|
||||
"version": "2.4.5",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
|
||||
@ -10,8 +10,8 @@
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jeecg/antd-online-mini": "2.4.0-beta4",
|
||||
"ant-design-vue": "^1.7.2",
|
||||
"@jeecg/antd-online-mini": "2.4.5-RC",
|
||||
"@antv/data-set": "^0.11.4",
|
||||
"viser-vue": "^2.4.8",
|
||||
"axios": "^0.18.0",
|
||||
@ -43,7 +43,8 @@
|
||||
"dom-align": "1.12.0",
|
||||
"xe-utils": "2.4.8",
|
||||
"vxe-table": "2.9.13",
|
||||
"vxe-table-plugin-antd": "1.8.10"
|
||||
"vxe-table-plugin-antd": "1.8.10",
|
||||
"cron-parser": "^2.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/polyfill": "^7.2.5",
|
||||
|
||||
File diff suppressed because one or more lines are too long
7
ant-design-vue-jeecg/public/color.less
vendored
7
ant-design-vue-jeecg/public/color.less
vendored
@ -2421,7 +2421,9 @@ a.listItemMetaTitle {
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
.main {
|
||||
background-color: #fff;
|
||||
//update-begin---author:liusq Date:20210108 for:[JT-409]编译主题色,然后退出登录后的首页是这样子------------
|
||||
//background-color: #fff;
|
||||
//update-end---author:liusq Date:20210108 for:[JT-409]编译主题色,然后退出登录后的首页是这样子------------
|
||||
}
|
||||
.main .leftmenu {
|
||||
border-right: 1px solid #e8e8e8;
|
||||
@ -7687,9 +7689,6 @@ font.weak {
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.ant-menu-submenu-selected {
|
||||
color: @primary-color;
|
||||
}
|
||||
|
||||
// begin -------- JAreaLinkage 三级联动样式 --------------
|
||||
.cascader-menu-list .cascader-menu-option.hover,
|
||||
|
||||
4
ant-design-vue-jeecg/public/index.html
vendored
4
ant-design-vue-jeecg/public/index.html
vendored
@ -5,7 +5,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Jeecg-Boot 企业级快速开发平台</title>
|
||||
<title>JeecgBoot 企业级低代码平台</title>
|
||||
<link rel="icon" href="<%= BASE_URL %>logo.png">
|
||||
<script src="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
|
||||
<style>
|
||||
@ -251,7 +251,7 @@
|
||||
<div id="loader"></div>
|
||||
<div class="loader-section section-left"></div>
|
||||
<div class="loader-section section-right"></div>
|
||||
<div class="load_title">正在加载 Jeecg-Boot 快速开发平台,请耐心等待
|
||||
<div class="load_title">正在加载 JeecgBoot 低代码平台,请耐心等待
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -18,6 +18,7 @@ const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
|
||||
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
|
||||
//改变密码
|
||||
const changePassword = (params)=>putAction("/sys/user/changePassword",params);
|
||||
|
||||
//权限管理
|
||||
const addPermission= (params)=>postAction("/sys/permission/add",params);
|
||||
const editPermission= (params)=>putAction("/sys/permission/edit",params);
|
||||
@ -25,7 +26,6 @@ const getPermissionList = (params)=>getAction("/sys/permission/list",params);
|
||||
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
|
||||
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
|
||||
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
|
||||
|
||||
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
|
||||
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
|
||||
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
|
||||
@ -38,6 +38,7 @@ const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermission
|
||||
|
||||
// 部门管理
|
||||
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params);
|
||||
const queryDepartTreeSync = (params)=>getAction("/sys/sysDepart/queryDepartTreeSync",params);
|
||||
const queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
|
||||
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
|
||||
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
|
||||
@ -68,7 +69,7 @@ export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItem
|
||||
function getDictItemsFromCache(dictCode) {
|
||||
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode]) {
|
||||
let dictItems = Vue.ls.get(UI_CACHE_DB_DICT_DATA)[dictCode];
|
||||
console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
|
||||
//console.log("-----------getDictItemsFromCache----------dictCode="+dictCode+"---- dictItems=",dictItems)
|
||||
return dictItems;
|
||||
}
|
||||
}
|
||||
@ -79,8 +80,10 @@ const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",param
|
||||
//获取系统访问量
|
||||
const getLoginfo = (params)=>getAction("/sys/loginfo",params);
|
||||
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
|
||||
|
||||
// 根据部门主键查询用户信息
|
||||
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
|
||||
|
||||
// 重复校验
|
||||
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
|
||||
// 加载分类字典
|
||||
@ -98,6 +101,8 @@ export const transitRESTful = {
|
||||
}
|
||||
|
||||
export {
|
||||
// imgView,
|
||||
// doMian,
|
||||
addRole,
|
||||
editRole,
|
||||
checkRoleCode,
|
||||
@ -121,6 +126,7 @@ export {
|
||||
getPermissionRuleList,
|
||||
queryPermissionRule,
|
||||
queryDepartTreeList,
|
||||
queryDepartTreeSync,
|
||||
queryIdTree,
|
||||
queryParentName,
|
||||
searchByKeywords,
|
||||
|
||||
@ -72,3 +72,16 @@ export function thirdLogin(token,thirdType) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 强退其他账号
|
||||
* @param token
|
||||
* @returns {*}
|
||||
*/
|
||||
export function forceLogout(parameter) {
|
||||
return axios({
|
||||
url: '/sys/online/forceLogout',
|
||||
method: 'post',
|
||||
data: parameter
|
||||
})
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import { axios } from '@/utils/request'
|
||||
import signMd5Utils from '@/utils/encryption/signMd5Utils'
|
||||
|
||||
const api = {
|
||||
user: '/mock/api/user',
|
||||
@ -13,19 +14,29 @@ export default api
|
||||
|
||||
//post
|
||||
export function postAction(url,parameter) {
|
||||
let sign = signMd5Utils.getSign(url, parameter);
|
||||
//将签名和时间戳,添加在请求接口 Header
|
||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method:'post' ,
|
||||
data: parameter
|
||||
data: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
//post method= {post | put}
|
||||
export function httpAction(url,parameter,method) {
|
||||
let sign = signMd5Utils.getSign(url, parameter);
|
||||
//将签名和时间戳,添加在请求接口 Header
|
||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method:method ,
|
||||
data: parameter
|
||||
data: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
@ -40,10 +51,15 @@ export function putAction(url,parameter) {
|
||||
|
||||
//get
|
||||
export function getAction(url,parameter) {
|
||||
let sign = signMd5Utils.getSign(url, parameter);
|
||||
//将签名和时间戳,添加在请求接口 Header
|
||||
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
|
||||
|
||||
return axios({
|
||||
url: url,
|
||||
method: 'get',
|
||||
params: parameter
|
||||
params: parameter,
|
||||
headers: signHeader
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JVxeCellMixins, { vModel, dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||
import JVxeCellMixins, { dispatchEvent, vModel } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||
|
||||
export default {
|
||||
name: 'JVxePopupCell',
|
||||
@ -22,6 +22,8 @@
|
||||
orgFields: col.orgFields,
|
||||
destFields: col.destFields,
|
||||
groupId: caseId,
|
||||
param: col.param,
|
||||
sorter: col.sorter,
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -48,7 +50,9 @@
|
||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||
enhanced: {
|
||||
aopEvents: {
|
||||
editActived: event => dispatchEvent(event, 'ant-input'),
|
||||
editActived(event) {
|
||||
dispatchEvent.call(this, event, 'ant-input')
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -254,7 +254,9 @@ export const DictSearchInputCell = {
|
||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||
enhanced: {
|
||||
aopEvents: {
|
||||
editActived: event => dispatchEvent(event, 'ant-select'),
|
||||
editActived(event) {
|
||||
dispatchEvent.call(this, event, 'ant-select')
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -39,5 +39,5 @@ UserMenu.vue:首页右上侧的内容
|
||||

|
||||
####16.trend包 趋势显示组件(如下图)
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
@ -12,13 +12,13 @@ export default class Area {
|
||||
let arr = []
|
||||
const province = pcaa['86']
|
||||
Object.keys(province).map(key=>{
|
||||
arr.push({id:key, text:province[key], pid:'86'});
|
||||
arr.push({id:key, text:province[key], pid:'86', index:1});
|
||||
const city = pcaa[key];
|
||||
Object.keys(city).map(key2=>{
|
||||
arr.push({id:key2, text:city[key2], pid:key});
|
||||
arr.push({id:key2, text:city[key2], pid:key, index:2});
|
||||
const qu = pcaa[key2];
|
||||
Object.keys(qu).map(key3=>{
|
||||
arr.push({id:key3, text:qu[key3], pid:key2});
|
||||
arr.push({id:key3, text:qu[key3], pid:key2, index:3});
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -45,33 +45,35 @@ export default class Area {
|
||||
return ''
|
||||
}
|
||||
let arr = []
|
||||
this.getAreaBycode(code,arr);
|
||||
this.getAreaBycode(code, arr, 3);
|
||||
return arr.join('/')
|
||||
}
|
||||
|
||||
getRealCode(code){
|
||||
let arr = []
|
||||
this.getPcode(code, arr)
|
||||
this.getPcode(code, arr, 3)
|
||||
return arr;
|
||||
}
|
||||
|
||||
getPcode(id, arr){
|
||||
getPcode(id, arr, index){
|
||||
for(let item of this.all){
|
||||
if(item.id === id){
|
||||
if(item.id === id && item.index == index){
|
||||
arr.unshift(id)
|
||||
if(item.pid != '86'){
|
||||
this.getPcode(item.pid,arr)
|
||||
this.getPcode(item.pid, arr, --index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getAreaBycode(code,arr){
|
||||
//console.log("this.all.length",this.all)
|
||||
getAreaBycode(code, arr, index){
|
||||
for(let item of this.all){
|
||||
if(item.id === code){
|
||||
if(item.id === code && item.index == index){
|
||||
arr.unshift(item.text);
|
||||
this.getAreaBycode(item.pid,arr)
|
||||
if(item.pid != '86'){
|
||||
this.getAreaBycode(item.pid, arr, --index)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
props: {
|
||||
dictCode: String,
|
||||
placeholder: String,
|
||||
triggerChange: Boolean,
|
||||
disabled: Boolean,
|
||||
value: [String, Number],
|
||||
type: String,
|
||||
@ -82,19 +81,15 @@
|
||||
}
|
||||
})
|
||||
},
|
||||
handleInput(e) {
|
||||
handleInput(e='') {
|
||||
let val;
|
||||
if(this.tagType=="radio"){
|
||||
if(Object.keys(e).includes('target')){
|
||||
val = e.target.value
|
||||
}else{
|
||||
val = e
|
||||
}
|
||||
console.log(val);
|
||||
if(this.triggerChange){
|
||||
this.$emit('change', val);
|
||||
}else{
|
||||
this.$emit('input', val);
|
||||
}
|
||||
this.$emit('change', val);
|
||||
},
|
||||
setCurrentDictOptions(dictOptions){
|
||||
this.dictOptions = dictOptions
|
||||
@ -102,6 +97,10 @@
|
||||
getCurrentDictOptions(){
|
||||
return this.dictOptions
|
||||
}
|
||||
},
|
||||
model:{
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
:disabled="disabled"
|
||||
mode="multiple"
|
||||
:placeholder="placeholder"
|
||||
:getPopupContainer="(node) => node.parentNode"
|
||||
:getPopupContainer="getParentContainer"
|
||||
optionFilterProp="children"
|
||||
:filterOption="filterOption"
|
||||
allowClear>
|
||||
@ -36,13 +36,23 @@
|
||||
disabled: Boolean,
|
||||
value: String,
|
||||
type: String,
|
||||
options:Array
|
||||
options:Array,
|
||||
spliter:{
|
||||
type: String,
|
||||
required: false,
|
||||
default: ','
|
||||
},
|
||||
popContainer:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dictOptions: [],
|
||||
tagType:"",
|
||||
arrayValue:!this.value?[]:this.value.split(",")
|
||||
arrayValue:!this.value?[]:this.value.split(this.spliter)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -68,7 +78,7 @@
|
||||
if(!val){
|
||||
this.arrayValue = []
|
||||
}else{
|
||||
this.arrayValue = this.value.split(",")
|
||||
this.arrayValue = this.value.split(this.spliter)
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -78,8 +88,9 @@
|
||||
this.dictOptions = [...this.options]
|
||||
}else{
|
||||
//优先从缓存中读取字典配置
|
||||
if(getDictItemsFromCache(this.dictCode)){
|
||||
this.dictOptions = getDictItemsFromCache(this.dictCode);
|
||||
let cacheOption = getDictItemsFromCache(this.dictCode)
|
||||
if(cacheOption && cacheOption.length>0){
|
||||
this.dictOptions = cacheOption
|
||||
return
|
||||
}
|
||||
//根据字典Code, 初始化字典数组
|
||||
@ -92,7 +103,7 @@
|
||||
|
||||
},
|
||||
onChange (selectedValue) {
|
||||
this.$emit('change', selectedValue.join(","));
|
||||
this.$emit('change', selectedValue.join(this.spliter));
|
||||
},
|
||||
setCurrentDictOptions(dictOptions){
|
||||
this.dictOptions = dictOptions
|
||||
@ -100,6 +111,13 @@
|
||||
getCurrentDictOptions(){
|
||||
return this.dictOptions
|
||||
},
|
||||
getParentContainer(node){
|
||||
if(!this.popContainer){
|
||||
return node.parentNode
|
||||
}else{
|
||||
return document.querySelector(this.popContainer)
|
||||
}
|
||||
},
|
||||
// update--begin--autor:lvdandan-----date:20201120------for:LOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
|
||||
filterOption(input, option) {
|
||||
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
showSearch
|
||||
labelInValue
|
||||
:disabled="disabled"
|
||||
:getPopupContainer="(node) => node.parentNode"
|
||||
:getPopupContainer="getParentContainer"
|
||||
@search="loadData"
|
||||
:placeholder="placeholder"
|
||||
v-model="selectedAsyncValue"
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
<a-select
|
||||
v-else
|
||||
:getPopupContainer="(node) => node.parentNode"
|
||||
:getPopupContainer="getParentContainer"
|
||||
showSearch
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
@ -55,7 +55,21 @@
|
||||
type:String,
|
||||
default:"请选择",
|
||||
required:false
|
||||
}
|
||||
},
|
||||
popContainer:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
pageSize:{
|
||||
type: Number,
|
||||
default: 10,
|
||||
required: false
|
||||
},
|
||||
getPopupContainer: {
|
||||
type:Function,
|
||||
default: null
|
||||
},
|
||||
},
|
||||
data(){
|
||||
this.loadData = debounce(this.loadData, 800);//消抖
|
||||
@ -126,7 +140,7 @@
|
||||
this.options = []
|
||||
this.loading=true
|
||||
// 字典code格式:table,text,code
|
||||
getAction(`/sys/dict/loadDict/${this.dict}`,{keyword:value}).then(res=>{
|
||||
getAction(`/sys/dict/loadDict/${this.dict}`,{keyword:value, pageSize: this.pageSize}).then(res=>{
|
||||
this.loading=false
|
||||
if(res.success){
|
||||
if(currentLoad!=this.lastLoad){
|
||||
@ -171,6 +185,17 @@
|
||||
})
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//异步一开始也加载一点数据
|
||||
this.loading=true
|
||||
getAction(`/sys/dict/loadDict/${this.dict}`,{pageSize: this.pageSize, keyword:''}).then(res=>{
|
||||
this.loading=false
|
||||
if(res.success){
|
||||
this.options = res.result
|
||||
}else{
|
||||
this.$message.warning(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
filterOption(input, option) {
|
||||
@ -182,9 +207,18 @@
|
||||
this.callback()
|
||||
},
|
||||
handleAsyncChange(selectedObj){
|
||||
this.selectedAsyncValue = selectedObj
|
||||
this.selectedValue = selectedObj.key
|
||||
//update-begin-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
|
||||
if(selectedObj){
|
||||
this.selectedAsyncValue = selectedObj
|
||||
this.selectedValue = selectedObj.key
|
||||
}else{
|
||||
this.selectedAsyncValue = null
|
||||
this.selectedValue = null
|
||||
this.options = null
|
||||
this.loadData("")
|
||||
}
|
||||
this.callback()
|
||||
//update-end-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
|
||||
},
|
||||
callback(){
|
||||
this.$emit('change', this.selectedValue);
|
||||
@ -194,7 +228,16 @@
|
||||
},
|
||||
getCurrentDictOptions(){
|
||||
return this.options
|
||||
}
|
||||
},
|
||||
getParentContainer(node){
|
||||
if(typeof this.getPopupContainer === 'function'){
|
||||
return this.getPopupContainer(node)
|
||||
} else if(!this.popContainer){
|
||||
return node.parentNode
|
||||
}else{
|
||||
return document.querySelector(this.popContainer)
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
model: {
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
import JDictSelectTag from './JDictSelectTag.vue'
|
||||
import JMultiSelectTag from './JMultiSelectTag.vue'
|
||||
import JSearchSelectTag from './JSearchSelectTag.vue'
|
||||
import { filterMultiDictText,filterDictText,initDictOptions,filterDictTextByCache } from './JDictSelectUtil'
|
||||
|
||||
export default {
|
||||
install: function (Vue) {
|
||||
Vue.component('JDictSelectTag',JDictSelectTag);
|
||||
Vue.component('JMultiSelectTag',JMultiSelectTag);
|
||||
Vue.component('JSearchSelectTag',JSearchSelectTag);
|
||||
Vue.prototype.$initDictOptions = (dictCode) => initDictOptions(dictCode)
|
||||
Vue.prototype.$filterMultiDictText = (dictOptions, text) => filterMultiDictText(dictOptions, text)
|
||||
Vue.prototype.$filterDictText = (dictOptions, text) => filterDictText(dictOptions, text)
|
||||
Vue.prototype.$filterDictTextByCache = (...param) => filterDictTextByCache(...param)
|
||||
}
|
||||
}
|
||||
@ -251,6 +251,9 @@
|
||||
},
|
||||
style: {}
|
||||
}
|
||||
if(isIE() || isIE11()){
|
||||
props.style['height'] = '240px'
|
||||
}
|
||||
if (this.fullCoder) {
|
||||
props.style['z-index'] = this.zIndex
|
||||
}
|
||||
|
||||
@ -1,282 +0,0 @@
|
||||
<template>
|
||||
<div v-bind="fullScreenParentProps">
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||
|
||||
<div class="code-editor-cust full-screen-child">
|
||||
<a-textarea auto-size v-model="textareaValue" :placeholder="placeholderShow" @change="handleChange" :style="{'max-height': maxHeight+'px','min-height': minHeight+'px'}"></a-textarea>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/ecmascript-6">
|
||||
export default {
|
||||
name: 'JCodeEditor',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
// 是否显示全屏按钮
|
||||
fullScreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 全屏以后的z-index
|
||||
zIndex: {
|
||||
type: [Number, String],
|
||||
default: 999
|
||||
},
|
||||
// 是否自适应高度,可以传String或Boolean
|
||||
// 传 String 类型只能写"!ie" ,
|
||||
// 填写这个字符串,代表其他浏览器自适应高度
|
||||
// 唯独IE下不自适应高度,因为IE下不支持min、max-height样式
|
||||
// 如果填写的不是"!ie"就视为true
|
||||
autoHeight: {
|
||||
type: [String, Boolean],
|
||||
default: true
|
||||
},
|
||||
// 不自适应高度的情况下生效的固定高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '240px'
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
minHeight:{
|
||||
type:Number,
|
||||
default: 100,
|
||||
required:false
|
||||
},
|
||||
maxHeight:{
|
||||
type:Number,
|
||||
default: 320,
|
||||
required:false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
textareaValue: '',
|
||||
// 内部真实的内容
|
||||
code: '',
|
||||
iconType: 'fullscreen',
|
||||
hasCode:false,
|
||||
// 默认的语法类型
|
||||
mode: 'javascript',
|
||||
// 编辑器实例
|
||||
coder: null,
|
||||
// 默认配置
|
||||
options: {
|
||||
// 缩进格式
|
||||
tabSize: 2,
|
||||
// 主题,对应主题库 JS 需要提前引入
|
||||
theme: 'panda-syntax',
|
||||
line: true,
|
||||
// extraKeys: {'Ctrl': 'autocomplete'},//自定义快捷键
|
||||
hintOptions: {
|
||||
tables: {
|
||||
users: ['name', 'score', 'birthDate'],
|
||||
countries: ['name', 'population', 'size']
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// code 编辑器 是否全屏
|
||||
fullCoder: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fullCoder:{
|
||||
handler(value) {
|
||||
if(value){
|
||||
this.iconType="fullscreen-exit"
|
||||
}else{
|
||||
this.iconType="fullscreen"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
placeholderShow() {
|
||||
if (this.placeholder == null) {
|
||||
return `请在此输入代码`
|
||||
} else {
|
||||
return this.placeholder
|
||||
}
|
||||
},
|
||||
isAutoHeight() {
|
||||
let {autoHeight} = this
|
||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||
autoHeight = !(isIE() || isIE11())
|
||||
} else {
|
||||
autoHeight = true
|
||||
}
|
||||
return autoHeight
|
||||
},
|
||||
fullScreenParentProps() {
|
||||
let props = {
|
||||
class: {
|
||||
'full-screen-parent': true,
|
||||
'full-screen': this.fullCoder,
|
||||
'auto-height': this.isAutoHeight
|
||||
},
|
||||
style: {}
|
||||
}
|
||||
if (this.fullCoder) {
|
||||
props.style['z-index'] = this.zIndex
|
||||
}
|
||||
if (!this.isAutoHeight) {
|
||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||
}
|
||||
return props
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
// 初始化
|
||||
this._initialize()
|
||||
},
|
||||
methods: {
|
||||
// 初始化
|
||||
_initialize () {
|
||||
this.setCodeContent(this.value)
|
||||
},
|
||||
handleChange(e){
|
||||
this.$emit('input', e.target.value)
|
||||
},
|
||||
getCodeContent(){
|
||||
return this.value
|
||||
},
|
||||
setCodeContent(val){
|
||||
setTimeout(()=>{
|
||||
if(!val){
|
||||
this.textareaValue = ''
|
||||
}else{
|
||||
this.textareaValue = val
|
||||
}
|
||||
},300)
|
||||
},
|
||||
nullTipClick(){
|
||||
this.coder.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.code-editor-cust{
|
||||
flex-grow:1;
|
||||
display:flex;
|
||||
position:relative;
|
||||
height:100%;
|
||||
.CodeMirror{
|
||||
flex-grow:1;
|
||||
z-index:1;
|
||||
.CodeMirror-code{
|
||||
line-height:19px;
|
||||
}
|
||||
|
||||
}
|
||||
.code-mode-select{
|
||||
position:absolute;
|
||||
z-index:2;
|
||||
right:10px;
|
||||
top:10px;
|
||||
max-width:130px;
|
||||
}
|
||||
.CodeMirror{
|
||||
height: auto;
|
||||
min-height:100%;
|
||||
}
|
||||
.null-tip{
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 36px;
|
||||
z-index: 10;
|
||||
color: #ffffffc9;
|
||||
line-height: initial;
|
||||
}
|
||||
.null-tip-hidden{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* 全屏样式 */
|
||||
.full-screen-parent {
|
||||
position: relative;
|
||||
|
||||
.full-screen-icon {
|
||||
opacity: 0;
|
||||
color: black;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 2px;
|
||||
z-index: 9;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.full-screen-icon {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.full-screen {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
width: calc(100% - 20px);
|
||||
height: calc(100% - 20px);
|
||||
padding: 10px;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.full-screen-icon {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.full-screen-child {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.full-screen-child {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&.auto-height {
|
||||
.full-screen-child {
|
||||
min-height: 120px;
|
||||
max-height: 320px;
|
||||
height: unset;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&.full-screen .full-screen-child {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.CodeMirror-cursor{
|
||||
height:18.4px !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="components-input-demo-presuffix">
|
||||
<a-input @click="openModal" placeholder="corn表达式" v-model="cron" @change="handleOK">
|
||||
<a-icon slot="prefix" type="schedule" title="corn控件"/>
|
||||
<a-input @click="openModal" placeholder="cron表达式" v-model="cron" @change="(e)=>handleOK(e.target.value)">
|
||||
<a-icon slot="prefix" type="schedule" title="cron控件"/>
|
||||
<a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||
</a-input>
|
||||
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>
|
||||
|
||||
246
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
246
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/EasyCron.vue
Normal file
@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<div class="j-easy-cron">
|
||||
<div class="content">
|
||||
<div>
|
||||
<a-tabs size="small" v-model="curtab">
|
||||
<a-tab-pane tab="秒" key="second" v-if="!hideSecond">
|
||||
<second-ui v-model="second" :disabled="disabled"></second-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="分" key="minute">
|
||||
<minute-ui v-model="minute" :disabled="disabled"></minute-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="时" key="hour">
|
||||
<hour-ui v-model="hour" :disabled="disabled"></hour-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="日" key="day">
|
||||
<day-ui v-model="day" :week="week" :disabled="disabled"></day-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="月" key="month">
|
||||
<month-ui v-model="month" :disabled="disabled"></month-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="周" key="week">
|
||||
<week-ui v-model="week" :day="day" :disabled="disabled"></week-ui>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="年" key="year" v-if="!hideYear && !hideSecond">
|
||||
<year-ui v-model="year" :disabled="disabled"></year-ui>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
<a-divider/>
|
||||
<!-- 执行时间预览 -->
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="18" style="margin-top: 22px;">
|
||||
<a-row :gutter="8">
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="秒" v-model="inputValues.second" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="分" v-model="inputValues.minute" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="时" v-model="inputValues.hour" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="日" v-model="inputValues.day" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="月" v-model="inputValues.month" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="周" v-model="inputValues.week" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="8" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="年" v-model="inputValues.year" @blur="onInputBlur"/>
|
||||
</a-col>
|
||||
<a-col :span="16" style="margin-bottom: 8px;">
|
||||
<a-input addon-before="Cron" v-model="inputValues.cron" @blur="onInputCronBlur"/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
<a-col :span="6">
|
||||
|
||||
<div>近十次执行时间(不含年)</div>
|
||||
<a-textarea type="textarea" :value="preTimeList" :rows="5"/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SecondUi from './tabs/second'
|
||||
import MinuteUi from './tabs/minute'
|
||||
import HourUi from './tabs/hour'
|
||||
import DayUi from './tabs/day'
|
||||
import WeekUi from './tabs/week'
|
||||
import MonthUi from './tabs/month'
|
||||
import YearUi from './tabs/year'
|
||||
import CronParser from 'cron-parser'
|
||||
import dateFormat from './format-date'
|
||||
import { simpleDebounce } from '@/utils/util'
|
||||
import ACol from 'ant-design-vue/es/grid/Col'
|
||||
|
||||
export default {
|
||||
name: 'easy-cron',
|
||||
components: {
|
||||
ACol,
|
||||
SecondUi,
|
||||
MinuteUi,
|
||||
HourUi,
|
||||
DayUi,
|
||||
WeekUi,
|
||||
MonthUi,
|
||||
YearUi
|
||||
},
|
||||
props: {
|
||||
cronValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hideSecond: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hideYear: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
remote: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
curtab: this.hideSecond ? 'minute' : 'second',
|
||||
second: '*',
|
||||
minute: '*',
|
||||
hour: '*',
|
||||
day: '*',
|
||||
month: '*',
|
||||
week: '?',
|
||||
year: '*',
|
||||
inputValues: {second: '', minute: '', hour: '', day: '', month: '', week: '', year: '', cron: ''},
|
||||
preTimeList: '执行预览,会忽略年份参数',
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
cronValue_c() {
|
||||
let result = []
|
||||
if (!this.hideSecond) result.push(this.second ? this.second : '*')
|
||||
result.push(this.minute ? this.minute : '*')
|
||||
result.push(this.hour ? this.hour : '*')
|
||||
result.push(this.day ? this.day : '*')
|
||||
result.push(this.month ? this.month : '*')
|
||||
result.push(this.week ? this.week : '?')
|
||||
if (!this.hideYear && !this.hideSecond) result.push(this.year ? this.year : '*')
|
||||
return result.join(' ')
|
||||
},
|
||||
cronValue_c2() {
|
||||
const v = this.cronValue_c
|
||||
if (this.hideYear || this.hideSecond) return v
|
||||
const vs = v.split(' ')
|
||||
return vs.slice(0, vs.length - 1).join(' ')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cronValue(newVal, oldVal) {
|
||||
if (newVal === this.cronValue_c) {
|
||||
// console.info('same cron value: ' + newVal)
|
||||
return
|
||||
}
|
||||
this.formatValue()
|
||||
},
|
||||
cronValue_c(newVal, oldVal) {
|
||||
this.calTriggerList()
|
||||
this.$emit('change', newVal)
|
||||
|
||||
Object.assign(this.inputValues, {
|
||||
second: this.second,
|
||||
minute: this.minute,
|
||||
hour: this.hour,
|
||||
day: this.day,
|
||||
month: this.month,
|
||||
week: this.week,
|
||||
year: this.year,
|
||||
cron: this.cronValue_c,
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.formatValue()
|
||||
this.$nextTick(() => {
|
||||
this.calTriggerListInner()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
formatValue() {
|
||||
if (!this.cronValue) return
|
||||
const values = this.cronValue.split(' ').filter(item => !!item)
|
||||
if (!values || values.length <= 0) return
|
||||
let i = 0
|
||||
if (!this.hideSecond) this.second = values[i++]
|
||||
if (values.length > i) this.minute = values[i++]
|
||||
if (values.length > i) this.hour = values[i++]
|
||||
if (values.length > i) this.day = values[i++]
|
||||
if (values.length > i) this.month = values[i++]
|
||||
if (values.length > i) this.week = values[i++]
|
||||
if (values.length > i) this.year = values[i]
|
||||
},
|
||||
calTriggerList: simpleDebounce(function () {
|
||||
this.calTriggerListInner()
|
||||
}, 500),
|
||||
calTriggerListInner() {
|
||||
// 设置了回调函数
|
||||
if (this.remote) {
|
||||
this.remote(this.cronValue_c, +new Date(), v => {
|
||||
this.preTimeList = v
|
||||
})
|
||||
return
|
||||
}
|
||||
const format = 'yyyy-MM-dd hh:mm:ss'
|
||||
const options = {
|
||||
currentDate: dateFormat(new Date(), format)
|
||||
}
|
||||
const iter = CronParser.parseExpression(this.cronValue_c2, options)
|
||||
const result = []
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
result.push(dateFormat(new Date(iter.next()), format))
|
||||
}
|
||||
this.preTimeList = result.length > 0 ? result.join('\n') : '无执行时间'
|
||||
},
|
||||
onInputBlur(){
|
||||
this.second = this.inputValues.second
|
||||
this.minute = this.inputValues.minute
|
||||
this.hour = this.inputValues.hour
|
||||
this.day = this.inputValues.day
|
||||
this.month = this.inputValues.month
|
||||
this.week = this.inputValues.week
|
||||
this.year = this.inputValues.year
|
||||
},
|
||||
onInputCronBlur(event){
|
||||
this.$emit('change', event.target.value)
|
||||
},
|
||||
},
|
||||
model: {
|
||||
prop: 'cronValue',
|
||||
event: 'change'
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.j-easy-cron {
|
||||
|
||||
/deep/ .content {
|
||||
.ant-checkbox-wrapper + .ant-checkbox-wrapper {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,99 @@
|
||||
<template>
|
||||
<div class="input-cron">
|
||||
<a-input :placeholder="placeholder" v-model="editCronValue" :disabled="disabled">
|
||||
<a slot="addonAfter" @click="showConfigDlg" class="config-btn" :disabled="disabled">
|
||||
<a-icon type="setting"></a-icon>
|
||||
选择
|
||||
</a>
|
||||
</a-input>
|
||||
<j-modal :visible.sync="show" title="Cron表达式" width="800px">
|
||||
<easy-cron
|
||||
v-model="editCronValue"
|
||||
:exeStartTime="exeStartTime"
|
||||
:hideYear="hideYear"
|
||||
:remote="remote"
|
||||
:hideSecond="hideSecond"
|
||||
style="width: 100%"
|
||||
></easy-cron>
|
||||
</j-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EasyCron from './EasyCron.vue'
|
||||
|
||||
export default {
|
||||
name: 'input-cron',
|
||||
components: {EasyCron},
|
||||
model: {
|
||||
prop: 'cronValue',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
cronValue: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '800px'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入cron表达式'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
exeStartTime: {
|
||||
type: [Number, String, Object],
|
||||
default: 0
|
||||
},
|
||||
hideSecond: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
hideYear: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
remote: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editCronValue: this.cronValue,
|
||||
show: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
cronValue(newVal, oldVal) {
|
||||
if (newVal === this.editCronValue) {
|
||||
return
|
||||
}
|
||||
this.editCronValue = newVal
|
||||
},
|
||||
editCronValue(newVal, oldVal) {
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showConfigDlg() {
|
||||
if (!this.disabled) {
|
||||
this.show = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.config-btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,37 @@
|
||||
const dateFormat = (date, block) => {
|
||||
if (!date) {
|
||||
return ''
|
||||
}
|
||||
|
||||
let format = block || 'yyyy-MM-dd'
|
||||
|
||||
date = new Date(date)
|
||||
|
||||
const map = {
|
||||
M: date.getMonth() + 1, // 月份
|
||||
d: date.getDate(), // 日
|
||||
h: date.getHours(), // 小时
|
||||
m: date.getMinutes(), // 分
|
||||
s: date.getSeconds(), // 秒
|
||||
q: Math.floor((date.getMonth() + 3) / 3), // 季度
|
||||
S: date.getMilliseconds() // 毫秒
|
||||
}
|
||||
|
||||
format = format.replace(/([yMdhmsqS])+/g, (all, t) => {
|
||||
let v = map[t]
|
||||
if (v !== undefined) {
|
||||
if (all.length > 1) {
|
||||
v = `0${v}`
|
||||
v = v.substr(v.length - 2)
|
||||
}
|
||||
return v
|
||||
} else if (t === 'y') {
|
||||
return (date.getFullYear().toString()).substr(4 - all.length)
|
||||
}
|
||||
return all
|
||||
})
|
||||
|
||||
return format
|
||||
}
|
||||
|
||||
export default dateFormat
|
||||
@ -0,0 +1,6 @@
|
||||
// 原开源项目地址:https://gitee.com/toktok/easy-cron
|
||||
|
||||
import InputCron from './InputCron.vue'
|
||||
|
||||
InputCron.name = 'JEasyCron'
|
||||
export default InputCron
|
||||
@ -0,0 +1,21 @@
|
||||
export const WEEK_MAP_EN = {
|
||||
'SUN': '0',
|
||||
'MON': '1',
|
||||
'TUE': '2',
|
||||
'WED': '3',
|
||||
'THU': '4',
|
||||
'FRI': '5',
|
||||
'SAT': '6'
|
||||
}
|
||||
|
||||
export const replaceWeekName = (c) => {
|
||||
// console.info('after: ' + c)
|
||||
if (c) {
|
||||
Object.keys(WEEK_MAP_EN).forEach(k => {
|
||||
c = c.replace(new RegExp(k, 'g'), WEEK_MAP_EN[k])
|
||||
})
|
||||
c = c.replace(new RegExp('7', 'g'), '0')
|
||||
}
|
||||
// console.info('after: ' + c)
|
||||
return c
|
||||
}
|
||||
101
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue
Normal file
101
ant-design-vue-jeecg/src/components/jeecg/JEasyCron/tabs/day.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_NOT_SET" class="choice" :disabled="disableChoice">不设置</a-radio>
|
||||
<span class="tip-info">日和周只能设置其中之一</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disableChoice">每日</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disableChoice">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
日
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
日
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disableChoice">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
日开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
日
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_WORK" class="choice" :disabled="disableChoice">工作日</a-radio>
|
||||
本月
|
||||
<a-input-number :disabled="type!==TYPE_WORK || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueWork"/>
|
||||
日,最近的工作日
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LAST" class="choice" :disabled="disableChoice">最后一日</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'day',
|
||||
mixins: [mixin],
|
||||
props: {
|
||||
week: {
|
||||
type: String,
|
||||
default: '?'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
disableChoice() {
|
||||
return (this.week && this.week !== '?') || this.disabled
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
// 数值变化
|
||||
this.updateValue()
|
||||
},
|
||||
week(newVal, oldVal) {
|
||||
// console.info('new week: ' + newVal)
|
||||
this.updateValue()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateValue() {
|
||||
this.$emit('change', this.disableChoice ? '?' : this.value_c)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 1
|
||||
this.maxValue = 31
|
||||
this.valueRange.start = 1
|
||||
this.valueRange.end = 31
|
||||
this.valueLoop.start = 1
|
||||
this.valueLoop.interval = 1
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每时</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
时
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
时
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
时开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
时
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'minute',
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 0
|
||||
this.maxValue = 23
|
||||
this.valueRange.start = 0
|
||||
this.valueRange.end = 23
|
||||
this.valueLoop.start = 0
|
||||
this.valueLoop.interval = 1
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每分</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
分
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
分
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
分开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
分
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'minute',
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 0
|
||||
this.maxValue = 59
|
||||
this.valueRange.start = 0
|
||||
this.valueRange.end = 59
|
||||
this.valueLoop.start = 0
|
||||
this.valueLoop.interval = 1
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,151 @@
|
||||
// 主要用于日和星期的互斥使用
|
||||
const TYPE_NOT_SET = 'TYPE_NOT_SET'
|
||||
const TYPE_EVERY = 'TYPE_EVERY'
|
||||
const TYPE_RANGE = 'TYPE_RANGE'
|
||||
const TYPE_LOOP = 'TYPE_LOOP'
|
||||
const TYPE_WORK = 'TYPE_WORK'
|
||||
const TYPE_LAST = 'TYPE_LAST'
|
||||
const TYPE_SPECIFY = 'TYPE_SPECIFY'
|
||||
|
||||
const DEFAULT_VALUE = '?'
|
||||
|
||||
export default {
|
||||
model: {
|
||||
prop: 'prop',
|
||||
event: 'change'
|
||||
},
|
||||
props: {
|
||||
prop: {
|
||||
type: String,
|
||||
default: DEFAULT_VALUE
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
const type = TYPE_EVERY
|
||||
return {
|
||||
DEFAULT_VALUE,
|
||||
// 类型
|
||||
type,
|
||||
// 启用日或者星期互斥用
|
||||
TYPE_NOT_SET,
|
||||
TYPE_EVERY,
|
||||
TYPE_RANGE,
|
||||
TYPE_LOOP,
|
||||
TYPE_WORK,
|
||||
TYPE_LAST,
|
||||
TYPE_SPECIFY,
|
||||
// 对于不同的类型,所定义的值也有所不同
|
||||
valueRange: {
|
||||
start: 0,
|
||||
end: 0
|
||||
},
|
||||
valueLoop: {
|
||||
start: 0,
|
||||
interval: 1
|
||||
},
|
||||
valueWeek: {
|
||||
start: 0,
|
||||
end: 0
|
||||
},
|
||||
valueList: [],
|
||||
valueWork: 1,
|
||||
maxValue: 0,
|
||||
minValue: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
prop (newVal, oldVal) {
|
||||
if (newVal === this.value_c) {
|
||||
// console.info('skip ' + newVal)
|
||||
return
|
||||
}
|
||||
this.parseProp(newVal)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
value_c () {
|
||||
let result = []
|
||||
switch (this.type) {
|
||||
case TYPE_NOT_SET:
|
||||
result.push('?')
|
||||
break
|
||||
case TYPE_EVERY:
|
||||
result.push('*')
|
||||
break
|
||||
case TYPE_RANGE:
|
||||
result.push(`${this.valueRange.start}-${this.valueRange.end}`)
|
||||
break
|
||||
case TYPE_LOOP:
|
||||
result.push(`${this.valueLoop.start}/${this.valueLoop.interval}`)
|
||||
break
|
||||
case TYPE_WORK:
|
||||
result.push(`${this.valueWork}W`)
|
||||
break
|
||||
case TYPE_LAST:
|
||||
result.push('L')
|
||||
break
|
||||
case TYPE_SPECIFY:
|
||||
result.push(this.valueList.join(','))
|
||||
break
|
||||
default:
|
||||
result.push(this.DEFAULT_VALUE)
|
||||
break
|
||||
}
|
||||
return result.length > 0 ? result.join('') : this.DEFAULT_VALUE
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
parseProp (value) {
|
||||
if (value === this.value_c) {
|
||||
// console.info('same ' + value)
|
||||
return
|
||||
}
|
||||
if (typeof (this.preProcessProp) === 'function') {
|
||||
value = this.preProcessProp(value)
|
||||
}
|
||||
try {
|
||||
if (!value || value === this.DEFAULT_VALUE) {
|
||||
this.type = TYPE_EVERY
|
||||
} else if (value.indexOf('?') >= 0) {
|
||||
this.type = TYPE_NOT_SET
|
||||
} else if (value.indexOf('-') >= 0) {
|
||||
this.type = TYPE_RANGE
|
||||
const values = value.split('-')
|
||||
if (values.length >= 2) {
|
||||
this.valueRange.start = parseInt(values[0])
|
||||
this.valueRange.end = parseInt(values[1])
|
||||
}
|
||||
} else if (value.indexOf('/') >= 0) {
|
||||
this.type = TYPE_LOOP
|
||||
const values = value.split('/')
|
||||
if (values.length >= 2) {
|
||||
this.valueLoop.start = value[0] === '*' ? 0 : parseInt(values[0])
|
||||
this.valueLoop.interval = parseInt(values[1])
|
||||
}
|
||||
} else if (value.indexOf('W') >= 0) {
|
||||
this.type = TYPE_WORK
|
||||
const values = value.split('W')
|
||||
if (!values[0] && !isNaN(values[0])) {
|
||||
this.valueWork = parseInt(values[0])
|
||||
}
|
||||
} else if (value.indexOf('L') >= 0) {
|
||||
this.type = TYPE_LAST
|
||||
const values = value.split('L')
|
||||
this.valueLast = parseInt(values[0])
|
||||
} else if (value.indexOf(',') >= 0 || !isNaN(value)) {
|
||||
this.type = TYPE_SPECIFY
|
||||
this.valueList = value.split(',').map(item => parseInt(item))
|
||||
} else {
|
||||
this.type = TYPE_EVERY
|
||||
}
|
||||
} catch (e) {
|
||||
// console.info(e)
|
||||
this.type = TYPE_EVERY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
|
||||
.config-list {
|
||||
text-align: left;
|
||||
margin: 0 10px 10px 10px;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.choice {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
|
||||
.w60 {
|
||||
width: 60px;
|
||||
}
|
||||
.w80 {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.list-check-item {
|
||||
padding: 1px 3px;
|
||||
width: 4em;
|
||||
}
|
||||
|
||||
.tip-info {
|
||||
color: #999
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每月</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
月
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
月
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
月开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
月
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'month',
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 1
|
||||
this.maxValue = 12
|
||||
this.valueRange.start = 1
|
||||
this.valueRange.end = 12
|
||||
this.valueLoop.start = 1
|
||||
this.valueLoop.interval = 1
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每秒</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
秒
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
秒
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
秒开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
秒
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disabled">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'second',
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 0
|
||||
this.maxValue = 59
|
||||
this.valueRange.start = 0
|
||||
this.valueRange.end = 59
|
||||
this.valueLoop.start = 0
|
||||
this.valueLoop.interval = 1
|
||||
// console.info('created')
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_NOT_SET" class="choice" :disabled="disableChoice">不设置</a-radio>
|
||||
<span class="tip-info">日和周只能设置其中之一</span>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disableChoice">区间</a-radio>
|
||||
从
|
||||
<a-select v-model="valueRange.start" class="w80" :disabled="type!==TYPE_RANGE || disableChoice">
|
||||
<template v-for="(v, k) of WEEK_MAP">
|
||||
<a-select-option :value="v">{{k}}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
至
|
||||
<a-select v-model="valueRange.end" class="w80" :disabled="type!==TYPE_RANGE || disableChoice">
|
||||
<template v-for="(v, k) of WEEK_MAP">
|
||||
<a-select-option :value="v">{{k}}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disableChoice">循环</a-radio>
|
||||
从
|
||||
<a-select v-model="valueLoop.start" class="w80" :disabled="type!==TYPE_LOOP || disableChoice">
|
||||
<template v-for="(v, k) of WEEK_MAP">
|
||||
<a-select-option :value="v">{{k}}</a-select-option>
|
||||
</template>
|
||||
</a-select>
|
||||
开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disableChoice" :max="maxValue" :min="minValue" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
天
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_SPECIFY" class="choice" :disabled="disableChoice">指定</a-radio>
|
||||
<div class="list">
|
||||
<a-checkbox-group v-model="valueList">
|
||||
<template v-for="i in maxValue+1">
|
||||
<a-checkbox class="list-check-item" :key="`key-${i-1}`" :value="i-1" :disabled="type!==TYPE_SPECIFY || disabled">{{i-1}}</a-checkbox>
|
||||
</template>
|
||||
</a-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
import { replaceWeekName, WEEK_MAP_EN } from './const.js'
|
||||
|
||||
const WEEK_MAP = {
|
||||
'周日': 0,
|
||||
'周一': 1,
|
||||
'周二': 2,
|
||||
'周三': 3,
|
||||
'周四': 4,
|
||||
'周五': 5,
|
||||
'周六': 6
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'week',
|
||||
mixins: [mixin],
|
||||
props: {
|
||||
day: {
|
||||
type: String,
|
||||
default: '*'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
WEEK_MAP,
|
||||
WEEK_MAP_EN
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
disableChoice() {
|
||||
return (this.day && this.day !== '?') || this.disabled
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
// 如果设置日,那么星期就直接不设置
|
||||
this.updateValue()
|
||||
},
|
||||
day(newVal) {
|
||||
// console.info('new day: ' + newVal)
|
||||
this.updateValue()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateValue() {
|
||||
this.$emit('change', this.disableChoice ? '?' : this.value_c)
|
||||
},
|
||||
preProcessProp(c) {
|
||||
return replaceWeekName(c)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.DEFAULT_VALUE = '*'
|
||||
// 0,7表示周日 1表示周一
|
||||
this.minValue = 0
|
||||
this.maxValue = 6
|
||||
this.valueRange.start = 0
|
||||
this.valueRange.end = 6
|
||||
this.valueLoop.start = 2
|
||||
this.valueLoop.interval = 1
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="config-list">
|
||||
<a-radio-group v-model="type">
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_EVERY" class="choice" :disabled="disabled">每年</a-radio>
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_RANGE" class="choice" :disabled="disabled">区间</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :min="0" :precision="0" class="w60" v-model="valueRange.start"/>
|
||||
年
|
||||
至
|
||||
<a-input-number :disabled="type!==TYPE_RANGE || disabled" :min="1" :precision="0" class="w60" v-model="valueRange.end"/>
|
||||
年
|
||||
</div>
|
||||
<div class="item">
|
||||
<a-radio value="TYPE_LOOP" class="choice" :disabled="disabled">循环</a-radio>
|
||||
从
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :min="0" :precision="0" class="w60" v-model="valueLoop.start"/>
|
||||
年开始,间隔
|
||||
<a-input-number :disabled="type!==TYPE_LOOP || disabled" :min="1" :precision="0" class="w60" v-model="valueLoop.interval"/>
|
||||
年
|
||||
</div>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixin from './mixin'
|
||||
|
||||
export default {
|
||||
name: 'year',
|
||||
mixins: [mixin],
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
value_c(newVal, oldVal) {
|
||||
// console.info('change:' + newVal)
|
||||
this.$emit('change', newVal)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const nowYear = (new Date()).getFullYear()
|
||||
this.DEFAULT_VALUE = '*'
|
||||
this.minValue = 0
|
||||
this.maxValue = 0
|
||||
this.valueRange.start = nowYear
|
||||
this.valueRange.end = nowYear + 100
|
||||
this.valueLoop.start = nowYear
|
||||
this.valueLoop.interval = 1
|
||||
// console.info('created')
|
||||
this.parseProp(this.prop)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import "mixin.less";
|
||||
</style>
|
||||
@ -0,0 +1,51 @@
|
||||
import CronParser from 'cron-parser'
|
||||
import { replaceWeekName } from './tabs/const'
|
||||
|
||||
export default (rule, value, callback) => {
|
||||
// 没填写就不校验
|
||||
if (!value) {
|
||||
callback()
|
||||
return true
|
||||
}
|
||||
const values = value.split(' ').filter(item => !!item)
|
||||
if (values.length > 7) {
|
||||
callback(new Error('Cron表达式最多7项!'))
|
||||
return false
|
||||
}
|
||||
// 检查第7项
|
||||
let e = value
|
||||
if (values.length === 7) {
|
||||
const year = replaceWeekName(values[6])
|
||||
if (year !== '*' && year !== '?') {
|
||||
let yearValues = []
|
||||
if (year.indexOf('-') >= 0) {
|
||||
yearValues = year.split('-')
|
||||
} else if (year.indexOf('/')) {
|
||||
yearValues = year.split('/')
|
||||
} else {
|
||||
yearValues = [year]
|
||||
}
|
||||
// console.info(yearValues)
|
||||
// 判断是否都是数字
|
||||
const checkYear = yearValues.some(item => isNaN(item))
|
||||
if (checkYear) {
|
||||
callback(new Error('Cron表达式参数[年]错误:' + year))
|
||||
return false
|
||||
}
|
||||
}
|
||||
// 取其中的前六项
|
||||
e = values.slice(0, 6).join(' ')
|
||||
}
|
||||
// 6位 没有年
|
||||
// 5位没有秒、年
|
||||
let result = true
|
||||
try {
|
||||
const iter = CronParser.parseExpression(e)
|
||||
iter.next()
|
||||
callback()
|
||||
} catch (e) {
|
||||
callback(new Error('Cron表达式错误:' + e))
|
||||
result = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -11,13 +11,13 @@
|
||||
<a-col>
|
||||
<!-- 操作按钮 -->
|
||||
<div v-if="actionButton" class="action-button">
|
||||
<a-button type="primary" icon="plus" @click="handleClickAdd" :disabled="disabled">新增</a-button>
|
||||
<a-button v-if="buttonPermission('add')" type="primary" icon="plus" @click="handleClickAdd" :disabled="disabled">新增</a-button>
|
||||
<span class="gap"></span>
|
||||
<template v-if="selectedRowIds.length>0">
|
||||
<a-popconfirm
|
||||
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
|
||||
@confirm="handleConfirmDelete">
|
||||
<a-button type="primary" icon="minus" :disabled="disabled">删除</a-button>
|
||||
<a-button v-if="buttonPermission('batch_delete')" type="primary" icon="minus" :disabled="disabled">删除</a-button>
|
||||
<span class="gap"></span>
|
||||
</a-popconfirm>
|
||||
<template v-if="showClearSelectButton">
|
||||
@ -59,7 +59,7 @@
|
||||
v-show="col.type !== formTypes.hidden"
|
||||
class="td"
|
||||
:key="col.key"
|
||||
:style="buildTdStyle(col,true)">
|
||||
:style="buildTdStyle(col)">
|
||||
|
||||
<span>{{ col.title }}</span>
|
||||
</div>
|
||||
@ -188,6 +188,7 @@
|
||||
:getPopupContainer="getParentContainer"
|
||||
:placeholder="replaceProps(col, col.placeholder)"
|
||||
:filterOption="(i,o)=>handleSelectFilterOption(i,o,col)"
|
||||
:maxTagCount="1"
|
||||
@change="(v)=>handleChangeSelectCommon(v,id,row,col)"
|
||||
@search="(v)=>handleSearchSelect(v,id,row,col)"
|
||||
@blur="(v)=>handleBlurSearch(v,id,row,col)"
|
||||
@ -201,6 +202,55 @@
|
||||
>{{ getSelectTranslateText(selectValues[id], row, col) }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 部门选择 -->
|
||||
<template v-else-if="col.type === formTypes.sel_depart">
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
<j-select-depart
|
||||
v-if="isEditRow(row, col)"
|
||||
:id="id"
|
||||
:key="i"
|
||||
v-bind="buildProps(row,col)"
|
||||
style="width: 100%;"
|
||||
:value="departCompValues[id]"
|
||||
:placeholder="replaceProps(col, col.placeholder)"
|
||||
:trigger-change="true"
|
||||
:multi="true"
|
||||
@change="(v)=>handleChangeDepartCommon(v,id,row,col)"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="j-td-span no-edit"
|
||||
:class="{disabled: buildProps(row,col).disabled}"
|
||||
@click="handleEditRow(row, col)"
|
||||
>{{ departCompValues[id] }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- 用户选择 -->
|
||||
<template v-else-if="col.type === formTypes.sel_user">
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
<j-select-user-by-dep
|
||||
v-if="isEditRow(row, col)"
|
||||
:id="id"
|
||||
:key="i"
|
||||
v-bind="buildProps(row,col)"
|
||||
style="width: 100%;"
|
||||
:value="userCompValues[id]"
|
||||
:placeholder="replaceProps(col, col.placeholder)"
|
||||
:trigger-change="true"
|
||||
:multi="true"
|
||||
@change="(v)=>handleChangeUserCommon(v,id,row,col)"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="j-td-span no-edit"
|
||||
:class="{disabled: buildProps(row,col).disabled}"
|
||||
@click="handleEditRow(row, col)"
|
||||
>{{ userCompValues[id] }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
|
||||
<!-- date -->
|
||||
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
@ -300,7 +350,7 @@
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
<a-upload
|
||||
name="file"
|
||||
:data="{'isup':1}"
|
||||
:data="{'isup':1, ...(col.data||{})}"
|
||||
:multiple="false"
|
||||
:action="col.action"
|
||||
:headers="uploadGetHeaders(row,col)"
|
||||
@ -331,6 +381,8 @@
|
||||
:dest-fields="col.destFields"
|
||||
:code="col.popupCode"
|
||||
:groupId="caseId"
|
||||
:param="col.param"
|
||||
:sorter="col.sorter"
|
||||
@input="(value,others)=>popupCallback(value,others,id,row,col,rowIndex)"
|
||||
/>
|
||||
<span
|
||||
@ -545,6 +597,33 @@
|
||||
</template>
|
||||
<!-- select搜索 -end -->
|
||||
|
||||
<!-- select异步搜索 -begin -->
|
||||
<template v-else-if="col.type === formTypes.sel_search_async">
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
<j-search-select-tag
|
||||
v-if="isEditRow(row, col)"
|
||||
:id="id"
|
||||
:key="i"
|
||||
:value="searchSelectAsyncValues[id]"
|
||||
:placeholder="replaceProps(col, col.placeholder)"
|
||||
:dict="col.dict"
|
||||
:async="true"
|
||||
:getPopupContainer="getParentContainer"
|
||||
v-bind="buildProps(row,col)"
|
||||
style="width: 100%;"
|
||||
@change="(v)=>handleSearchSelectAsyncChange(v,id,row,col)"
|
||||
>
|
||||
</j-search-select-tag>
|
||||
<span
|
||||
v-else
|
||||
class="j-td-span no-edit"
|
||||
:class="{disabled: buildProps(row,col).disabled}"
|
||||
@click="handleEditRow(row, col)"
|
||||
>{{ searchSelectAsyncValues[id] }}</span>
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<!-- select异步搜索 -end -->
|
||||
|
||||
<div v-else-if="col.type === formTypes.slot" :key="i">
|
||||
<a-tooltip v-bind="buildTooltipProps(row, col, id)">
|
||||
<slot
|
||||
@ -565,7 +644,7 @@
|
||||
</div>
|
||||
|
||||
<!-- else (normal) -->
|
||||
<span v-else :key="i" v-bind="buildProps(row,col)">{{ inputValues[rowIndex][col.key] }}</span>
|
||||
<span class="comp-normal" v-else :key="i" :title="inputValues[rowIndex][col.key]" v-bind="buildProps(row,col)">{{ inputValues[rowIndex][col.key] }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@ -622,12 +701,13 @@
|
||||
import Draggable from 'vuedraggable'
|
||||
import { ACCESS_TOKEN } from '@/store/mutation-types'
|
||||
import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil'
|
||||
import { cloneObject, randomString, randomNumber, getEventPath } from '@/utils/util'
|
||||
import { cloneObject, getEventPath, randomNumber, randomString } from '@/utils/util'
|
||||
import JDate from '@/components/jeecg/JDate'
|
||||
import { filterDictText, initDictOptions } from '@/components/dict/JDictSelectUtil'
|
||||
import { getFileAccessHttpUrl } from '@/api/manage';
|
||||
import { getFileAccessHttpUrl } from '@/api/manage'
|
||||
import JInputPop from '@/components/jeecg/minipop/JInputPop'
|
||||
import JFilePop from '@/components/jeecg/minipop/JFilePop'
|
||||
import { getNoAuthCols } from '@/utils/authFilter'
|
||||
|
||||
// 行高,需要在实例加载完成前用到
|
||||
let rowHeight = 61
|
||||
@ -704,6 +784,11 @@
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
authPre: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -749,11 +834,16 @@
|
||||
uploadValues: {},
|
||||
//popup信息
|
||||
popupValues: {},
|
||||
//部门组件信息
|
||||
departCompValues:{},
|
||||
//用户组件信息
|
||||
userCompValues: {},
|
||||
|
||||
radioValues: {},
|
||||
metaCheckboxValues: {},
|
||||
multiSelectValues: {},
|
||||
searchSelectValues: {},
|
||||
searchSelectAsyncValues: {},
|
||||
// 绑定左侧选择框已选择的id
|
||||
selectedRowIds: [],
|
||||
// 存储被删除行的id
|
||||
@ -775,6 +865,8 @@
|
||||
// 上次push数据的事件,用于判断是否点击过快
|
||||
lastPushTimeMap: new Map(),
|
||||
number:0,
|
||||
//不显示的按钮编码
|
||||
excludeCode:[]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -883,6 +975,8 @@
|
||||
columns: {
|
||||
immediate: true,
|
||||
handler(columns) {
|
||||
//列改变的时候重新设置按钮权限信息
|
||||
this.loadExcludeCode()
|
||||
// 兼容IE
|
||||
this.getElementPromise('tbody').then(() => {
|
||||
columns.forEach(column => {
|
||||
@ -964,41 +1058,52 @@
|
||||
this.visibleTrEls = []
|
||||
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
|
||||
if (!this.isFirst) {
|
||||
// inputValues:用来存储input表单的值
|
||||
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
||||
// 示例:
|
||||
// [{
|
||||
// id: "_jet-4sp0iu-15541771111770"
|
||||
// dbDefaultVal: "aaa",
|
||||
// dbFieldName: "bbb",
|
||||
// dbFieldTxt: "ccc",
|
||||
// dbLength: 32
|
||||
// }]
|
||||
this.inputValues = []
|
||||
this.rows = []
|
||||
this.deleteIds = []
|
||||
this.selectValues = {}
|
||||
this.checkboxValues = {}
|
||||
this.jdateValues = {}
|
||||
this.jInputPopValues = {}
|
||||
this.slotValues = {}
|
||||
this.selectedRowIds = []
|
||||
this.tooltips = {}
|
||||
this.notPassedIds = []
|
||||
this.uploadValues = []
|
||||
this.popupValues = []
|
||||
this.radioValues = []
|
||||
this.multiSelectValues = []
|
||||
this.searchSelectValues = []
|
||||
this.scrollTop = 0
|
||||
this.$nextTick(() => {
|
||||
this.getElement('tbody').scrollTop = 0
|
||||
})
|
||||
this.clearRow();
|
||||
} else {
|
||||
this.isFirst = false
|
||||
}
|
||||
},
|
||||
/**清空行*/
|
||||
clearRow(){
|
||||
// inputValues:用来存储input表单的值
|
||||
// 数组里的每项都是一个对象,对象里每个key都是input的rowKey,值就是input的值,其中有个id的字段来区分
|
||||
// 示例:
|
||||
// [{
|
||||
// id: "_jet-4sp0iu-15541771111770"
|
||||
// dbDefaultVal: "aaa",
|
||||
// dbFieldName: "bbb",
|
||||
// dbFieldTxt: "ccc",
|
||||
// dbLength: 32
|
||||
// }]
|
||||
this.inputValues = []
|
||||
this.rows = []
|
||||
this.deleteIds = []
|
||||
this.selectedRowIds = []
|
||||
this.tooltips = {}
|
||||
this.notPassedIds = []
|
||||
// 重置values
|
||||
this.selectValues = {}
|
||||
this.checkboxValues = {}
|
||||
this.jdateValues = {}
|
||||
this.jInputPopValues = {}
|
||||
this.departCompValues = {}
|
||||
this.userCompValues = {}
|
||||
this.slotValues = {}
|
||||
//update-begin-author:shunjlei date:20210415 for:类型赋值错误
|
||||
this.uploadValues = {}
|
||||
this.popupValues = {}
|
||||
this.radioValues = {}
|
||||
this.multiSelectValues = {}
|
||||
this.searchSelectValues = {}
|
||||
this.searchSelectAsyncValues = {}
|
||||
//update-end-author:shunjlei date:20210415 for:类型赋值错误
|
||||
|
||||
// 重置滚动条
|
||||
this.scrollTop = 0
|
||||
this.$nextTick(() => {
|
||||
this.getElement('tbody').scrollTop = 0
|
||||
})
|
||||
},
|
||||
/** 同步滚动条状态 */
|
||||
syncScrollBar(scrollLeft) {
|
||||
// this.style.tbody.left = `${scrollLeft}px`
|
||||
@ -1058,6 +1163,8 @@
|
||||
let checkboxValues = { ...this.checkboxValues }
|
||||
let selectValues = { ...this.selectValues }
|
||||
let jdateValues = { ...this.jdateValues }
|
||||
let departCompValues = { ...this.departCompValues }
|
||||
let userCompValues = { ...this.userCompValues }
|
||||
let jInputPopValues = { ...this.jInputPopValues }
|
||||
let slotValues = { ...this.slotValues }
|
||||
let uploadValues = { ...this.uploadValues }
|
||||
@ -1065,6 +1172,7 @@
|
||||
let radioValues = { ...this.radioValues }
|
||||
let multiSelectValues = { ...this.multiSelectValues }
|
||||
let searchSelectValues = { ...this.searchSelectValues }
|
||||
let searchSelectAsyncValues = { ...this.searchSelectAsyncValues }
|
||||
// 禁用行的id
|
||||
let disabledRowIds = (this.disabledRowIds || [])
|
||||
dataSource.forEach((data, newValueIndex) => {
|
||||
@ -1144,12 +1252,18 @@
|
||||
|
||||
} else if (column.type === FormTypes.popup) {
|
||||
popupValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.sel_depart) {
|
||||
departCompValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.sel_user) {
|
||||
userCompValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.input_pop) {
|
||||
jInputPopValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.radio) {
|
||||
radioValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.sel_search) {
|
||||
searchSelectValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.sel_search_async) {
|
||||
searchSelectAsyncValues[inputId] = sourceValue
|
||||
} else if (column.type === FormTypes.list_multi) {
|
||||
if (typeof sourceValue === 'string' && sourceValue.length > 0) {
|
||||
multiSelectValues[inputId] = sourceValue.split(',')
|
||||
@ -1170,6 +1284,8 @@
|
||||
status: 'done',
|
||||
path: sourceValue
|
||||
}
|
||||
} else {
|
||||
uploadValues[inputId] = null
|
||||
}
|
||||
} else {
|
||||
value[column.key] = sourceValue
|
||||
@ -1225,6 +1341,8 @@
|
||||
this.checkboxValues = checkboxValues
|
||||
this.selectValues = selectValues
|
||||
this.jdateValues = jdateValues
|
||||
this.departCompValues = departCompValues
|
||||
this.userCompValues = userCompValues
|
||||
this.jInputPopValues = jInputPopValues
|
||||
this.slotValues = slotValues
|
||||
this.uploadValues = uploadValues
|
||||
@ -1232,6 +1350,7 @@
|
||||
this.radioValues = radioValues
|
||||
this.multiSelectValues = multiSelectValues
|
||||
this.searchSelectValues = searchSelectValues
|
||||
this.searchSelectAsyncValues = searchSelectAsyncValues
|
||||
// 重新计算所有统计列
|
||||
this.recalcAllStatisticsColumns()
|
||||
// 更新到 dom
|
||||
@ -1440,6 +1559,12 @@
|
||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
||||
value[column.key] = this.jdateValues[inputId]
|
||||
|
||||
} else if (column.type === FormTypes.sel_depart) {
|
||||
value[column.key] = this.departCompValues[inputId]
|
||||
|
||||
} else if (column.type === FormTypes.sel_user) {
|
||||
value[column.key] = this.userCompValues[inputId]
|
||||
|
||||
} else if (column.type === FormTypes.input_pop) {
|
||||
value[column.key] = this.jInputPopValues[inputId]
|
||||
|
||||
@ -1460,6 +1585,8 @@
|
||||
value[column.key] = this.radioValues[inputId]
|
||||
} else if (column.type === FormTypes.sel_search) {
|
||||
value[column.key] = this.searchSelectValues[inputId]
|
||||
} else if (column.type === FormTypes.sel_search_async) {
|
||||
value[column.key] = this.searchSelectAsyncValues[inputId]
|
||||
} else if (column.type === FormTypes.list_multi) {
|
||||
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
|
||||
value[column.key] = ''
|
||||
@ -1579,6 +1706,8 @@
|
||||
selectValues: this.selectValues,
|
||||
checkboxValues: this.checkboxValues,
|
||||
jdateValues: this.jdateValues,
|
||||
departCompValues: this.departCompValues,
|
||||
userCompValues: this.userCompValues,
|
||||
jInputPopValues: this.jInputPopValues,
|
||||
slotValues: this.slotValues,
|
||||
uploadValues: this.uploadValues,
|
||||
@ -1586,6 +1715,7 @@
|
||||
radioValues: this.radioValues,
|
||||
multiSelectValues: this.multiSelectValues,
|
||||
searchSelectValues: this.searchSelectValues,
|
||||
searchSelectAsyncValues: this.searchSelectAsyncValues,
|
||||
})
|
||||
},
|
||||
/** 设置某行某列的值 */
|
||||
@ -1633,6 +1763,10 @@
|
||||
edited = true
|
||||
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
|
||||
edited = this.setOneValue(this.jdateValues, modelKey, newValue)
|
||||
} else if (column.type === FormTypes.sel_depart) {
|
||||
edited = this.setOneValue(this.departCompValues, modelKey, newValue)
|
||||
} else if (column.type === FormTypes.sel_user) {
|
||||
edited = this.setOneValue(this.userCompValues, modelKey, newValue)
|
||||
} else if (column.type === FormTypes.input_pop) {
|
||||
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
|
||||
} else if (column.type === FormTypes.slot) {
|
||||
@ -1647,6 +1781,8 @@
|
||||
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
|
||||
} else if (column.type === FormTypes.sel_search) {
|
||||
edited = this.setOneValue(this.searchSelectValues, modelKey, newValue)
|
||||
} else if (column.type === FormTypes.sel_search_async) {
|
||||
edited = this.setOneValue(this.searchSelectAsyncValues, modelKey, newValue)
|
||||
} else {
|
||||
edited = false
|
||||
}
|
||||
@ -1809,7 +1945,7 @@
|
||||
|
||||
// 兼容 online 的规则
|
||||
let foo = [
|
||||
{ title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,18}$/ },
|
||||
{ title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,16}$/ },
|
||||
{ title: '6到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/ },
|
||||
{ title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/ },
|
||||
{ title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ },
|
||||
@ -2183,6 +2319,20 @@
|
||||
this.elemValueChange(FormTypes.date, row, column, value)
|
||||
}
|
||||
},
|
||||
//部门组件值改变
|
||||
handleChangeDepartCommon(value, id, row, column){
|
||||
this.departCompValues = this.bindValuesChange(value, id, 'departCompValues')
|
||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||
// 触发valueChange 事件
|
||||
this.elemValueChange(FormTypes.sel_depart, row, column, value)
|
||||
},
|
||||
//用户组件值改变
|
||||
handleChangeUserCommon(value, id, row, column){
|
||||
this.userCompValues = this.bindValuesChange(value, id, 'userCompValues')
|
||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||
// 触发valueChange 事件
|
||||
this.elemValueChange(FormTypes.sel_user, row, column, value)
|
||||
},
|
||||
handleChangeJInputPopCommon(value, id, row, column){
|
||||
this.jInputPopValues = this.bindValuesChange(value, id, 'jInputPopValues')
|
||||
// 做单个表单验证
|
||||
@ -2462,7 +2612,7 @@
|
||||
}
|
||||
},
|
||||
/** view辅助方法:构建 td style */
|
||||
buildTdStyle(col,isTitle) {
|
||||
buildTdStyle(col) {
|
||||
const isEmptyWidth = (column) => (column.type === FormTypes.hidden || column.width === '0px' || column.width === '0' || column.width === 0)
|
||||
|
||||
let style = {}
|
||||
@ -2475,13 +2625,15 @@
|
||||
style['width'] = '120px'
|
||||
}
|
||||
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||
//是否为标题,如果是时间控件设为200,时间控件的标题设为240 时间
|
||||
//如果是时间控件设为200px
|
||||
if(col.type === FormTypes.datetime){
|
||||
if(true === isTitle){
|
||||
style['width'] = '240px'
|
||||
}else{
|
||||
style['width'] = '200px'
|
||||
}
|
||||
style['width'] = '200px'
|
||||
}
|
||||
if(col.type === FormTypes.sel_user && !col.width){
|
||||
style['width'] = '220px'
|
||||
}
|
||||
if(col.type === FormTypes.sel_depart && !col.width){
|
||||
style['width'] = '160px'
|
||||
}
|
||||
//update-end-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
|
||||
|
||||
@ -2599,7 +2751,7 @@
|
||||
}
|
||||
this.setOneValue(this.popupValues, id, popupValue)
|
||||
// 做单个表单验证
|
||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||
this.validateOneInput(popupValue, row, column, this.notPassedIds, true, 'change')
|
||||
// 触发valueChange 事件
|
||||
this.elemValueChange('input', row, column, value)
|
||||
},
|
||||
@ -2626,6 +2778,11 @@
|
||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||
this.elemValueChange(FormTypes.sel_search, row, column, value)
|
||||
},
|
||||
handleSearchSelectAsyncChange(value, id, row, column) {
|
||||
this.searchSelectAsyncValues = this.bindValuesChange(value, id, 'searchSelectAsyncValues')
|
||||
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
|
||||
this.elemValueChange(FormTypes.sel_search_async, row, column, value)
|
||||
},
|
||||
filterOption(input, option) {
|
||||
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
},
|
||||
@ -2718,15 +2875,35 @@
|
||||
removeEventListener() {
|
||||
window.removeEventListener('mouseup', this.handleMouseup)
|
||||
},
|
||||
|
||||
/* --------------------------- 2020年5月18日 默认span模式 ------------------------------ */
|
||||
|
||||
//获取没有授权的按钮编码
|
||||
loadExcludeCode(){
|
||||
if(!this.authPre || this.authPre.length==0){
|
||||
this.excludeCode = []
|
||||
}else{
|
||||
let pre = this.authPre
|
||||
if(!pre.endsWith(':')){
|
||||
pre += ':'
|
||||
}
|
||||
this.excludeCode = getNoAuthCols(pre)
|
||||
}
|
||||
},
|
||||
//判断button是否显示
|
||||
buttonPermission(code){
|
||||
if(!this.excludeCode || this.excludeCode.length==0){
|
||||
return true
|
||||
}else{
|
||||
return this.excludeCode.indexOf(code)<0
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.removeEventListener()
|
||||
this.destroyCleanGroupRequest = true
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -2867,6 +3044,8 @@
|
||||
border-bottom: @border;
|
||||
transition: background-color 300ms;
|
||||
width: 100%;
|
||||
height: 61px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 10;
|
||||
@ -2976,6 +3155,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.comp-normal {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.j-td-span {
|
||||
position: relative;
|
||||
padding: 4px 11px;
|
||||
|
||||
@ -128,6 +128,9 @@
|
||||
this.reload()
|
||||
}
|
||||
})
|
||||
//update--begin--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||
this.reload()
|
||||
//update--end--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
|
||||
}else{
|
||||
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
|
||||
let tabLayout = getVmParentByName(this, 'TabLayout')
|
||||
|
||||
@ -11,13 +11,13 @@
|
||||
:beforeUpload="beforeUpload"
|
||||
:disabled="disabled"
|
||||
:isMultiple="isMultiple"
|
||||
:showUploadList="isMultiple"
|
||||
|
||||
@change="handleChange"
|
||||
@preview="handlePreview"
|
||||
:class="!isMultiple?'imgupload':''">
|
||||
<div style="width:104px;height:104px">
|
||||
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>
|
||||
<div v-else class="iconp">
|
||||
:class="[!isMultiple?'imgupload':'', (!isMultiple && picUrl)?'image-upload-single-over':'' ]">
|
||||
<div>
|
||||
<!--<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>-->
|
||||
<div class="iconp">
|
||||
<a-icon :type="uploadLoading ? 'loading' : 'plus'" />
|
||||
<div class="ant-upload-text">{{ text }}</div>
|
||||
</div>
|
||||
@ -189,7 +189,7 @@
|
||||
path = ''
|
||||
}
|
||||
let arr = [];
|
||||
if(!this.isMultiple){
|
||||
if(!this.isMultiple && uploadFiles.length>0){
|
||||
arr.push(uploadFiles[uploadFiles.length-1].response.message)
|
||||
}else{
|
||||
for(let a=0;a<uploadFiles.length;a++){
|
||||
@ -231,8 +231,9 @@
|
||||
* https://github.com/zhangdaiscott/jeecg-boot/issues/1810
|
||||
* https://github.com/zhangdaiscott/jeecg-boot/issues/1779
|
||||
*/
|
||||
/deep/ .imgupload .ant-upload-select{display:block}
|
||||
/deep/ .imgupload .ant-upload.ant-upload-select-picture-card{ width:120px;height: 120px;}
|
||||
/deep/ .imgupload .iconp{padding:32px;}
|
||||
|
||||
/deep/ .imgupload .iconp{padding:20px;}
|
||||
/* update--end--autor:lvdandan-----date:20201016------for:j-image-upload图片组件单张图片详情回显空白*/
|
||||
|
||||
/deep/ .image-upload-single-over .ant-upload-select{display: none}
|
||||
</style>
|
||||
|
||||
@ -6,6 +6,13 @@
|
||||
:confirmLoading="uploading"
|
||||
@cancel="handleClose">
|
||||
|
||||
<div style="margin: 0px 0px 5px 1px" v-if="online">
|
||||
<span style="display: inline-block;height: 32px;line-height: 32px;vertical-align: middle;">是否开启校验:</span>
|
||||
<span style="display: inline-block;height: 32px;margin-left: 6px">
|
||||
<a-switch :checked="validateStatus==1" @change="handleChangeValidateStatus" checked-children="是" un-checked-children="否" size="small"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a-upload
|
||||
name="file"
|
||||
:multiple="true"
|
||||
@ -47,6 +54,12 @@
|
||||
type: String,
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
//是否online导入
|
||||
online:{
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
@ -55,7 +68,8 @@
|
||||
uploading:false,
|
||||
fileList:[],
|
||||
uploadAction:'',
|
||||
foreignKeys:''
|
||||
foreignKeys:'',
|
||||
validateStatus: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -78,6 +92,7 @@
|
||||
this.uploading = false
|
||||
this.visible = true
|
||||
this.foreignKeys = arg;
|
||||
this.validateStatus = 0
|
||||
},
|
||||
handleRemove(file) {
|
||||
const index = this.fileList.indexOf(file);
|
||||
@ -98,6 +113,9 @@
|
||||
if(this.foreignKeys && this.foreignKeys.length>0){
|
||||
formData.append('foreignKeys',this.foreignKeys);
|
||||
}
|
||||
if(this.online==true){
|
||||
formData.append('validateStatus',this.validateStatus);
|
||||
}
|
||||
fileList.forEach((file) => {
|
||||
formData.append('files[]', file);
|
||||
});
|
||||
@ -105,14 +123,41 @@
|
||||
postAction(this.uploadAction, formData).then((res) => {
|
||||
this.uploading = false
|
||||
if(res.success){
|
||||
this.$message.success(res.message)
|
||||
if(res.code == 201){
|
||||
this.errorTip(res.message, res.result)
|
||||
}else{
|
||||
this.$message.success(res.message)
|
||||
}
|
||||
this.visible=false
|
||||
this.$emit('ok')
|
||||
}else{
|
||||
this.$message.warning(res.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
// 是否开启校验 开关改变事件
|
||||
handleChangeValidateStatus(checked){
|
||||
this.validateStatus = checked==true?1:0
|
||||
},
|
||||
// 错误信息提示
|
||||
errorTip(tipMessage, fileUrl) {
|
||||
const h = this.$createElement;
|
||||
let href = window._CONFIG['domianURL'] + fileUrl
|
||||
this.$warning({
|
||||
title: '导入成功,但是有错误数据!',
|
||||
content: h('div', {}, [
|
||||
h('div', tipMessage),
|
||||
h('span', '具体详情请 '),
|
||||
h('a', {
|
||||
attrs: {
|
||||
href: href,
|
||||
target: '_blank'
|
||||
},
|
||||
},'点击下载'),
|
||||
]),
|
||||
onOk() {},
|
||||
});
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,10 +8,11 @@
|
||||
v-on="$listeners"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
destroyOnClose
|
||||
>
|
||||
|
||||
<slot></slot>
|
||||
|
||||
<!--有设置标题-->
|
||||
<template v-if="!isNoTitle" slot="title">
|
||||
<a-row class="j-modal-title-row" type="flex">
|
||||
<a-col class="left">
|
||||
@ -22,6 +23,14 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
<!--没有设置标题-->
|
||||
<template v-else slot="title">
|
||||
<a-row class="j-modal-title-row" type="flex">
|
||||
<a-col v-if="switchFullscreen" class="right" @click="toggleFullscreen">
|
||||
<a-button class="ant-modal-close ant-modal-close-x" ghost type="link" :icon="fullscreenButtonIcon"/>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<!-- 处理 scopedSlots -->
|
||||
<template v-for="slotName of scopedSlotsKeys" :slot="slotName">
|
||||
@ -161,7 +170,6 @@
|
||||
|
||||
<style lang="less">
|
||||
.j-modal-box {
|
||||
|
||||
&.fullscreen {
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -190,7 +198,6 @@
|
||||
height: calc(100% - 55px);
|
||||
}
|
||||
}
|
||||
|
||||
&.no-title.no-footer {
|
||||
.ant-modal-body {
|
||||
height: 100%;
|
||||
@ -217,6 +224,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
&.no-title{
|
||||
.ant-modal-header {
|
||||
padding: 0px 24px;
|
||||
border-bottom: 0px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
ref="jPopupOnlReport"
|
||||
:code="code"
|
||||
:multi="multi"
|
||||
:sorter="sorter"
|
||||
:groupId="uniqGroupId"
|
||||
:param="param"
|
||||
@ok="callBack"
|
||||
@ -47,6 +48,11 @@
|
||||
default: '',
|
||||
required: false
|
||||
},
|
||||
/** 排序列,指定要排序的列,使用方式:列名=desc|asc */
|
||||
sorter: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 1200,
|
||||
@ -82,6 +88,11 @@
|
||||
required: false,
|
||||
default: ()=>{}
|
||||
},
|
||||
spliter:{
|
||||
type: String,
|
||||
required: false,
|
||||
default: ','
|
||||
},
|
||||
/** 分组ID,用于将多个popup的请求合并到一起,不传不分组 */
|
||||
groupId: String
|
||||
|
||||
@ -108,7 +119,7 @@
|
||||
if (!val) {
|
||||
this.showText = ''
|
||||
} else {
|
||||
this.showText = val
|
||||
this.showText = val.split(this.spliter).join(',')
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,7 +199,11 @@
|
||||
} else {
|
||||
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
|
||||
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.field)]])
|
||||
this.$emit('input', this.showText, res)
|
||||
let str = ''
|
||||
if(this.showText){
|
||||
str = this.showText.split(',').join(this.spliter)
|
||||
}
|
||||
this.$emit('input', str, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
<a-select-option
|
||||
v-for="(item,index) in options"
|
||||
:key="index"
|
||||
:getPopupContainer="getParentContainer"
|
||||
:value="item.value">
|
||||
{{ item.text || item.label }}
|
||||
</a-select-option>
|
||||
@ -36,11 +37,21 @@
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
spliter:{
|
||||
type: String,
|
||||
required: false,
|
||||
default: ','
|
||||
},
|
||||
popContainer:{
|
||||
type:String,
|
||||
default:'',
|
||||
required:false
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
arrayValue:!this.value?[]:this.value.split(",")
|
||||
arrayValue:!this.value?[]:this.value.split(this.spliter)
|
||||
}
|
||||
},
|
||||
watch:{
|
||||
@ -48,18 +59,25 @@
|
||||
if(!val){
|
||||
this.arrayValue = []
|
||||
}else{
|
||||
this.arrayValue = this.value.split(",")
|
||||
this.arrayValue = this.value.split(this.spliter)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
onChange (selectedValue) {
|
||||
if(this.triggerChange){
|
||||
this.$emit('change', selectedValue.join(","));
|
||||
this.$emit('change', selectedValue.join(this.spliter));
|
||||
}else{
|
||||
this.$emit('input', selectedValue.join(","));
|
||||
this.$emit('input', selectedValue.join(this.spliter));
|
||||
}
|
||||
},
|
||||
getParentContainer(node){
|
||||
if(!this.popContainer){
|
||||
return node.parentNode
|
||||
}else{
|
||||
return document.querySelector(this.popContainer)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
@ -101,7 +101,15 @@
|
||||
</a-col>
|
||||
|
||||
<a-col :md="8" :xs="24" style="margin-bottom: 12px;">
|
||||
<template v-if="item.dictCode">
|
||||
<!-- 下拉搜索 -->
|
||||
<j-search-select-tag v-if="item.type==='sel_search'" v-model="item.val" :dict="getDictInfo(item)" placeholder="请选择"/>
|
||||
<!-- 下拉多选 -->
|
||||
<template v-else-if="item.type==='list_multi'">
|
||||
<j-multi-select-tag v-if="item.options" v-model="item.val" :options="item.options" placeholder="请选择"/>
|
||||
<j-multi-select-tag v-else v-model="item.val" :dictCode="getDictInfo(item)" placeholder="请选择"/>
|
||||
</template>
|
||||
|
||||
<template v-else-if="item.dictCode">
|
||||
<template v-if="item.type === 'table-dict'">
|
||||
<j-popup
|
||||
v-model="item.val"
|
||||
@ -109,6 +117,7 @@
|
||||
:field="item.dictCode"
|
||||
:orgFields="item.dictCode"
|
||||
:destFields="item.dictCode"
|
||||
:multi="true"
|
||||
></j-popup>
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -116,7 +125,13 @@
|
||||
<j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
|
||||
</template>
|
||||
</template>
|
||||
<j-popup v-else-if="item.type === 'popup'" :value="item.val" v-bind="item.popup" group-id="superQuery" @input="(e,v)=>handleChangeJPopup(item,e,v)"/>
|
||||
<j-popup
|
||||
v-else-if="item.type === 'popup'"
|
||||
:value="item.val"
|
||||
v-bind="item.popup"
|
||||
group-id="superQuery"
|
||||
@input="(e,v)=>handleChangeJPopup(item,e,v)"
|
||||
:multi="true"/>
|
||||
<j-select-multi-user
|
||||
v-else-if="item.type === 'select-user' || item.type === 'sel_user'"
|
||||
v-model="item.val"
|
||||
@ -338,6 +353,17 @@
|
||||
}
|
||||
this.visible = true
|
||||
},
|
||||
|
||||
getDictInfo(item) {
|
||||
let str = ''
|
||||
if(!item.dictTable){
|
||||
str = item.dictCode
|
||||
}else{
|
||||
str = item.dictTable+','+item.dictText+','+item.dictCode
|
||||
}
|
||||
console.log('高级查询字典信息',str)
|
||||
return str
|
||||
},
|
||||
handleOk() {
|
||||
if (!this.isNullArray(this.queryParamsModel)) {
|
||||
let event = {
|
||||
@ -386,11 +412,12 @@
|
||||
this.queryParamsModel.splice(index, 1)
|
||||
},
|
||||
handleSelected(node, item) {
|
||||
let { type, options, dictCode, dictTable, customReturnField, popup } = node.dataRef
|
||||
let { type, options, dictCode, dictTable, dictText, customReturnField, popup } = node.dataRef
|
||||
item['type'] = type
|
||||
item['options'] = options
|
||||
item['dictCode'] = dictCode
|
||||
item['dictTable'] = dictTable
|
||||
item['dictText'] = dictText
|
||||
item['customReturnField'] = customReturnField
|
||||
if (popup) {
|
||||
item['popup'] = popup
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<a-upload
|
||||
name="file"
|
||||
:multiple="true"
|
||||
:multiple="multiple"
|
||||
:action="uploadAction"
|
||||
:headers="headers"
|
||||
:data="{'biz':bizPath}"
|
||||
@ -135,6 +135,10 @@
|
||||
required:false,
|
||||
default: true
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
watch:{
|
||||
value:{
|
||||
@ -374,14 +378,17 @@
|
||||
},
|
||||
mounted(){
|
||||
const moverObj = document.getElementById(this.containerId+'-mover');
|
||||
moverObj.addEventListener('mouseover',()=>{
|
||||
this.moverHold = true
|
||||
this.moveDisplay = 'block';
|
||||
});
|
||||
moverObj.addEventListener('mouseout',()=>{
|
||||
this.moverHold = false
|
||||
this.moveDisplay = 'none';
|
||||
});
|
||||
if(moverObj){
|
||||
moverObj.addEventListener('mouseover',()=>{
|
||||
this.moverHold = true
|
||||
this.moveDisplay = 'block';
|
||||
});
|
||||
moverObj.addEventListener('mouseout',()=>{
|
||||
this.moverHold = false
|
||||
this.moveDisplay = 'none';
|
||||
});
|
||||
}
|
||||
|
||||
let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[];
|
||||
if(picList && picList.length>0){
|
||||
picList[0].addEventListener('mouseover',(ev)=>{
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-popover :visible="visible" placement="bottom" overlayClassName="j-vxe-popover-overlay" :overlayStyle="overlayStyle">
|
||||
<a-popover :visible="visible" :placement="placement" overlayClassName="j-vxe-popover-overlay" :overlayStyle="overlayStyle">
|
||||
<div class="j-vxe-popover-title" slot="title">
|
||||
<div>子表</div>
|
||||
<div class="j-vxe-popover-title-close" @click="close">
|
||||
@ -34,6 +34,7 @@
|
||||
width: null,
|
||||
zIndex: 100
|
||||
},
|
||||
placement: 'bottom'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -41,6 +42,14 @@
|
||||
methods: {
|
||||
|
||||
toggle(event) {
|
||||
|
||||
//update-begin-author:taoyan date:20200921 for: 弹出子表时,子表会闪一下,类似重新计算子表的位置
|
||||
if(document.body.clientHeight - event.$event.clientY > 350){
|
||||
this.placement = 'bottom'
|
||||
}else{
|
||||
this.placement = 'top'
|
||||
}
|
||||
//update-end-author:taoyan date:20200921 for: 弹出子表时,子表会闪一下,类似重新计算子表的位置
|
||||
if (this.row == null) {
|
||||
this.open(event)
|
||||
} else {
|
||||
@ -83,13 +92,22 @@
|
||||
this.$refs.div.style.height = clientHeight + 'px'
|
||||
this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px'
|
||||
this.overlayStyle.maxWidth = this.overlayStyle.width
|
||||
domAlign(this.$refs.div, tr, {
|
||||
//update-begin-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
|
||||
//let realTable = getParentNodeByTagName(tr, 'table')
|
||||
//let left = realTable.parentNode.scrollLeft
|
||||
let h = event.$event.clientY
|
||||
if(h){
|
||||
h = h-140
|
||||
}
|
||||
let toolbar = this.$refs.div.nextSibling
|
||||
domAlign(this.$refs.div, toolbar, {
|
||||
points: ['tl', 'tl'],
|
||||
offset: [0, 0],
|
||||
offset: [0, h],
|
||||
overflow: {
|
||||
alwaysByViewport: true
|
||||
},
|
||||
})
|
||||
//update-end-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
|
||||
this.$nextTick(() => {
|
||||
this.visible = true
|
||||
this.$nextTick(() => {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import XEUtils from 'xe-utils'
|
||||
import PropTypes from 'ant-design-vue/es/_util/vue-types'
|
||||
import { JVXETypes } from '@/components/jeecg/JVxeTable/index'
|
||||
import { JVXETypes } from '@/components/jeecg/JVxeTable/jvxeTypes'
|
||||
import VxeWebSocketMixins from '../mixins/vxe.web.socket.mixins'
|
||||
import { initDictOptions } from '@/components/dict/JDictSelectUtil'
|
||||
|
||||
@ -13,7 +13,7 @@ import JVxeDetailsModal from './JVxeDetailsModal'
|
||||
import JVxePagination from './JVxePagination'
|
||||
import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util'
|
||||
import { UtilTools } from 'vxe-table/packages/tools/src/utils'
|
||||
import { getNoAuthCols } from "@/utils/authFilter"
|
||||
import { getNoAuthCols } from '@/utils/authFilter'
|
||||
|
||||
export default {
|
||||
name: 'JVxeTable',
|
||||
@ -95,6 +95,9 @@ export default {
|
||||
// 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启,
|
||||
// 在remove事件里调用confirmRemove方法才会真正删除(除非删除的全是新增的行)
|
||||
asyncRemove: PropTypes.bool.def(false),
|
||||
// 是否一直显示组件,如果为false则只有点击的时候才出现组件
|
||||
// 注:该参数不能动态修改;如果行、列字段多的情况下,会根据机器性能造成不同程度的卡顿。
|
||||
alwaysEdit: PropTypes.bool.def(false),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -188,6 +191,21 @@ export default {
|
||||
}
|
||||
}
|
||||
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
|
||||
|
||||
// update--begin--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
|
||||
if (column.$type === JVXETypes.datetime || column.$type === JVXETypes.userSelect || column.$type === JVXETypes.departSelect) {
|
||||
let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
|
||||
if(width <= 190){
|
||||
column.width = '190px'
|
||||
}
|
||||
}
|
||||
if (column.$type === JVXETypes.date) {
|
||||
let width = column.width && column.width.endsWith('px')?Number.parseInt(column.width.substr(0,column.width.length-2)):0;
|
||||
if(width <= 135){
|
||||
column.width = '135px'
|
||||
}
|
||||
}
|
||||
// update--end--autor:lvdandan-----date:20201211------for:JT-118 【online】 日期、时间控件长度较小
|
||||
})
|
||||
return this._innerColumns
|
||||
},
|
||||
@ -339,7 +357,7 @@ export default {
|
||||
col.visible = false
|
||||
} else if (enhanced.switches.editRender) {
|
||||
renderName = 'editRender'
|
||||
renderOptions.type = enhanced.switches.visible ? 'visible' : 'default'
|
||||
renderOptions.type = (enhanced.switches.visible || this.alwaysEdit) ? 'visible' : 'default'
|
||||
}
|
||||
} else {
|
||||
renderOptions.name = JVXETypes._prefix + JVXETypes.normal
|
||||
@ -709,6 +727,11 @@ export default {
|
||||
deleteData: this.getDeleteData()
|
||||
}
|
||||
},
|
||||
/** 获取表格表单里的值 */
|
||||
getValues(callback, rowIds) {
|
||||
let tableData = this.getTableData({rowIds: rowIds})
|
||||
callback('', tableData)
|
||||
},
|
||||
/** 获取表格数据 */
|
||||
getTableData(options = {}) {
|
||||
let {rowIds} = options
|
||||
@ -864,6 +887,8 @@ export default {
|
||||
trigger(name, event = {}) {
|
||||
event.$target = this
|
||||
event.$table = this.$refs.vxe
|
||||
//online增强参数兼容
|
||||
event.target = this
|
||||
this.$emit(name, event)
|
||||
},
|
||||
|
||||
@ -885,7 +910,11 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
//options自定义赋值 刷新
|
||||
virtualRefresh(){
|
||||
this.scrolling = true
|
||||
this.closeScrolling()
|
||||
},
|
||||
// 设置 this.scrolling 防抖模式
|
||||
closeScrolling: simpleDebounce(function () {
|
||||
this.scrolling = false
|
||||
@ -1050,7 +1079,7 @@ export default {
|
||||
// 添加默认值
|
||||
xTable.tableFullColumn.forEach(column => {
|
||||
let col = column.own
|
||||
if (record[col.key] == null || record[col.key] === '') {
|
||||
if (col.key && (record[col.key] == null || record[col.key] === '')) {
|
||||
// 设置默认值
|
||||
let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
|
||||
record[col.key] = createValue({row: record, column, $table: xTable})
|
||||
@ -1201,7 +1230,7 @@ export default {
|
||||
// 兼容 online 的规则
|
||||
const fooPatterns = [
|
||||
{title: '非空', value: '*', pattern: /^.+$/},
|
||||
{title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,18}$/},
|
||||
{title: '6到16位数字', value: 'n6-16', pattern: /^\d{6,16}$/},
|
||||
{title: '6到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/},
|
||||
{title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/},
|
||||
{title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/},
|
||||
|
||||
@ -59,7 +59,7 @@
|
||||
// TODO 需要将remove替换batch_delete
|
||||
// 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下
|
||||
if(exclude.indexOf('batch_delete')>=0){
|
||||
exclude.add('remove')
|
||||
exclude.push('remove')
|
||||
}
|
||||
// 按钮权限 需要去掉不被授权的按钮
|
||||
return arr.filter(item=>{
|
||||
|
||||
@ -55,7 +55,9 @@
|
||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||
enhanced: {
|
||||
aopEvents: {
|
||||
editActived: event => dispatchEvent(event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event)),
|
||||
editActived(event) {
|
||||
dispatchEvent.call(this, event, 'ant-calendar-picker', el => el.children[0].dispatchEvent(event.$event))
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-input
|
||||
v-show="!departIds"
|
||||
@click="openSelect"
|
||||
placeholder="请点击选择部门"
|
||||
v-model="departNames"
|
||||
readOnly
|
||||
:disabled="componentDisabled"
|
||||
class="jvxe-select-input">
|
||||
<a-icon slot="prefix" type="cluster" title="部门选择控件"/>
|
||||
</a-input>
|
||||
<j-select-depart-modal
|
||||
ref="innerDepartSelectModal"
|
||||
:modal-width="modalWidth"
|
||||
:multi="multi"
|
||||
:rootOpened="rootOpened"
|
||||
:depart-id="departIds"
|
||||
@ok="handleOK"
|
||||
@initComp="initComp"/>
|
||||
<span style="display: inline-block;height:100%;padding-left:14px" v-if="departIds" >
|
||||
<span @click="openSelect" style="display: inline-block;vertical-align: middle">{{ departNames }}</span>
|
||||
<a-icon style="margin-left:5px;vertical-align: middle" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||
import JSelectDepartModal from '@/components/jeecgbiz/modal/JSelectDepartModal'
|
||||
|
||||
export default {
|
||||
name: 'JVxeDepartSelectCell',
|
||||
mixins: [JVxeCellMixins],
|
||||
components:{
|
||||
JSelectDepartModal
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
departNames: '',
|
||||
departIds: '',
|
||||
selectedOptions: [],
|
||||
customReturnField: 'id'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
custProps() {
|
||||
const {departIds, originColumn: col, caseId, cellProps} = this
|
||||
return {
|
||||
...cellProps,
|
||||
value: departIds,
|
||||
field: col.field || col.key,
|
||||
groupId: caseId,
|
||||
class: 'jvxe-select'
|
||||
}
|
||||
},
|
||||
componentDisabled(){
|
||||
if(this.cellProps.disabled==true){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
modalWidth(){
|
||||
if(this.cellProps.modalWidth){
|
||||
return this.cellProps.modalWidth
|
||||
}else{
|
||||
return 500
|
||||
}
|
||||
},
|
||||
multi(){
|
||||
if(this.cellProps.multi==false){
|
||||
return false
|
||||
}else{
|
||||
return true
|
||||
}
|
||||
},
|
||||
rootOpened(){
|
||||
if(this.cellProps.open==false){
|
||||
return false
|
||||
}else{
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
innerValue: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (val == null || val === '') {
|
||||
this.departIds = ''
|
||||
} else {
|
||||
this.departIds = val
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openSelect(){
|
||||
this.$refs.innerDepartSelectModal.show()
|
||||
},
|
||||
handleEmpty(){
|
||||
this.handleOK('')
|
||||
},
|
||||
handleOK(rows, idstr) {
|
||||
let value = ''
|
||||
if (!rows && rows.length <= 0) {
|
||||
this.departNames = ''
|
||||
this.departIds = ''
|
||||
} else {
|
||||
value = rows.map(row => row[this.customReturnField]).join(',')
|
||||
this.departNames = rows.map(row => row['departName']).join(',')
|
||||
this.departIds = idstr
|
||||
}
|
||||
this.handleChangeCommon(this.departIds)
|
||||
},
|
||||
initComp(departNames){
|
||||
this.departNames = departNames
|
||||
},
|
||||
handleChange(value) {
|
||||
this.handleChangeCommon(value)
|
||||
}
|
||||
},
|
||||
enhanced: {
|
||||
switches: {
|
||||
visible: true
|
||||
},
|
||||
translate: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .jvxe-select-input .ant-input{
|
||||
border: none !important;
|
||||
}
|
||||
</style>
|
||||
@ -34,7 +34,7 @@
|
||||
return this.rowIndex === 0
|
||||
},
|
||||
disabledMoveDown() {
|
||||
return this.rowIndex === (this.rows.length - 1)
|
||||
return this.rowIndex === (this.fullDataLength - 1)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@ -116,7 +116,9 @@
|
||||
// 【组件增强】注释详见:JVxeCellMixins.js
|
||||
enhanced: {
|
||||
aopEvents: {
|
||||
editActived: event => dispatchEvent(event, 'ant-select'),
|
||||
editActived(event) {
|
||||
dispatchEvent.call(this, event, 'ant-select')
|
||||
},
|
||||
},
|
||||
translate: {enabled: true},
|
||||
getValue(value) {
|
||||
|
||||
@ -23,7 +23,9 @@
|
||||
autofocus: '.ant-input',
|
||||
},
|
||||
aopEvents: {
|
||||
editActived: event => dispatchEvent(event, 'anticon-fullscreen'),
|
||||
editActived(event) {
|
||||
dispatchEvent.call(this, event, 'anticon-fullscreen')
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-input
|
||||
v-show="!userIds"
|
||||
@click="openSelect"
|
||||
placeholder="请选择用户"
|
||||
v-model="userNames"
|
||||
readOnly
|
||||
class="jvxe-select-input"
|
||||
:disabled="componentDisabled">
|
||||
<a-icon slot="prefix" type="user" title="用户选择控件"/>
|
||||
</a-input>
|
||||
<j-select-user-by-dep-modal
|
||||
ref="selectModal"
|
||||
:modal-width="modalWidth"
|
||||
:multi="multi"
|
||||
:user-ids="userIds"
|
||||
@ok="selectOK"
|
||||
@initComp="initComp"/>
|
||||
<span style="display: inline-block;height:100%;padding-left:14px" v-if="userIds" >
|
||||
<span @click="openSelect" style="display: inline-block;vertical-align: middle">{{ userNames }}</span>
|
||||
<a-icon style="margin-left:5px;vertical-align: middle" type="close-circle" @click="handleEmpty" title="清空"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- <j-select-user-by-dep
|
||||
v-bind="custProps"
|
||||
@change="handleChange"
|
||||
:trigger-change="true">
|
||||
</j-select-user-by-dep>-->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JVxeCellMixins, { dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
|
||||
import JSelectUserByDepModal from '@/components/jeecgbiz/modal/JSelectUserByDepModal'
|
||||
|
||||
export default {
|
||||
name: 'JVxeUserSelectCell',
|
||||
mixins: [JVxeCellMixins],
|
||||
components: { JSelectUserByDepModal },
|
||||
data() {
|
||||
return {
|
||||
userIds:'',
|
||||
userNames:'',
|
||||
innerUserValue: '',
|
||||
selectedOptions: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
custProps() {
|
||||
const {userIds, originColumn: col, caseId, cellProps} = this
|
||||
return {
|
||||
...cellProps,
|
||||
value: userIds,
|
||||
field: col.field || col.key,
|
||||
groupId: caseId,
|
||||
class: 'jvxe-select'
|
||||
}
|
||||
},
|
||||
componentDisabled(){
|
||||
console.log('333',this.cellProps)
|
||||
if(this.cellProps.disabled==true){
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
modalWidth(){
|
||||
if(this.cellProps.modalWidth){
|
||||
return this.cellProps.modalWidth
|
||||
}else{
|
||||
return 1250
|
||||
}
|
||||
},
|
||||
multi(){
|
||||
if(this.cellProps.multi==false){
|
||||
return false
|
||||
}else{
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
innerValue: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (val == null || val === '') {
|
||||
this.userIds = ''
|
||||
} else {
|
||||
this.userIds = val
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openSelect() {
|
||||
this.$refs.selectModal.showModal()
|
||||
},
|
||||
selectOK(rows, idstr) {
|
||||
console.log("当前选中用户", rows)
|
||||
console.log("当前选中用户ID", idstr)
|
||||
if (!rows) {
|
||||
this.userNames = ''
|
||||
this.userIds = ''
|
||||
} else {
|
||||
let temp = ''
|
||||
for (let item of rows) {
|
||||
temp += ',' + item.realname
|
||||
}
|
||||
this.userNames = temp.substring(1)
|
||||
this.userIds = idstr
|
||||
}
|
||||
this.handleChangeCommon(this.userIds)
|
||||
},
|
||||
handleEmpty(){
|
||||
this.selectOK('')
|
||||
},
|
||||
initComp(userNames) {
|
||||
this.userNames = userNames
|
||||
},
|
||||
},
|
||||
enhanced: {
|
||||
switches: {
|
||||
visible: true
|
||||
},
|
||||
translate: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .jvxe-select-input .ant-input {
|
||||
border: none !important;
|
||||
}
|
||||
</style>
|
||||
@ -1,3 +1,4 @@
|
||||
import * as jvxeTypes from './jvxeTypes'
|
||||
import { installCell, mapCell } from './install'
|
||||
import JVxeTable from './components/JVxeTable'
|
||||
|
||||
@ -12,46 +13,13 @@ import { TagsInputCell, TagsSpanCell } from './components/cells/JVxeTagsCell'
|
||||
import JVxeProgressCell from './components/cells/JVxeProgressCell'
|
||||
import JVxeTextareaCell from './components/cells/JVxeTextareaCell'
|
||||
import JVxeDragSortCell from './components/cells/JVxeDragSortCell'
|
||||
import JVxeDepartSelectCell from './components/cells/JVxeDepartSelectCell'
|
||||
import JVxeUserSelectCell from './components/cells/JVxeUserSelectCell'
|
||||
|
||||
//update--begin--autor:lvdandan-----date:20201216------for:JVxeTable--JVXETypes 【online】代码结构调整,便于online打包
|
||||
// 组件类型
|
||||
export const JVXETypes = {
|
||||
// 为了防止和 vxe 内置的类型冲突,所以加上一个前缀
|
||||
// 前缀是自动加的,代码中直接用就行(JVXETypes.input)
|
||||
_prefix: 'j-',
|
||||
|
||||
// 行号列
|
||||
rowNumber: 'row-number',
|
||||
// 选择列
|
||||
rowCheckbox: 'row-checkbox',
|
||||
// 单选列
|
||||
rowRadio: 'row-radio',
|
||||
// 展开列
|
||||
rowExpand: 'row-expand',
|
||||
// 上下排序
|
||||
rowDragSort: 'row-drag-sort',
|
||||
|
||||
input: 'input',
|
||||
inputNumber: 'inputNumber',
|
||||
textarea: 'textarea',
|
||||
select: 'select',
|
||||
date: 'date',
|
||||
datetime: 'datetime',
|
||||
checkbox: 'checkbox',
|
||||
upload: 'upload',
|
||||
// 下拉搜索
|
||||
selectSearch: 'select-search',
|
||||
// 下拉多选
|
||||
selectMultiple: 'select-multiple',
|
||||
// 进度条
|
||||
progress: 'progress',
|
||||
|
||||
// 拖轮Tags(暂无用)
|
||||
tags: 'tags',
|
||||
|
||||
slot: 'slot',
|
||||
normal: 'normal',
|
||||
hidden: 'hidden',
|
||||
}
|
||||
export const JVXETypes = jvxeTypes.JVXETypes
|
||||
//update--end--autor:lvdandan-----date:20201216------for:JVxeTable--JVXETypes 【online】代码结构调整,便于online打包
|
||||
|
||||
// 注册自定义组件
|
||||
export const AllCells = {
|
||||
@ -72,6 +40,8 @@ export const AllCells = {
|
||||
|
||||
...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell),
|
||||
...mapCell(JVXETypes.slot, JVxeSlotCell),
|
||||
...mapCell(JVXETypes.departSelect, JVxeDepartSelectCell),
|
||||
...mapCell(JVXETypes.userSelect, JVxeUserSelectCell)
|
||||
|
||||
/* hidden 是特殊的组件,不在这里注册 */
|
||||
}
|
||||
|
||||
@ -62,8 +62,8 @@ VXETable.interceptor.add('event.clearActived', function (params, event, target)
|
||||
if (className.includes('j-input-pop')) {
|
||||
return false
|
||||
}
|
||||
// 点击的标签是JPopup的弹出层
|
||||
if (className.includes('j-popup-modal')) {
|
||||
// 点击的标签是JPopup的弹出层、部门选择、用户选择
|
||||
if (className.includes('j-popup-modal') || className.includes('j-depart-select-modal') || className.includes('j-user-select-modal')) {
|
||||
return false
|
||||
}
|
||||
// 执行增强
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
// 组件类型
|
||||
export default JVXETypes
|
||||
export const JVXETypes = {
|
||||
// 为了防止和 vxe 内置的类型冲突,所以加上一个前缀
|
||||
// 前缀是自动加的,代码中直接用就行(JVXETypes.input)
|
||||
_prefix: 'j-',
|
||||
|
||||
// 行号列
|
||||
rowNumber: 'row-number',
|
||||
// 选择列
|
||||
rowCheckbox: 'row-checkbox',
|
||||
// 单选列
|
||||
rowRadio: 'row-radio',
|
||||
// 展开列
|
||||
rowExpand: 'row-expand',
|
||||
// 上下排序
|
||||
rowDragSort: 'row-drag-sort',
|
||||
|
||||
input: 'input',
|
||||
inputNumber: 'inputNumber',
|
||||
textarea: 'textarea',
|
||||
select: 'select',
|
||||
date: 'date',
|
||||
datetime: 'datetime',
|
||||
checkbox: 'checkbox',
|
||||
upload: 'upload',
|
||||
// 下拉搜索
|
||||
selectSearch: 'select-search',
|
||||
// 下拉多选
|
||||
selectMultiple: 'select-multiple',
|
||||
// 进度条
|
||||
progress: 'progress',
|
||||
//部门选择
|
||||
departSelect: 'sel_depart',
|
||||
//用户选择
|
||||
userSelect: 'sel_user',
|
||||
|
||||
// 拖轮Tags(暂无用)
|
||||
tags: 'tags',
|
||||
|
||||
slot: 'slot',
|
||||
normal: 'normal',
|
||||
hidden: 'hidden',
|
||||
}
|
||||
@ -36,6 +36,9 @@ export default {
|
||||
rows() {
|
||||
return this.params.data
|
||||
},
|
||||
fullDataLength() {
|
||||
return this.params.$table.tableFullData.length
|
||||
},
|
||||
rowIndex() {
|
||||
return this.params.rowIndex
|
||||
},
|
||||
@ -149,6 +152,8 @@ export default {
|
||||
packageEvent(name, event = {}) {
|
||||
event.row = this.row
|
||||
event.column = this.column
|
||||
//online增强参数兼容
|
||||
event.column['key'] = this.column['property']
|
||||
event.cellTarget = this
|
||||
if (!event.type) {
|
||||
event.type = name
|
||||
@ -289,6 +294,10 @@ export function vModel(value, row, property) {
|
||||
|
||||
/** 模拟触发事件 */
|
||||
export function dispatchEvent({cell, $event}, className, handler) {
|
||||
// alwaysEdit 下不模拟触发事件,否者会导致触发两次
|
||||
if (this && this.alwaysEdit) {
|
||||
return
|
||||
}
|
||||
window.setTimeout(() => {
|
||||
let element = cell.getElementsByClassName(className)
|
||||
if (element && element.length > 0) {
|
||||
@ -296,7 +305,9 @@ export function dispatchEvent({cell, $event}, className, handler) {
|
||||
handler(element[0])
|
||||
} else {
|
||||
// 模拟触发点击事件
|
||||
element[0].dispatchEvent($event)
|
||||
if($event){
|
||||
element[0].dispatchEvent($event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 10)
|
||||
|
||||
@ -141,6 +141,33 @@ export async function validateFormAndTables(form, cases, autoJumpTab) {
|
||||
return dataMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 一次性验证主表单和所有的次表单
|
||||
* @param form 主表单 form 对象
|
||||
* @param cases 接收一个数组,每项都是一个JVxeTable实例
|
||||
* @param autoJumpTab
|
||||
* @returns {Promise<any>}
|
||||
* @author sunjianlei
|
||||
*/
|
||||
export async function validateFormModelAndTables(form,formData, cases, autoJumpTab) {
|
||||
if (!(form && typeof form.validate === 'function')) {
|
||||
throw `form 参数需要的是一个form对象,而传入的却是${typeof form}`
|
||||
}
|
||||
let dataMap = {}
|
||||
let values = await new Promise((resolve, reject) => {
|
||||
// 验证主表表单
|
||||
form.validate((valid,obj) => {
|
||||
valid ?resolve(formData): reject({error: VALIDATE_FAILED, originError: valid})
|
||||
})
|
||||
})
|
||||
Object.assign(dataMap, {formValue: values})
|
||||
// 验证所有子表的表单
|
||||
let subData = await validateTables(cases, autoJumpTab)
|
||||
// 合并最终数据
|
||||
dataMap = Object.assign(dataMap, {tablesValue: subData})
|
||||
return dataMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证并获取一个或多个表格的所有值
|
||||
*
|
||||
|
||||
@ -1,246 +0,0 @@
|
||||
<template>
|
||||
<div class="tinymce-containerty" :style="{width:containerWidth}">
|
||||
<textarea :id="tinymceId" class="tinymce-textarea" @change="ada"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* docs:
|
||||
* https://panjiachen.github.io/vue-element-admin-site/feature/component/rich-editor.html#tinymce
|
||||
*/
|
||||
import load from './load'
|
||||
//const toolbar = ['searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample', 'hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen']
|
||||
//const plugins = ['advlist anchor autolink autosave code codesample colorpicker colorpicker contextmenu directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textcolor textpattern visualblocks visualchars wordcount']
|
||||
// why use this cdn, detail see https://github.com/PanJiaChen/tinymce-all-in-one
|
||||
const tinymceCDN = 'https://cdn.jsdelivr.net/npm/tinymce-all-in-one@4.9.3/tinymce.min.js'
|
||||
|
||||
export default {
|
||||
name: 'JEditorDyn',
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
toolbar: {
|
||||
type: [String, Array],
|
||||
required: false,
|
||||
default: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link unlink image media table | removeformat | fullscreen',
|
||||
},
|
||||
menubar: {
|
||||
type: String,
|
||||
default: 'file edit insert view format table'
|
||||
},
|
||||
height: {
|
||||
type: [Number, String],
|
||||
required: false,
|
||||
default: 360
|
||||
},
|
||||
width: {
|
||||
type: [Number, String],
|
||||
required: false,
|
||||
default: 'auto'
|
||||
},
|
||||
plugins: {
|
||||
type: [String, Array],
|
||||
default: 'lists image link media table textcolor wordcount contextmenu fullscreen'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasChange: false,
|
||||
hasInit: false,
|
||||
tinymceId: this.id,
|
||||
fullscreen: false,
|
||||
languageTypeList: {
|
||||
'en': 'en',
|
||||
'zh': 'zh_CN',
|
||||
'es': 'es_MX',
|
||||
'ja': 'ja'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerWidth() {
|
||||
const width = this.width
|
||||
if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
|
||||
return `${width}px`
|
||||
}
|
||||
return width
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (!this.hasChange && this.hasInit) {
|
||||
this.$nextTick(() =>
|
||||
window.tinymce.get(this.tinymceId).setContent(val || ''))
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
activated() {
|
||||
if (window.tinymce) {
|
||||
this.initTinymce()
|
||||
}
|
||||
},
|
||||
deactivated() {
|
||||
this.destroyTinymce()
|
||||
},
|
||||
destroyed() {
|
||||
this.destroyTinymce()
|
||||
},
|
||||
methods: {
|
||||
ada() {
|
||||
console.log('change')
|
||||
},
|
||||
init() {
|
||||
// dynamic load tinymce from cdn
|
||||
load(tinymceCDN, (err) => {
|
||||
if (err) {
|
||||
this.$message.error(err.message)
|
||||
return
|
||||
}
|
||||
this.initTinymce()
|
||||
})
|
||||
},
|
||||
initTinymce() {
|
||||
const _this = this
|
||||
window.tinymce.init({
|
||||
selector: `#${this.tinymceId}`,
|
||||
language: this.languageTypeList['zh'],
|
||||
height: this.height,
|
||||
body_class: 'panel-body ',
|
||||
object_resizing: false,
|
||||
toolbar: this.toolbar,
|
||||
menubar: false,
|
||||
plugins: this.plugins,
|
||||
end_container_on_empty_block: true,
|
||||
powerpaste_word_import: 'clean',
|
||||
code_dialog_height: 450,
|
||||
code_dialog_width: 1000,
|
||||
advlist_bullet_styles: 'square',
|
||||
advlist_number_styles: 'default',
|
||||
imagetools_cors_hosts: ['www.tinymce.com', 'codepen.io'],
|
||||
default_link_target: '_blank',
|
||||
link_title: false,
|
||||
nonbreaking_force_tab: true, // inserting nonbreaking space need Nonbreaking Space Plugin
|
||||
init_instance_callback: editor => {
|
||||
if (_this.value) {
|
||||
editor.setContent(_this.value)
|
||||
}
|
||||
_this.hasInit = true
|
||||
editor.on('NodeChange Change KeyUp SetContent', () => {
|
||||
this.hasChange = true
|
||||
this.$emit('input', editor.getContent())
|
||||
})
|
||||
},
|
||||
setup(editor) {
|
||||
editor.on('FullscreenStateChanged', (e) => {
|
||||
_this.fullscreen = e.state
|
||||
})
|
||||
},
|
||||
// it will try to keep these URLs intact
|
||||
// https://www.tiny.cloud/docs-3x/reference/configuration/Configuration3x@convert_urls/
|
||||
// https://stackoverflow.com/questions/5196205/disable-tinymce-absolute-to-relative-url-conversions
|
||||
convert_urls: false
|
||||
// 整合七牛上传
|
||||
// images_dataimg_filter(img) {
|
||||
// setTimeout(() => {
|
||||
// const $image = $(img);
|
||||
// $image.removeAttr('width');
|
||||
// $image.removeAttr('height');
|
||||
// if ($image[0].height && $image[0].width) {
|
||||
// $image.attr('data-wscntype', 'image');
|
||||
// $image.attr('data-wscnh', $image[0].height);
|
||||
// $image.attr('data-wscnw', $image[0].width);
|
||||
// $image.addClass('wscnph');
|
||||
// }
|
||||
// }, 0);
|
||||
// return img
|
||||
// },
|
||||
// images_upload_handler(blobInfo, success, failure, progress) {
|
||||
// progress(0);
|
||||
// const token = _this.$store.getters.token;
|
||||
// getToken(token).then(response => {
|
||||
// const url = response.data.qiniu_url;
|
||||
// const formData = new FormData();
|
||||
// formData.append('token', response.data.qiniu_token);
|
||||
// formData.append('key', response.data.qiniu_key);
|
||||
// formData.append('file', blobInfo.blob(), url);
|
||||
// upload(formData).then(() => {
|
||||
// success(url);
|
||||
// progress(100);
|
||||
// })
|
||||
// }).catch(err => {
|
||||
// failure('err')
|
||||
// console.log(err);
|
||||
// });
|
||||
// },
|
||||
})
|
||||
},
|
||||
destroyTinymce() {
|
||||
const tinymce = window.tinymce.get(this.tinymceId)
|
||||
if (this.fullscreen) {
|
||||
tinymce.execCommand('mceFullScreen')
|
||||
}
|
||||
|
||||
if (tinymce) {
|
||||
tinymce.destroy()
|
||||
}
|
||||
},
|
||||
setContent(value) {
|
||||
window.tinymce.get(this.tinymceId).setContent(value)
|
||||
},
|
||||
getContent() {
|
||||
window.tinymce.get(this.tinymceId).getContent()
|
||||
},
|
||||
imageSuccessCBK(arr) {
|
||||
arr.forEach(v => window.tinymce.get(this.tinymceId).insertContent(`<img class="wscnph" src="${v.url}" >`))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tinymce-containerty {
|
||||
position: relative;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.tinymce-containerty {
|
||||
::v-deep {
|
||||
.mce-fullscreen {
|
||||
z-index: 10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tinymce-textarea {
|
||||
visibility: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.editor-custom-btn-container {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
/*z-index: 2005;*/
|
||||
}
|
||||
|
||||
.fullscreen .editor-custom-btn-container {
|
||||
z-index: 10000;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.editor-upload-btn {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@ -1,142 +0,0 @@
|
||||
<template>
|
||||
<div class="j-markdown-editor" :id="dynamicId"/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import load from './load'
|
||||
import { md_js, md_zh_cn_js } from './Resource'
|
||||
import defaultOptions from '@/components/jeecg/JMarkdownEditor/default-options.js'
|
||||
|
||||
export default {
|
||||
name: 'JMdEditorDyn',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
required: false,
|
||||
default() {
|
||||
return 'markdown-editor-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
}
|
||||
},
|
||||
options: {
|
||||
type: Object,
|
||||
default() {
|
||||
return defaultOptions
|
||||
}
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'markdown'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '300px'
|
||||
},
|
||||
language: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'zh-CN'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
dynamicId: this.id
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editorOptions() {
|
||||
const options = Object.assign({}, defaultOptions, this.options)
|
||||
options.initialEditType = this.mode
|
||||
options.height = this.height
|
||||
options.language = this.language
|
||||
return options
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newValue, preValue) {
|
||||
if (newValue !== preValue && newValue !== this.editor.getMarkdown()) {
|
||||
this.editor.setMarkdown(newValue)
|
||||
}
|
||||
},
|
||||
language(val) {
|
||||
this.destroyEditor()
|
||||
this.initEditor()
|
||||
},
|
||||
height(newValue) {
|
||||
this.editor.height(newValue)
|
||||
},
|
||||
mode(newValue) {
|
||||
this.editor.changeMode(newValue)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
destroyed() {
|
||||
this.destroyEditor()
|
||||
},
|
||||
methods: {
|
||||
init(){
|
||||
|
||||
this.initEditor()
|
||||
/* load(md_js,'',()=>{
|
||||
load(md_zh_cn_js,'',()=>{
|
||||
|
||||
})
|
||||
})*/
|
||||
},
|
||||
initEditor() {
|
||||
const Editor = toastui.Editor
|
||||
this.editor = new Editor({
|
||||
el: document.getElementById(this.dynamicId),
|
||||
...this.editorOptions
|
||||
})
|
||||
if (this.value) {
|
||||
this.editor.setMarkdown(this.value)
|
||||
}
|
||||
this.editor.on('change', () => {
|
||||
this.$emit('change', this.editor.getMarkdown())
|
||||
})
|
||||
},
|
||||
destroyEditor() {
|
||||
if (!this.editor) return
|
||||
this.editor.off('change')
|
||||
this.editor.remove()
|
||||
},
|
||||
setMarkdown(value) {
|
||||
this.editor.setMarkdown(value)
|
||||
},
|
||||
getMarkdown() {
|
||||
return this.editor.getMarkdown()
|
||||
},
|
||||
setHtml(value) {
|
||||
this.editor.setHtml(value)
|
||||
},
|
||||
getHtml() {
|
||||
return this.editor.getHtml()
|
||||
}
|
||||
},
|
||||
model: {
|
||||
prop: 'value',
|
||||
event: 'change'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
||||
.j-markdown-editor {
|
||||
/deep/ .tui-editor-defaultUI {
|
||||
.te-mode-switch,
|
||||
.tui-scrollsync
|
||||
{
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,325 +0,0 @@
|
||||
<template>
|
||||
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||
<textarea :id="dynamicId" />
|
||||
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import load from './load'
|
||||
import '@/assets/less/codemirror_idea.css'
|
||||
import './cm_sql_hint.js'
|
||||
import { sql_keyword } from './Resource'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'JSqlCodeEditorDyn',
|
||||
props:{
|
||||
id: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 显示行号
|
||||
lineNumbers: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
zIndex: {
|
||||
type: [Number, String],
|
||||
default: 999
|
||||
},
|
||||
autoHeight: {
|
||||
type: [String, Boolean],
|
||||
default: true
|
||||
},
|
||||
// 不自适应高度的情况下生效的固定高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '240px'
|
||||
},
|
||||
autoHeight: {
|
||||
type: [String, Boolean],
|
||||
default: true
|
||||
},
|
||||
// 是否显示全屏按钮
|
||||
fullScreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
autoHint:{
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
dynamicId: this.id,
|
||||
coder: '',
|
||||
hasCode: false,
|
||||
code: '',
|
||||
// code 编辑器 是否全屏
|
||||
fullCoder: false,
|
||||
iconType: 'fullscreen',
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
placeholderShow() {
|
||||
if (this.placeholder == null) {
|
||||
return `请在此输入javascript代码`
|
||||
} else {
|
||||
return this.placeholder
|
||||
}
|
||||
},
|
||||
nullTipStyle(){
|
||||
if (this.lineNumbers) {
|
||||
return { left: '36px' }
|
||||
} else {
|
||||
return { left: '12px' }
|
||||
}
|
||||
},
|
||||
isAutoHeight() {
|
||||
let {autoHeight} = this
|
||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||
autoHeight = !(isIE() || isIE11())
|
||||
} else {
|
||||
autoHeight = true
|
||||
}
|
||||
return autoHeight
|
||||
},
|
||||
fullScreenParentProps() {
|
||||
let props = {
|
||||
class: {
|
||||
'full-screen-parent': true,
|
||||
'full-screen': this.fullCoder,
|
||||
'auto-height': this.isAutoHeight
|
||||
},
|
||||
style: {}
|
||||
}
|
||||
if (this.fullCoder) {
|
||||
props.style['z-index'] = this.zIndex
|
||||
}
|
||||
if (!this.isAutoHeight) {
|
||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||
}
|
||||
return props
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fullCoder:{
|
||||
handler(value) {
|
||||
if(value){
|
||||
this.iconType="fullscreen-exit"
|
||||
}else{
|
||||
this.iconType="fullscreen"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
methods:{
|
||||
init(){
|
||||
this.main();
|
||||
},
|
||||
main(){
|
||||
let obj = document.getElementById(this.dynamicId);
|
||||
const that = this;
|
||||
let editor = CodeMirror.fromTextArea(obj,{
|
||||
theme:'idea',
|
||||
lineNumbers: this.lineNumbers,
|
||||
lineWrapping: true,
|
||||
mode: "sql",
|
||||
indentUnit: 1,
|
||||
indentWithTabs: true,
|
||||
styleActiveLine: true,
|
||||
/* styleSelectedText: false, */
|
||||
extraKeys: {
|
||||
"F11": function(cm) {
|
||||
that.fullCoder = !that.fullCoder
|
||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||
},
|
||||
"Esc": function(cm) {
|
||||
that.fullCoder = false
|
||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||
},
|
||||
"Alt-/": function(cm) {
|
||||
cm.showHint();
|
||||
},
|
||||
"Tab": (cm) => {
|
||||
if (cm.somethingSelected()) {
|
||||
cm.indentSelection('add');
|
||||
} else {
|
||||
//cm.indentLine(cm.getCursor().line, "add");
|
||||
//走两格 第三格输入
|
||||
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
||||
}
|
||||
},
|
||||
"Shift-Tab": (cm) => {
|
||||
if (cm.somethingSelected()) {
|
||||
cm.indentSelection('subtract');
|
||||
} else {
|
||||
// cm.indentLine(cm.getCursor().line, "subtract");
|
||||
const cursor = cm.getCursor();
|
||||
// 光标回退 indexUnit 字符
|
||||
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
||||
}
|
||||
return ;
|
||||
}
|
||||
}
|
||||
})
|
||||
this.coder = editor
|
||||
this.addEvent();
|
||||
this.setCoderValue();
|
||||
this.addSystemHint();
|
||||
},
|
||||
setCoderValue(){
|
||||
if(this.value||this.code){
|
||||
this.hasCode=true
|
||||
this.setCodeContent(this.value || this.code)
|
||||
}else{
|
||||
this.coder.setValue('')
|
||||
this.hasCode=false
|
||||
}
|
||||
},
|
||||
getCodeContent(){
|
||||
return this.code
|
||||
},
|
||||
setCodeContent(val){
|
||||
setTimeout(()=>{
|
||||
if(!val){
|
||||
this.coder.setValue('')
|
||||
}else{
|
||||
this.coder.setValue(val)
|
||||
}
|
||||
},300)
|
||||
},
|
||||
addSystemHint(){
|
||||
this.coder.setOption('hintOptions', {
|
||||
completeSingle: false,
|
||||
tables: sql_keyword
|
||||
});
|
||||
},
|
||||
addEvent(){
|
||||
if(this.autoHint){
|
||||
this.coder.on('cursorActivity', ()=>{
|
||||
this.coder.showHint();
|
||||
});
|
||||
}
|
||||
this.coder.on('change', (coder) => {
|
||||
this.code = coder.getValue()
|
||||
if(this.code){
|
||||
this.hasCode=true
|
||||
}else{
|
||||
this.hasCode=false
|
||||
}
|
||||
if (this.$emit) {
|
||||
this.$emit('input', this.code)
|
||||
}
|
||||
});
|
||||
this.coder.on('focus', () => {
|
||||
this.hasCode=true
|
||||
});
|
||||
this.coder.on('blur', () => {
|
||||
if(this.code){
|
||||
this.hasCode=true
|
||||
}else{
|
||||
this.hasCode=false
|
||||
}
|
||||
});
|
||||
},
|
||||
loadResource(src,type){
|
||||
return new Promise((resolve,reject)=>{
|
||||
load(src,type,(msg)=>{
|
||||
if(!msg){
|
||||
resolve();
|
||||
}else{
|
||||
reject(msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
nullTipClick(){
|
||||
this.coder.focus()
|
||||
},
|
||||
fullToggle(){
|
||||
this.fullCoder = !this.fullCoder
|
||||
this.coder.setOption("fullScreen", this.fullCoder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="less" >
|
||||
.jeecg-editor-ty{
|
||||
position: relative;
|
||||
|
||||
.full-screen-icon {
|
||||
opacity: 0;
|
||||
color: black;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 2px;
|
||||
z-index: 9;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
&:hover {
|
||||
.full-screen-icon {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.null-tip{
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 36px;
|
||||
z-index: 10;
|
||||
font-size:16px;
|
||||
color: #acaaaac9;
|
||||
line-height: initial;
|
||||
}
|
||||
.null-tip-hidden{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.jeecg-editor-max{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
|
||||
.CodeMirror{
|
||||
position: inherit !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.full-screen-icon{
|
||||
z-index:9999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,319 +0,0 @@
|
||||
<template>
|
||||
<div class="jeecg-editor-ty" :class="fullCoder?'jeecg-editor-max':'jeecg-editor-min'">
|
||||
<a-icon v-if="fullScreen" class="full-screen-icon" :type="iconType" @click="()=>fullCoder=!fullCoder"/>
|
||||
<textarea :id="dynamicId" />
|
||||
<span @click="nullTipClick" class="null-tip" :class="{'null-tip-hidden': hasCode}" :style="nullTipStyle">{{ placeholderShow }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import '@/assets/less/codemirror_idea.css'
|
||||
import './cm_hint.js'
|
||||
|
||||
export default {
|
||||
name: 'JsCodeEditorDyn',
|
||||
props:{
|
||||
id: {
|
||||
type: String,
|
||||
default: function() {
|
||||
return 'vue-editor-' + new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
||||
}
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 显示行号
|
||||
lineNumbers: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
zIndex: {
|
||||
type: [Number, String],
|
||||
default: 999
|
||||
},
|
||||
autoHeight: {
|
||||
type: [String, Boolean],
|
||||
default: true
|
||||
},
|
||||
// 不自适应高度的情况下生效的固定高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '240px'
|
||||
},
|
||||
autoHeight: {
|
||||
type: [String, Boolean],
|
||||
default: true
|
||||
},
|
||||
// 是否显示全屏按钮
|
||||
fullScreen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
dynamicId: this.id,
|
||||
coder: '',
|
||||
hasCode: false,
|
||||
code: '',
|
||||
// code 编辑器 是否全屏
|
||||
fullCoder: false,
|
||||
iconType: 'fullscreen',
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
placeholderShow() {
|
||||
if (this.placeholder == null) {
|
||||
return `请在此输入javascript代码`
|
||||
} else {
|
||||
return this.placeholder
|
||||
}
|
||||
},
|
||||
nullTipStyle(){
|
||||
if (this.lineNumbers) {
|
||||
return { left: '36px' }
|
||||
} else {
|
||||
return { left: '12px' }
|
||||
}
|
||||
},
|
||||
isAutoHeight() {
|
||||
let {autoHeight} = this
|
||||
if (typeof autoHeight === 'string' && autoHeight.toLowerCase().trim() === '!ie') {
|
||||
autoHeight = !(isIE() || isIE11())
|
||||
} else {
|
||||
autoHeight = true
|
||||
}
|
||||
return autoHeight
|
||||
},
|
||||
fullScreenParentProps() {
|
||||
let props = {
|
||||
class: {
|
||||
'full-screen-parent': true,
|
||||
'full-screen': this.fullCoder,
|
||||
'auto-height': this.isAutoHeight
|
||||
},
|
||||
style: {}
|
||||
}
|
||||
if (this.fullCoder) {
|
||||
props.style['z-index'] = this.zIndex
|
||||
}
|
||||
if (!this.isAutoHeight) {
|
||||
props.style['height'] = (typeof this.height === 'number' ? this.height + 'px' : this.height)
|
||||
}
|
||||
return props
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
fullCoder:{
|
||||
handler(value) {
|
||||
if(value){
|
||||
this.iconType="fullscreen-exit"
|
||||
}else{
|
||||
this.iconType="fullscreen"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
methods:{
|
||||
init(){
|
||||
this.main();
|
||||
},
|
||||
main(){
|
||||
let obj = document.getElementById(this.dynamicId);
|
||||
const that = this;
|
||||
let editor = CodeMirror.fromTextArea(obj,{
|
||||
theme:'idea',
|
||||
lineNumbers: this.lineNumbers,
|
||||
lineWrapping: true,
|
||||
mode: "javascript",
|
||||
indentUnit: 1,
|
||||
indentWithTabs: true,
|
||||
styleActiveLine: true,
|
||||
/* styleSelectedText: false, */
|
||||
extraKeys: {
|
||||
"F11": function(cm) {
|
||||
that.fullCoder = !that.fullCoder
|
||||
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
|
||||
},
|
||||
"Esc": function(cm) {
|
||||
that.fullCoder = false
|
||||
if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
|
||||
},
|
||||
"Alt-/": function(cm) {
|
||||
let a = cm.getValue()+""
|
||||
console.log('a',a)
|
||||
cm.showHint();
|
||||
},
|
||||
"Tab": (cm) => {
|
||||
if (cm.somethingSelected()) {
|
||||
cm.indentSelection('add');
|
||||
} else {
|
||||
//cm.indentLine(cm.getCursor().line, "add");
|
||||
//走两格 第三格输入
|
||||
cm.replaceSelection(Array(3).join(" "), "end", "+input");
|
||||
}
|
||||
},
|
||||
"Shift-Tab": (cm) => {
|
||||
if (cm.somethingSelected()) {
|
||||
cm.indentSelection('subtract');
|
||||
} else {
|
||||
// cm.indentLine(cm.getCursor().line, "subtract");
|
||||
const cursor = cm.getCursor();
|
||||
// 光标回退 indexUnit 字符
|
||||
cm.setCursor({line: cursor.line, ch: cursor.ch - 4});
|
||||
}
|
||||
return ;
|
||||
}
|
||||
}
|
||||
})
|
||||
this.coder = editor
|
||||
this.addEvent();
|
||||
this.setCoderValue();
|
||||
},
|
||||
setCoderValue(){
|
||||
if(this.value||this.code){
|
||||
this.hasCode=true
|
||||
this.setCodeContent(this.value || this.code)
|
||||
}else{
|
||||
this.coder.setValue('')
|
||||
this.hasCode=false
|
||||
}
|
||||
},
|
||||
getCodeContent(){
|
||||
return this.code
|
||||
},
|
||||
setCodeContent(val){
|
||||
setTimeout(()=>{
|
||||
if(!val){
|
||||
this.coder.setValue('')
|
||||
}else{
|
||||
this.coder.setValue(val)
|
||||
}
|
||||
},300)
|
||||
},
|
||||
addEvent(){
|
||||
const that = this;
|
||||
this.coder.on('cursorActivity',function(wl) {
|
||||
let arr = wl.state.activeLines
|
||||
if(arr && arr.length>0){
|
||||
let text = arr[0].text
|
||||
if(text.lastIndexOf('that.')>=0){
|
||||
that.coder.showHint();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.coder.on('change', (coder) => {
|
||||
this.code = coder.getValue()
|
||||
if(this.code){
|
||||
this.hasCode=true
|
||||
}else{
|
||||
this.hasCode=false
|
||||
}
|
||||
if (this.$emit) {
|
||||
this.$emit('input', this.code)
|
||||
}
|
||||
});
|
||||
this.coder.on('focus', () => {
|
||||
this.hasCode=true
|
||||
});
|
||||
this.coder.on('blur', () => {
|
||||
if(this.code){
|
||||
this.hasCode=true
|
||||
}else{
|
||||
this.hasCode=false
|
||||
}
|
||||
});
|
||||
},
|
||||
loadResource(src,type){
|
||||
return new Promise((resolve,reject)=>{
|
||||
load(src,type,(msg)=>{
|
||||
if(!msg){
|
||||
resolve();
|
||||
}else{
|
||||
reject(msg)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
nullTipClick(){
|
||||
this.coder.focus()
|
||||
},
|
||||
fullToggle(){
|
||||
this.fullCoder = !this.fullCoder
|
||||
this.coder.setOption("fullScreen", this.fullCoder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
<style lang="less" >
|
||||
.jeecg-editor-ty{
|
||||
position: relative;
|
||||
|
||||
.full-screen-icon {
|
||||
opacity: 0;
|
||||
color: black;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 24px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 2px;
|
||||
z-index: 9;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
&:hover {
|
||||
.full-screen-icon {
|
||||
opacity: 1;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.88);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.null-tip{
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 36px;
|
||||
z-index: 10;
|
||||
font-size:16px;
|
||||
color: #acaaaac9;
|
||||
line-height: initial;
|
||||
}
|
||||
.null-tip-hidden{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.jeecg-editor-max{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
height: 100%;
|
||||
width: 100% !important;
|
||||
|
||||
.CodeMirror{
|
||||
position: inherit !important;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.full-screen-icon{
|
||||
z-index:9999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,24 +0,0 @@
|
||||
|
||||
/**js编辑器关键词用于提示*/
|
||||
const js_keyword = [
|
||||
'that',
|
||||
'getAction','postAction','deleteAction',
|
||||
'beforeAdd','beforeEdit','beforeDelete','mounted','created','show'
|
||||
]
|
||||
|
||||
/**js编辑器 方法名用于提示*/
|
||||
const js_method = [
|
||||
'.getSelectOptions','.changeOptions','.triggleChangeValues','.immediateEnhance ','.simpleDateFormat','.lodash'
|
||||
]
|
||||
|
||||
/**sql编辑器 表名字段名用于提示*/
|
||||
const sql_keyword = {
|
||||
sys_user: ['USERNAME', 'REALNAME', 'ID','BIRTHDAY','AGE'],
|
||||
demo: ['name', 'age', 'id', 'sex']
|
||||
}
|
||||
|
||||
export {
|
||||
js_keyword,
|
||||
js_method,
|
||||
sql_keyword
|
||||
}
|
||||
@ -1,177 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
import { js_keyword, js_method } from './Resource'
|
||||
(function(mod) {
|
||||
mod(CodeMirror);
|
||||
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env*/
|
||||
|
||||
})(function(CodeMirror) {
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function forEach(arr, f) {
|
||||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
|
||||
}
|
||||
|
||||
function arrayContains(arr, item) {
|
||||
if (!Array.prototype.indexOf) {
|
||||
var i = arr.length;
|
||||
while (i--) {
|
||||
if (arr[i] === item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return arr.indexOf(item) != -1;
|
||||
}
|
||||
|
||||
function scriptHint(editor, keywords, getToken, options) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur);
|
||||
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||
var innerMode = CodeMirror.innerMode(editor.getMode(), token.state);
|
||||
if (innerMode.mode.helperType === "json") return;
|
||||
token.state = innerMode.state;
|
||||
if('.' === token.string){
|
||||
let arr = []
|
||||
for(let k of js_method){
|
||||
arr.push(k)
|
||||
}
|
||||
return {
|
||||
list: arr,
|
||||
from: Pos(cur.line, token.start),
|
||||
to: Pos(cur.line, token.end)
|
||||
};
|
||||
}
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
type: token.string == "." ? "property" : null};
|
||||
} else if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
var tprop = token;
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.type == "property") {
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (tprop.string != ".") return;
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
||||
if (!context) var context = [];
|
||||
context.push(tprop);
|
||||
}
|
||||
return {list: getCompletions(token, context, keywords, options),
|
||||
from: Pos(cur.line, token.start),
|
||||
to: Pos(cur.line, token.end)};
|
||||
}
|
||||
|
||||
function javascriptHint(editor, options) {
|
||||
return scriptHint(editor, javascriptKeywords,
|
||||
function (e, cur) {return e.getTokenAt(cur);},
|
||||
options);
|
||||
};
|
||||
CodeMirror.registerHelper("hint", "javascript", javascriptHint);
|
||||
|
||||
function getCoffeeScriptToken(editor, cur) {
|
||||
// This getToken, it is for coffeescript, imitates the behavior of
|
||||
// getTokenAt method in javascript.js, that is, returning "property"
|
||||
// type and treat "." as indepenent token.
|
||||
var token = editor.getTokenAt(cur);
|
||||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
|
||||
token.end = token.start;
|
||||
token.string = '.';
|
||||
token.type = "property";
|
||||
}
|
||||
else if (/^\.[\w$_]*$/.test(token.string)) {
|
||||
token.type = "property";
|
||||
token.start++;
|
||||
token.string = token.string.replace(/\./, '');
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
function coffeescriptHint(editor, options) {
|
||||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
|
||||
}
|
||||
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);
|
||||
|
||||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
|
||||
"toUpperCase toLowerCase split concat match replace search").split(" ");
|
||||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
|
||||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
|
||||
var funcProps = "prototype apply call bind".split(" ");
|
||||
|
||||
var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " +
|
||||
"if in import instanceof new null return super switch this throw true try typeof var void while with yield that").split(" ");
|
||||
for(let jk of js_keyword){
|
||||
javascriptKeywords.push(jk)
|
||||
}
|
||||
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
|
||||
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");
|
||||
|
||||
function forAllProps(obj, callback) {
|
||||
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
|
||||
for (var name in obj) callback(name)
|
||||
} else {
|
||||
for (var o = obj; o; o = Object.getPrototypeOf(o))
|
||||
Object.getOwnPropertyNames(o).forEach(callback)
|
||||
}
|
||||
}
|
||||
|
||||
function getCompletions(token, context, keywords, options) {
|
||||
var found = [], start = token.string, global = options && options.globalScope || window;
|
||||
function maybeAdd(str) {
|
||||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
|
||||
}
|
||||
function gatherCompletions(obj) {
|
||||
if (typeof obj == "string") forEach(stringProps, maybeAdd);
|
||||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
|
||||
else if (obj instanceof Function) forEach(funcProps, maybeAdd);
|
||||
forAllProps(obj, maybeAdd)
|
||||
}
|
||||
|
||||
if (context && context.length) {
|
||||
// If this is a property, see if it belongs to some object we can
|
||||
// find in the current environment.
|
||||
var obj = context.pop(), base;
|
||||
if (obj.type && obj.type.indexOf("variable") === 0) {
|
||||
if (options && options.additionalContext)
|
||||
base = options.additionalContext[obj.string];
|
||||
if (!options || options.useGlobalScope !== false)
|
||||
base = base || global[obj.string];
|
||||
} else if (obj.type == "string") {
|
||||
base = "";
|
||||
} else if (obj.type == "atom") {
|
||||
base = 1;
|
||||
} else if (obj.type == "function") {
|
||||
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
|
||||
(typeof global.jQuery == 'function'))
|
||||
base = global.jQuery();
|
||||
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
|
||||
base = global._();
|
||||
}
|
||||
while (base != null && context.length)
|
||||
base = base[context.pop().string];
|
||||
if (base != null) gatherCompletions(base);
|
||||
} else {
|
||||
// If not, just look in the global object, any local scope, and optional additional-context
|
||||
// (reading into JS mode internals to get at the local and global variables)
|
||||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
|
||||
for (var c = token.state.context; c; c = c.prev)
|
||||
for (var v = c.vars; v; v = v.next) maybeAdd(v.name)
|
||||
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
|
||||
if (options && options.additionalContext != null)
|
||||
for (var key in options.additionalContext)
|
||||
maybeAdd(key);
|
||||
if (!options || options.useGlobalScope !== false)
|
||||
gatherCompletions(global);
|
||||
forEach(keywords, maybeAdd);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
});
|
||||
@ -1,305 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
/*if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../../mode/sql/sql"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../../mode/sql/sql"], mod);
|
||||
else */
|
||||
// Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var tables;
|
||||
var defaultTable;
|
||||
var keywords;
|
||||
var identifierQuote;
|
||||
var CONS = {
|
||||
QUERY_DIV: ";",
|
||||
ALIAS_KEYWORD: "AS"
|
||||
};
|
||||
var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos;
|
||||
|
||||
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" }
|
||||
|
||||
function getKeywords(editor) {
|
||||
var mode = editor.doc.modeOption;
|
||||
if (mode === "sql") mode = "text/x-sql";
|
||||
return CodeMirror.resolveMode(mode).keywords;
|
||||
}
|
||||
|
||||
function getIdentifierQuote(editor) {
|
||||
var mode = editor.doc.modeOption;
|
||||
if (mode === "sql") mode = "text/x-sql";
|
||||
return CodeMirror.resolveMode(mode).identifierQuote || "`";
|
||||
}
|
||||
|
||||
function getText(item) {
|
||||
return typeof item == "string" ? item : item.text;
|
||||
}
|
||||
|
||||
function wrapTable(name, value) {
|
||||
if (isArray(value)) value = {columns: value}
|
||||
if (!value.text) value.text = name
|
||||
return value
|
||||
}
|
||||
|
||||
function parseTables(input) {
|
||||
var result = {}
|
||||
if (isArray(input)) {
|
||||
for (var i = input.length - 1; i >= 0; i--) {
|
||||
var item = input[i]
|
||||
result[getText(item).toUpperCase()] = wrapTable(getText(item), item)
|
||||
}
|
||||
} else if (input) {
|
||||
for (var name in input)
|
||||
result[name.toUpperCase()] = wrapTable(name, input[name])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function getTable(name) {
|
||||
return tables[name.toUpperCase()]
|
||||
}
|
||||
|
||||
function shallowClone(object) {
|
||||
var result = {};
|
||||
for (var key in object) if (object.hasOwnProperty(key))
|
||||
result[key] = object[key];
|
||||
return result;
|
||||
}
|
||||
|
||||
function match(string, word) {
|
||||
var len = string.length;
|
||||
var sub = getText(word).substr(0, len);
|
||||
return string.toUpperCase() === sub.toUpperCase();
|
||||
}
|
||||
|
||||
function addMatches(result, search, wordlist, formatter) {
|
||||
if (isArray(wordlist)) {
|
||||
for (var i = 0; i < wordlist.length; i++)
|
||||
if (match(search, wordlist[i])) result.push(formatter(wordlist[i]))
|
||||
} else {
|
||||
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) {
|
||||
var val = wordlist[word]
|
||||
if (!val || val === true)
|
||||
val = word
|
||||
else
|
||||
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text
|
||||
if (match(search, val)) result.push(formatter(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanName(name) {
|
||||
// Get rid name from identifierQuote and preceding dot(.)
|
||||
if (name.charAt(0) == ".") {
|
||||
name = name.substr(1);
|
||||
}
|
||||
// replace doublicated identifierQuotes with single identifierQuotes
|
||||
// and remove single identifierQuotes
|
||||
var nameParts = name.split(identifierQuote+identifierQuote);
|
||||
for (var i = 0; i < nameParts.length; i++)
|
||||
nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), "");
|
||||
return nameParts.join(identifierQuote);
|
||||
}
|
||||
|
||||
function insertIdentifierQuotes(name) {
|
||||
var nameParts = getText(name).split(".");
|
||||
for (var i = 0; i < nameParts.length; i++)
|
||||
nameParts[i] = identifierQuote +
|
||||
// doublicate identifierQuotes
|
||||
nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) +
|
||||
identifierQuote;
|
||||
var escaped = nameParts.join(".");
|
||||
if (typeof name == "string") return escaped;
|
||||
name = shallowClone(name);
|
||||
name.text = escaped;
|
||||
return name;
|
||||
}
|
||||
|
||||
function nameCompletion(cur, token, result, editor) {
|
||||
// Try to complete table, column names and return start position of completion
|
||||
var useIdentifierQuotes = false;
|
||||
var nameParts = [];
|
||||
var start = token.start;
|
||||
var cont = true;
|
||||
while (cont) {
|
||||
cont = (token.string.charAt(0) == ".");
|
||||
useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote);
|
||||
|
||||
start = token.start;
|
||||
nameParts.unshift(cleanName(token.string));
|
||||
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||
if (token.string == ".") {
|
||||
cont = true;
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start));
|
||||
}
|
||||
}
|
||||
|
||||
// Try to complete table names
|
||||
var string = nameParts.join(".");
|
||||
addMatches(result, string, tables, function(w) {
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
|
||||
// Try to complete columns from defaultTable
|
||||
addMatches(result, string, defaultTable, function(w) {
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
|
||||
// Try to complete columns
|
||||
string = nameParts.pop();
|
||||
var table = nameParts.join(".");
|
||||
|
||||
var alias = false;
|
||||
var aliasTable = table;
|
||||
// Check if table is available. If not, find table by Alias
|
||||
if (!getTable(table)) {
|
||||
var oldTable = table;
|
||||
table = findTableByAlias(table, editor);
|
||||
if (table !== oldTable) alias = true;
|
||||
}
|
||||
|
||||
var columns = getTable(table);
|
||||
if (columns && columns.columns)
|
||||
columns = columns.columns;
|
||||
|
||||
if (columns) {
|
||||
addMatches(result, string, columns, function(w) {
|
||||
var tableInsert = table;
|
||||
if (alias == true) tableInsert = aliasTable;
|
||||
if (typeof w == "string") {
|
||||
w = tableInsert + "." + w;
|
||||
} else {
|
||||
w = shallowClone(w);
|
||||
w.text = tableInsert + "." + w.text;
|
||||
}
|
||||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w;
|
||||
});
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
function eachWord(lineText, f) {
|
||||
var words = lineText.split(/\s+/)
|
||||
for (var i = 0; i < words.length; i++)
|
||||
if (words[i]) f(words[i].replace(/[,;]/g, ''))
|
||||
}
|
||||
|
||||
function findTableByAlias(alias, editor) {
|
||||
var doc = editor.doc;
|
||||
var fullQuery = doc.getValue();
|
||||
var aliasUpperCase = alias.toUpperCase();
|
||||
var previousWord = "";
|
||||
var table = "";
|
||||
var separator = [];
|
||||
var validRange = {
|
||||
start: Pos(0, 0),
|
||||
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length)
|
||||
};
|
||||
|
||||
//add separator
|
||||
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV);
|
||||
while(indexOfSeparator != -1) {
|
||||
separator.push(doc.posFromIndex(indexOfSeparator));
|
||||
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1);
|
||||
}
|
||||
separator.unshift(Pos(0, 0));
|
||||
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
|
||||
|
||||
//find valid range
|
||||
var prevItem = null;
|
||||
var current = editor.getCursor()
|
||||
for (var i = 0; i < separator.length; i++) {
|
||||
if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) {
|
||||
validRange = {start: prevItem, end: separator[i]};
|
||||
break;
|
||||
}
|
||||
prevItem = separator[i];
|
||||
}
|
||||
|
||||
if (validRange.start) {
|
||||
var query = doc.getRange(validRange.start, validRange.end, false);
|
||||
|
||||
for (var i = 0; i < query.length; i++) {
|
||||
var lineText = query[i];
|
||||
eachWord(lineText, function(word) {
|
||||
var wordUpperCase = word.toUpperCase();
|
||||
if (wordUpperCase === aliasUpperCase && getTable(previousWord))
|
||||
table = previousWord;
|
||||
if (wordUpperCase !== CONS.ALIAS_KEYWORD)
|
||||
previousWord = word;
|
||||
});
|
||||
if (table) break;
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
||||
tables = parseTables(options && options.tables)
|
||||
var defaultTableName = options && options.defaultTable;
|
||||
var disableKeywords = options && options.disableKeywords;
|
||||
defaultTable = defaultTableName && getTable(defaultTableName);
|
||||
keywords = getKeywords(editor);
|
||||
identifierQuote = getIdentifierQuote(editor);
|
||||
|
||||
if (defaultTableName && !defaultTable)
|
||||
defaultTable = findTableByAlias(defaultTableName, editor);
|
||||
|
||||
defaultTable = defaultTable || [];
|
||||
|
||||
if (defaultTable.columns)
|
||||
defaultTable = defaultTable.columns;
|
||||
|
||||
var cur = editor.getCursor();
|
||||
var result = [];
|
||||
var token = editor.getTokenAt(cur), start, end, search;
|
||||
if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) {
|
||||
search = token.string;
|
||||
start = token.start;
|
||||
end = token.end;
|
||||
} else {
|
||||
start = end = cur.ch;
|
||||
search = "";
|
||||
}
|
||||
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) {
|
||||
start = nameCompletion(cur, token, result, editor);
|
||||
} else {
|
||||
var objectOrClass = function(w, className) {
|
||||
if (typeof w === "object") {
|
||||
w.className = className;
|
||||
} else {
|
||||
w = { text: w, className: className };
|
||||
}
|
||||
return w;
|
||||
};
|
||||
addMatches(result, search, defaultTable, function(w) {
|
||||
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
|
||||
});
|
||||
addMatches(
|
||||
result,
|
||||
search,
|
||||
tables, function(w) {
|
||||
return objectOrClass(w, "CodeMirror-hint-table");
|
||||
}
|
||||
);
|
||||
if (!disableKeywords)
|
||||
addMatches(result, search, keywords, function(w) {
|
||||
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
|
||||
});
|
||||
}
|
||||
|
||||
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
|
||||
});
|
||||
});
|
||||
@ -1,92 +0,0 @@
|
||||
let callbacks = []
|
||||
|
||||
function loadSuccess(key) {
|
||||
// to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2144
|
||||
// check is successfully downloaded script
|
||||
return window[key]
|
||||
}
|
||||
|
||||
const load = (src, type, callback) => {
|
||||
if(type=='link'){
|
||||
|
||||
loadStyle(src, callback)
|
||||
}else{
|
||||
let loadKey = ''
|
||||
if(src.indexOf('tinymce')>=0){
|
||||
loadKey = 'tinymce'
|
||||
}else if(src.indexOf('codemirror')>=0){
|
||||
loadKey = 'CodeMirror'
|
||||
}
|
||||
const scriptTag = document.getElementById(src)
|
||||
//const cb = callback || function() {}
|
||||
if (!scriptTag) {
|
||||
const script = document.createElement('script')
|
||||
script.src = src // src url for the third-party library being loaded.
|
||||
script.id = src
|
||||
script.onload=()=>callback()
|
||||
script.onerror=()=>callback('加载失败:'+src)
|
||||
document.body.appendChild(script)
|
||||
//callbacks.push(cb)
|
||||
// const onEnd = 'onload' in script ? stdOnEnd : ieOnEnd
|
||||
// onEnd(script)
|
||||
}else{
|
||||
if (loadSuccess(loadKey)) {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
|
||||
if (scriptTag) {
|
||||
/* else {
|
||||
callbacks.push(cb)
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
function stdOnEnd(script) {
|
||||
script['onload'] = function() {
|
||||
// this.onload = null here is necessary
|
||||
// because even IE9 works not like others
|
||||
this.onerror = this.onload = null
|
||||
for (const cb of callbacks) {
|
||||
cb(null, script)
|
||||
}
|
||||
callbacks = null
|
||||
}
|
||||
script['onerror'] = function() {
|
||||
this.onerror = this.onload = null
|
||||
cb(new Error('Failed to load ' + src), script)
|
||||
}
|
||||
}
|
||||
|
||||
function ieOnEnd(script) {
|
||||
script.onreadystatechange = function() {
|
||||
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
|
||||
this.onreadystatechange = null
|
||||
for (const cb of callbacks) {
|
||||
cb(null, script) // there is no way to catch loading errors in IE8
|
||||
}
|
||||
callbacks = null
|
||||
}
|
||||
}
|
||||
|
||||
function loadStyle(src, callback) {
|
||||
const link = document.getElementById(src)
|
||||
if (!link) {
|
||||
const link = document.createElement('link')
|
||||
link.setAttribute("rel", "stylesheet");
|
||||
link.setAttribute("type", "text/css");
|
||||
link.setAttribute("href", src);
|
||||
link.id = src
|
||||
let heads = document.getElementsByTagName("head")
|
||||
if(heads.length){
|
||||
heads[0].appendChild(link)
|
||||
}else{
|
||||
document.documentElement.appendChild(link)
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default load
|
||||
@ -26,6 +26,14 @@ import JSlider from './JSlider.vue'
|
||||
import JSwitch from './JSwitch.vue'
|
||||
import JTime from './JTime.vue'
|
||||
import JTreeTable from './JTreeTable.vue'
|
||||
import JEasyCron from "@/components/jeecg/JEasyCron";
|
||||
|
||||
//jeecgbiz
|
||||
import JSelectDepart from '../jeecgbiz/JSelectDepart.vue'
|
||||
import JSelectMultiUser from '../jeecgbiz/JSelectMultiUser.vue'
|
||||
import JSelectPosition from '../jeecgbiz/JSelectPosition.vue'
|
||||
import JSelectRole from '../jeecgbiz/JSelectRole.vue'
|
||||
import JSelectUserByDep from '../jeecgbiz/JSelectUserByDep.vue'
|
||||
|
||||
export default {
|
||||
install(Vue) {
|
||||
@ -57,5 +65,13 @@ export default {
|
||||
Vue.component('JTreeSelect', JTreeSelect)
|
||||
Vue.component('JTreeTable', JTreeTable)
|
||||
Vue.component('JUpload', JUpload)
|
||||
|
||||
//jeecgbiz
|
||||
Vue.component('JSelectDepart', JSelectDepart)
|
||||
Vue.component('JSelectMultiUser', JSelectMultiUser)
|
||||
Vue.component('JSelectPosition', JSelectPosition)
|
||||
Vue.component('JSelectRole', JSelectRole)
|
||||
Vue.component('JSelectUserByDep', JSelectUserByDep)
|
||||
Vue.component(JEasyCron.name, JEasyCron)
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,6 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import JUpload from '@/components/jeecg/JUpload'
|
||||
import { getFileAccessHttpUrl } from '@/api/manage';
|
||||
|
||||
const getFileName=(path)=>{
|
||||
@ -27,7 +26,7 @@
|
||||
|
||||
export default {
|
||||
name: 'JFilePop',
|
||||
components: { JUpload },
|
||||
components: { },
|
||||
props:{
|
||||
title:{
|
||||
type:String,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a-modal
|
||||
title="corn表达式"
|
||||
title="cron表达式"
|
||||
:width="modalWidth"
|
||||
:visible="visible"
|
||||
:confirmLoading="confirmLoading"
|
||||
|
||||
@ -78,7 +78,7 @@
|
||||
const MODAL_WIDTH = 1200;
|
||||
export default {
|
||||
name: 'JPopupOnlReport',
|
||||
props: ['multi', 'code', 'groupId', 'param'],
|
||||
props: ['multi', 'code', 'sorter', 'groupId', 'param'],
|
||||
components:{
|
||||
},
|
||||
data(){
|
||||
@ -121,9 +121,10 @@
|
||||
},
|
||||
cgRpConfigId:"",
|
||||
modalWidth:MODAL_WIDTH,
|
||||
tableScroll:{x:MODAL_WIDTH-100},
|
||||
dynamicParam:{}
|
||||
|
||||
tableScroll:{x:true},
|
||||
dynamicParam:{},
|
||||
// 排序字段,默认无排序
|
||||
iSorter: null,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@ -139,7 +140,28 @@
|
||||
this.dynamicParamHandler()
|
||||
this.loadData();
|
||||
},
|
||||
}
|
||||
},
|
||||
sorter: {
|
||||
immediate: true,
|
||||
handler() {
|
||||
if (this.sorter) {
|
||||
let arr = this.sorter.split('=')
|
||||
if (arr.length === 2 && ['asc', 'desc'].includes(arr[1].toLowerCase())) {
|
||||
this.iSorter = {column: arr[0], order: arr[1].toLowerCase()}
|
||||
// 排序字段受控
|
||||
this.table.columns.forEach(col => {
|
||||
if (col.dataIndex === this.iSorter.column) {
|
||||
this.$set(col, 'sortOrder', this.iSorter.order === 'asc' ? 'ascend' : 'descend')
|
||||
} else {
|
||||
this.$set(col, 'sortOrder', false)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.warn('【JPopup】sorter参数不合法')
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
computed:{
|
||||
showSearchFlag(){
|
||||
@ -167,6 +189,10 @@
|
||||
return filterMultiDictText(this.dictOptions[dictCode], text+"");
|
||||
}
|
||||
}
|
||||
// 排序字段受控
|
||||
if (this.iSorter && currColumns[a].dataIndex === this.iSorter.column) {
|
||||
currColumns[a].sortOrder = this.iSorter.order === 'asc' ? 'ascend' : 'descend'
|
||||
}
|
||||
}
|
||||
this.table.columns = [...currColumns]
|
||||
this.initQueryInfo()
|
||||
@ -253,7 +279,7 @@
|
||||
paramTarget['self_'+key] = this.dynamicParam[key]
|
||||
})
|
||||
}
|
||||
let param = Object.assign(paramTarget, this.queryParam, this.sorter);
|
||||
let param = Object.assign(paramTarget, this.queryParam, this.iSorter);
|
||||
param.pageNo = this.table.pagination.current;
|
||||
param.pageSize = this.table.pagination.pageSize;
|
||||
return filterObj(param);
|
||||
@ -288,8 +314,18 @@
|
||||
handleChangeInTable(pagination, filters, sorter) {
|
||||
//分页、排序、筛选变化时触发
|
||||
if (Object.keys(sorter).length > 0) {
|
||||
this.sorter.column = sorter.field
|
||||
this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc'
|
||||
this.iSorter = {
|
||||
column: sorter.field,
|
||||
order: 'ascend' === sorter.order ? 'asc' : 'desc'
|
||||
}
|
||||
// 排序字段受控
|
||||
this.table.columns.forEach(col => {
|
||||
if (col.dataIndex === sorter.field) {
|
||||
this.$set(col, 'sortOrder',sorter.order)
|
||||
} else {
|
||||
this.$set(col, 'sortOrder', false)
|
||||
}
|
||||
})
|
||||
}
|
||||
this.table.pagination = pagination
|
||||
this.loadData()
|
||||
@ -342,7 +378,13 @@
|
||||
combineRowKey(record){
|
||||
let res = ''
|
||||
Object.keys(record).forEach(key=>{
|
||||
res+=record[key]
|
||||
//update-begin---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||
if(key=='id'){
|
||||
res=record[key]+res
|
||||
}else{
|
||||
res+=record[key]
|
||||
}
|
||||
//update-end---author:liusq Date:20210203 for:pop选择器列主键问题 issues/I29P9Q------------
|
||||
})
|
||||
if(res.length>50){
|
||||
res = res.substring(0,50)
|
||||
|
||||
@ -53,6 +53,11 @@
|
||||
customReturnField: {
|
||||
type: String,
|
||||
default: 'id'
|
||||
},
|
||||
backDepart: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
@ -91,6 +96,23 @@
|
||||
}
|
||||
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填
|
||||
},
|
||||
//返回选中的部门信息
|
||||
backDeparInfo(){
|
||||
if(this.backDepart===true){
|
||||
if(this.departIds && this.departIds.length>0){
|
||||
let arr1 = this.departIds.split(',')
|
||||
let arr2 = this.departNames.split(',')
|
||||
let info = []
|
||||
for(let i=0;i<arr1.length;i++){
|
||||
info.push({
|
||||
value: arr1[i],
|
||||
text: arr2[i]
|
||||
})
|
||||
}
|
||||
this.$emit('back', info)
|
||||
}
|
||||
}
|
||||
},
|
||||
openModal(){
|
||||
this.$refs.innerDepartSelectModal.show()
|
||||
},
|
||||
@ -105,6 +127,7 @@
|
||||
this.departIds = idstr
|
||||
}
|
||||
this.$emit("change", value)
|
||||
this.backDeparInfo()
|
||||
},
|
||||
getDepartNames(){
|
||||
return this.departNames
|
||||
|
||||
@ -38,6 +38,11 @@
|
||||
default: true,
|
||||
required: false
|
||||
},
|
||||
backUser: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -61,6 +66,23 @@
|
||||
initComp(userNames) {
|
||||
this.userNames = userNames
|
||||
},
|
||||
//返回选中的用户信息
|
||||
backDeparInfo(){
|
||||
if(this.backUser===true){
|
||||
if(this.userIds && this.userIds.length>0){
|
||||
let arr1 = this.userIds.split(',')
|
||||
let arr2 = this.userNames.split(',')
|
||||
let info = []
|
||||
for(let i=0;i<arr1.length;i++){
|
||||
info.push({
|
||||
value: arr1[i],
|
||||
text: arr2[i]
|
||||
})
|
||||
}
|
||||
this.$emit('back', info)
|
||||
}
|
||||
}
|
||||
},
|
||||
onSearchDepUser() {
|
||||
this.$refs.selectModal.showModal()
|
||||
},
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
:confirmLoading="confirmLoading"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
wrapClassName="j-depart-select-modal"
|
||||
switchFullscreen
|
||||
cancelText="关闭">
|
||||
<a-spin tip="Loading..." :spinning="false">
|
||||
@ -166,7 +167,9 @@
|
||||
if(!this.checkedKeys || this.checkedKeys.length==0){
|
||||
this.$emit("ok",'')
|
||||
}else{
|
||||
this.$emit("ok",this.checkedRows,this.checkedKeys.join(","))
|
||||
let checkRow = this.getCheckedRows(this.checkedKeys)
|
||||
let keyStr = this.checkedKeys.join(",")
|
||||
this.$emit("ok", checkRow, keyStr)
|
||||
}
|
||||
this.handleClear()
|
||||
},
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
:visible="visible"
|
||||
:title="title"
|
||||
switchFullscreen
|
||||
wrapClassName="j-user-select-modal"
|
||||
@ok="handleSubmit"
|
||||
@cancel="close"
|
||||
style="top:50px"
|
||||
@ -55,8 +56,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {filterObj} from '@/utils/util'
|
||||
import { pushIfNotExist, filterObj } from '@/utils/util'
|
||||
import {queryDepartTreeList, getUserList, queryUserByDepId} from '@/api/api'
|
||||
import { getAction } from '@/api/manage'
|
||||
|
||||
export default {
|
||||
name: 'JSelectUserByDepModal',
|
||||
@ -105,6 +107,7 @@
|
||||
],
|
||||
scrollTrigger: {},
|
||||
dataSource: [],
|
||||
selectionRows: [],
|
||||
selectedRowKeys: [],
|
||||
selectUserRows: [],
|
||||
selectUserIds: [],
|
||||
@ -162,11 +165,13 @@
|
||||
pageSize: values.length
|
||||
}).then((res) => {
|
||||
if (res.success) {
|
||||
this.selectionRows = []
|
||||
let selectedRowKeys = []
|
||||
let realNames = []
|
||||
res.result.records.forEach(user => {
|
||||
realNames.push(user['realname'])
|
||||
selectedRowKeys.push(user['id'])
|
||||
this.selectionRows.push(user)
|
||||
})
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
this.$emit('initComp', realNames.join(','))
|
||||
@ -181,20 +186,16 @@
|
||||
if (arg === 1) {
|
||||
this.ipagination.current = 1;
|
||||
}
|
||||
if (this.selectedDepIds && this.selectedDepIds.length > 0) {
|
||||
await this.initQueryUserByDepId(this.selectedDepIds)
|
||||
} else {
|
||||
this.loading = true
|
||||
let params = this.getQueryParams()//查询条件
|
||||
await getUserList(params).then((res) => {
|
||||
if (res.success) {
|
||||
this.dataSource = res.result.records
|
||||
this.ipagination.total = res.result.total
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
let params = this.getQueryParams()//查询条件
|
||||
this.loading = true
|
||||
getAction('/sys/user/queryUserComponentData', params).then(res=>{
|
||||
if (res.success) {
|
||||
this.dataSource = res.result.records
|
||||
this.ipagination.total = res.result.total
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 触发屏幕自适应
|
||||
resetScreenSize() {
|
||||
@ -217,6 +218,7 @@
|
||||
param.field = this.getQueryField();
|
||||
param.pageNo = this.ipagination.current;
|
||||
param.pageSize = this.ipagination.pageSize;
|
||||
param.departId = this.selectedDepIds.join(',')
|
||||
return filterObj(param);
|
||||
},
|
||||
getQueryField() {
|
||||
@ -228,13 +230,13 @@
|
||||
},
|
||||
searchReset(num) {
|
||||
let that = this;
|
||||
that.selectedRowKeys = [];
|
||||
that.selectUserIds = [];
|
||||
that.selectedDepIds = [];
|
||||
if (num !== 0) {
|
||||
that.queryParam = {};
|
||||
that.loadData(1);
|
||||
}
|
||||
that.selectedRowKeys = [];
|
||||
that.selectUserIds = [];
|
||||
that.selectedDepIds = [];
|
||||
},
|
||||
close() {
|
||||
this.searchReset(0);
|
||||
@ -257,30 +259,27 @@
|
||||
that.close();
|
||||
},
|
||||
//获取选择用户信息
|
||||
getSelectUserRows(rowId) {
|
||||
let dataSource = this.dataSource;
|
||||
let userIds = "";
|
||||
this.selectUserRows = [];
|
||||
for (let i = 0, len = dataSource.length; i < len; i++) {
|
||||
if (this.selectedRowKeys.includes(dataSource[i].id)) {
|
||||
this.selectUserRows.push(dataSource[i]);
|
||||
userIds = userIds + "," + dataSource[i].username
|
||||
getSelectUserRows() {
|
||||
this.selectUserRows = []
|
||||
for (let row of this.selectionRows) {
|
||||
if (this.selectedRowKeys.includes(row.id)) {
|
||||
this.selectUserRows.push(row)
|
||||
}
|
||||
}
|
||||
this.selectUserIds = userIds.substring(1);
|
||||
this.selectUserIds = this.selectUserRows.map(row => row.username).join(',')
|
||||
},
|
||||
// 点击树节点,筛选出对应的用户
|
||||
onDepSelect(selectedDepIds) {
|
||||
if (selectedDepIds[0] != null) {
|
||||
this.initQueryUserByDepId(selectedDepIds); // 调用方法根据选选择的id查询用户信息
|
||||
if (this.selectedDepIds[0] !== selectedDepIds[0]) {
|
||||
this.selectedDepIds = [selectedDepIds[0]];
|
||||
}
|
||||
this.loadData(1);
|
||||
}
|
||||
},
|
||||
onSelectChange(selectedRowKeys, selectionRows) {
|
||||
this.selectedRowKeys = selectedRowKeys;
|
||||
this.selectionRows = selectionRows;
|
||||
selectionRows.forEach(row => pushIfNotExist(this.selectionRows, row, 'id'))
|
||||
},
|
||||
onSearch() {
|
||||
this.loadData(1);
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<span v-if="syncToApp || syncToLocal">
|
||||
<j-third-app-dropdown v-if="enabledTypes.wechatEnterprise" type="wechatEnterprise" name="企微" v-bind="bindAttrs" v-on="bindEvents"/>
|
||||
<j-third-app-dropdown v-if="enabledTypes.dingtalk" type="dingtalk" name="钉钉" v-bind="bindAttrs" v-on="bindEvents"/>
|
||||
</span>
|
||||
<span v-else>未设置任何同步方向</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAction } from '@/api/manage'
|
||||
import { cloneObject } from '@/utils/util'
|
||||
import JThirdAppDropdown from './JThirdAppDropdown'
|
||||
|
||||
const backEndUrl = {
|
||||
// 获取启用的第三方App
|
||||
getEnabledType: '/sys/thirdApp/getEnabledType',
|
||||
// 企业微信
|
||||
wechatEnterprise: {
|
||||
user: '/sys/thirdApp/sync/wechatEnterprise/user',
|
||||
depart: '/sys/thirdApp/sync/wechatEnterprise/depart',
|
||||
},
|
||||
// 钉钉
|
||||
dingtalk: {
|
||||
user: '/sys/thirdApp/sync/dingtalk/user',
|
||||
depart: '/sys/thirdApp/sync/dingtalk/depart',
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'JThirdAppButton',
|
||||
components: {JThirdAppDropdown},
|
||||
props: {
|
||||
// 同步类型,可以是 user、depart
|
||||
bizType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
// 是否允许同步到第三方APP
|
||||
syncToApp: Boolean,
|
||||
// 是否允许第三方APP同步到本地
|
||||
syncToLocal: Boolean,
|
||||
// 选择的行
|
||||
selectedRowKeys: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enabledTypes: {},
|
||||
attrs: {
|
||||
dingtalk: {},
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
bindAttrs() {
|
||||
return {
|
||||
syncToApp: this.syncToApp,
|
||||
syncToLocal: this.syncToLocal
|
||||
}
|
||||
},
|
||||
bindEvents() {
|
||||
return {
|
||||
'to-app': this.onToApp,
|
||||
'to-local': this.onToLocal,
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadEnabledTypes()
|
||||
},
|
||||
methods: {
|
||||
handleMenuClick() {
|
||||
console.log(arguments)
|
||||
},
|
||||
onToApp(e) {
|
||||
this.doSync(e.type, '/toApp')
|
||||
},
|
||||
onToLocal(e) {
|
||||
this.doSync(e.type, '/toLocal')
|
||||
},
|
||||
// 获取启用的第三方App
|
||||
async loadEnabledTypes() {
|
||||
this.enabledTypes = await loadEnabledTypes()
|
||||
},
|
||||
// 开始同步第三方App
|
||||
doSync(type, direction) {
|
||||
let urls = backEndUrl[type]
|
||||
if (!(urls && urls[this.bizType])) {
|
||||
console.warn('配置出错')
|
||||
return
|
||||
}
|
||||
let url = urls[this.bizType] + direction
|
||||
|
||||
let selectedRowKeys = this.selectedRowKeys
|
||||
let content = '确定要开始同步全部数据吗?可能花费较长时间!'
|
||||
if (Array.isArray(selectedRowKeys) && selectedRowKeys.length > 0) {
|
||||
content = `确定要开始同步这 ${selectedRowKeys.length} 项吗?`
|
||||
} else {
|
||||
selectedRowKeys = []
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
let model = this.$confirm({
|
||||
title: '同步',
|
||||
content,
|
||||
onOk: () => {
|
||||
model.update({
|
||||
keyboard: false,
|
||||
okText: '同步中…',
|
||||
cancelButtonProps: {props: {disabled: true}}
|
||||
})
|
||||
return getAction(url, {
|
||||
ids: selectedRowKeys.join(',')
|
||||
}).then(res => {
|
||||
let options = null
|
||||
if (res.result) {
|
||||
options = {
|
||||
width: 600,
|
||||
title: res.message,
|
||||
content: (h) => {
|
||||
let nodes
|
||||
let successInfo = [
|
||||
`成功信息如下:`,
|
||||
this.renderTextarea(h, res.result.successInfo.map((v, i) => `${i + 1}. ${v}`).join('\n')),
|
||||
]
|
||||
if (res.success) {
|
||||
nodes = [
|
||||
...successInfo,
|
||||
h('br'),
|
||||
`无失败信息!`,
|
||||
]
|
||||
} else {
|
||||
nodes = [
|
||||
`失败信息如下:`,
|
||||
this.renderTextarea(h, res.result.failInfo.map((v, i) => `${i + 1}. ${v}`).join('\n')),
|
||||
h('br'),
|
||||
...successInfo,
|
||||
]
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res.success) {
|
||||
if (options != null) {
|
||||
this.$success(options)
|
||||
} else {
|
||||
this.$message.success(res.message)
|
||||
}
|
||||
this.$emit('sync-ok')
|
||||
} else {
|
||||
if (options != null) {
|
||||
this.$warning(options)
|
||||
} else {
|
||||
this.$message.warning(res.message)
|
||||
}
|
||||
this.$emit('sync-error')
|
||||
}
|
||||
}).catch(() => model.destroy()).finally(() => {
|
||||
resolve()
|
||||
this.$emit('sync-finally', {
|
||||
type,
|
||||
direction,
|
||||
isToApp: direction === '/toApp',
|
||||
isToLocal: direction === '/toLocal',
|
||||
})
|
||||
})
|
||||
},
|
||||
onCancel() {
|
||||
resolve()
|
||||
},
|
||||
})
|
||||
})
|
||||
},
|
||||
renderTextarea(h, value) {
|
||||
return h('a-textarea', {
|
||||
props: {
|
||||
value: value,
|
||||
readOnly: true,
|
||||
autosize: {minRows: 5, maxRows: 10},
|
||||
},
|
||||
style: {
|
||||
// 关闭textarea的自动换行,使其可以左右滚动
|
||||
whiteSpace: 'pre',
|
||||
overflow: 'auto',
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// 启用了哪些第三方App(在此缓存)
|
||||
let enabledTypes = null
|
||||
|
||||
// 获取启用的第三方App
|
||||
export async function loadEnabledTypes() {
|
||||
// 获取缓存
|
||||
if (enabledTypes != null) {
|
||||
return cloneObject(enabledTypes)
|
||||
} else {
|
||||
let {success, result} = await getAction(backEndUrl.getEnabledType)
|
||||
if (success) {
|
||||
// 在此缓存
|
||||
enabledTypes = cloneObject(result)
|
||||
return result
|
||||
} else {
|
||||
console.warn('getEnabledType查询失败:', res)
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<a-dropdown v-if="syncToApp && syncToLocal">
|
||||
<a-button type="primary" icon="sync">同步{{name}}</a-button>
|
||||
<a-menu slot="overlay" @click="handleMenuClick">
|
||||
<a-menu-item v-if="syncToApp" key="to-app">同步到{{name}}</a-menu-item>
|
||||
<a-menu-item v-if="syncToLocal" key="to-local">同步到本地</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
<a-button v-else-if="syncToApp" type="primary" icon="sync" @click="handleMenuClick({key:'to-app'})">同步{{name}}</a-button>
|
||||
<a-button v-else type="primary" icon="sync" @click="handleMenuClick({key:'to-local'})">同步{{name}}到本地</a-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
/* JThirdAppButton 的子组件,不可单独使用 */
|
||||
export default {
|
||||
name: 'JThirdAppDropdown',
|
||||
props: {
|
||||
type: String,
|
||||
name: String,
|
||||
syncToApp: Boolean,
|
||||
syncToLocal: Boolean,
|
||||
},
|
||||
methods: {
|
||||
handleMenuClick(event) {
|
||||
this.$emit(event.key, {type: this.type})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@ -38,16 +38,20 @@
|
||||
//url = "http://www.baidu.com"
|
||||
console.log("------url------"+url)
|
||||
if (url !== null && url !== undefined) {
|
||||
this.url = url;
|
||||
//-----------------------------------------------------------------------------------------
|
||||
//url支持通过 ${token}方式传递当前登录TOKEN
|
||||
let tokenStr = "${token}";
|
||||
if(url.indexOf(tokenStr)!=-1) {
|
||||
let token = Vue.ls.get(ACCESS_TOKEN);
|
||||
this.url = url.replace(tokenStr, token);
|
||||
} else {
|
||||
this.url = url
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------
|
||||
|
||||
/*update_begin author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
||||
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
|
||||
this.closeCurrent();
|
||||
//外部url加入token
|
||||
let tokenStr = "${token}";
|
||||
if(url.indexOf(tokenStr)!=-1){
|
||||
let token = Vue.ls.get(ACCESS_TOKEN);
|
||||
this.url = url.replace(tokenStr,token);
|
||||
}
|
||||
window.open(this.url);
|
||||
}
|
||||
/*update_end author:wuxianquan date:20190908 for:判断打开方式,新窗口打开时this.$route.meta.internalOrExternal==true */
|
||||
|
||||
@ -19,14 +19,14 @@
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<div style="margin: 12px 12px 0;">
|
||||
<transition name="page-toggle">
|
||||
<keep-alive v-if="multipage">
|
||||
<router-view v-if="reloadFlag"/>
|
||||
</keep-alive>
|
||||
<template v-else>
|
||||
<router-view v-if="reloadFlag"/>
|
||||
</template>
|
||||
</transition>
|
||||
<!-- update-begin-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
|
||||
<keep-alive v-if="multipage">
|
||||
<router-view v-if="reloadFlag"/>
|
||||
</keep-alive>
|
||||
<template v-else>
|
||||
<router-view v-if="reloadFlag"/>
|
||||
</template>
|
||||
<!-- update-end-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
|
||||
</div>
|
||||
</global-layout>
|
||||
</template>
|
||||
@ -36,9 +36,10 @@
|
||||
import Contextmenu from '@/components/menu/Contextmenu'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||
const indexKey = '/dashboard/analysis'
|
||||
import Vue from 'vue'
|
||||
import { CACHE_INCLUDED_ROUTES } from "@/store/mutation-types"
|
||||
import { CACHE_INCLUDED_ROUTES } from '@/store/mutation-types'
|
||||
|
||||
const indexKey = '/dashboard/analysis'
|
||||
|
||||
export default {
|
||||
name: 'TabLayout',
|
||||
@ -86,13 +87,6 @@
|
||||
// 复制一个route对象出来,不能影响原route
|
||||
let currentRoute = Object.assign({}, this.$route)
|
||||
currentRoute.meta = Object.assign({}, currentRoute.meta)
|
||||
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||
let storeKey = 'route:title:' + currentRoute.fullPath
|
||||
let routeTitle = this.$ls.get(storeKey)
|
||||
if (routeTitle) {
|
||||
currentRoute.meta.title = routeTitle
|
||||
}
|
||||
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||
this.pageList.push(currentRoute)
|
||||
this.linkList.push(currentRoute.fullPath)
|
||||
this.activePage = currentRoute.fullPath
|
||||
@ -171,7 +165,7 @@
|
||||
|
||||
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
|
||||
changeTitle(title) {
|
||||
let projectTitle = "Jeecg-Boot 企业级快速开发平台"
|
||||
let projectTitle = "Jeecg-Boot 企业级低代码平台"
|
||||
// 首页特殊处理
|
||||
if (this.$route.path === indexKey) {
|
||||
document.title = projectTitle
|
||||
@ -186,7 +180,12 @@
|
||||
},
|
||||
tabCallBack() {
|
||||
this.$nextTick(() => {
|
||||
triggerWindowResizeEvent()
|
||||
//update-begin-author:taoyan date: 20201211 for:【新版】online报错 JT-100
|
||||
setTimeout(()=>{
|
||||
//省市区组件里面给window绑定了个resize事件 导致切换页面的时候触发了他的resize,但是切换页面,省市区组件还没被销毁前就触发了该事件,导致控制台报错,加个延迟
|
||||
triggerWindowResizeEvent()
|
||||
},20)
|
||||
//update-end-author:taoyan date: 20201211 for:【新版】online报错 JT-100
|
||||
})
|
||||
},
|
||||
editPage(key, action) {
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="desc">
|
||||
Jeecg Boot 是中国最具影响力的 企业级 快速开发平台
|
||||
Jeecg Boot 是中国最具影响力的 企业级 低代码平台
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -54,6 +54,11 @@ import {
|
||||
Carousel,
|
||||
Pagination,
|
||||
FormModel,
|
||||
Cascader,
|
||||
Slider,
|
||||
Transfer,
|
||||
Rate,
|
||||
Collapse,
|
||||
} from 'ant-design-vue'
|
||||
import Viser from 'viser-vue'
|
||||
|
||||
@ -104,6 +109,11 @@ Vue.use(TreeSelect)
|
||||
Vue.use(Carousel)
|
||||
Vue.use(Pagination)
|
||||
Vue.use(FormModel)
|
||||
Vue.use(Cascader)
|
||||
Vue.use(Slider)
|
||||
Vue.use(Transfer)
|
||||
Vue.use(Rate)
|
||||
Vue.use(Collapse)
|
||||
|
||||
Vue.prototype.$confirm = Modal.confirm
|
||||
Vue.prototype.$message = message
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
:menu="menus"
|
||||
:theme="theme"
|
||||
@select="onSelect"
|
||||
@updateMenuTitle="onUpdateMenuTitle"
|
||||
:mode="mode"
|
||||
:style="smenuStyle">
|
||||
</s-menu>
|
||||
@ -19,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ALayoutSider from "ant-design-vue/es/layout/Sider"
|
||||
import ALayoutSider from 'ant-design-vue/es/layout/Sider'
|
||||
import Logo from '../tools/Logo'
|
||||
import SMenu from './index'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
@ -68,6 +69,9 @@
|
||||
methods: {
|
||||
onSelect (obj) {
|
||||
this.$emit('menuSelect', obj)
|
||||
},
|
||||
onUpdateMenuTitle (obj) {
|
||||
this.$emit('updateMenuTitle', obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,41 +140,8 @@
|
||||
background-color: #999999;
|
||||
}
|
||||
}
|
||||
background-color: rgb(48, 65, 86);
|
||||
/deep/ .ant-menu-submenu-title:hover{
|
||||
background-color: #263445;
|
||||
}
|
||||
/deep/ .ant-menu-item:hover{
|
||||
background-color: #263445;
|
||||
}
|
||||
/deep/ .ant-menu-item-selected {
|
||||
background-color: #263445;
|
||||
}
|
||||
/deep/ .ant-menu-item-selected i{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
/deep/ .ant-menu-item-selected span{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub{
|
||||
background-color: #1f2d3d;
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub li:hover{
|
||||
background-color: #1f2d3d;
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub .ant-menu-submenu-title:hover{
|
||||
background-color: #1f2d3d;
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub .ant-menu-item-selected{
|
||||
background-color: #1f2d3d;
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub .ant-menu-item-selected span{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
/deep/ .ant-menu-inline.ant-menu-sub .ant-menu-item-selected i{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* update_end author:sunjianlei date:20190509 for: 修改侧边导航栏滚动条的样式 */
|
||||
|
||||
@ -82,18 +82,49 @@ export default {
|
||||
} else {
|
||||
this.selectedKeys = [routes.pop().path]
|
||||
}
|
||||
const openKeys = []
|
||||
let openKeys = []
|
||||
if (this.mode === 'inline') {
|
||||
routes.forEach(item => {
|
||||
openKeys.push(item.path)
|
||||
})
|
||||
}
|
||||
|
||||
// update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
// 包含冒号的是动态菜单
|
||||
if (this.selectedKeys[0].includes(':')) {
|
||||
let selectedKey = this.$route.fullPath
|
||||
this.selectedKeys = [selectedKey]
|
||||
let newOpenKeys = []
|
||||
this.fullOpenKeys(this.menu, selectedKey, newOpenKeys)
|
||||
if (newOpenKeys.length > 0) {
|
||||
openKeys = newOpenKeys.reverse()
|
||||
}
|
||||
}
|
||||
// update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
|
||||
//update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
|
||||
if(!this.selectedKeys || this.selectedKeys[0].indexOf(":")<0){
|
||||
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
|
||||
}
|
||||
//update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
|
||||
},
|
||||
// update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
// 递归查找当前选中的菜单和父级菜单,填充openKeys
|
||||
fullOpenKeys(menus, selectedKey, openKeys) {
|
||||
for (let item of menus) {
|
||||
if (item.path === selectedKey) {
|
||||
openKeys.push(item.path)
|
||||
this.$emit('updateMenuTitle', item)
|
||||
return true
|
||||
} else if (Array.isArray(item.children)) {
|
||||
if (this.fullOpenKeys(item.children, selectedKey, openKeys)) {
|
||||
openKeys.push(item.path)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
|
||||
// render
|
||||
renderItem (menu) {
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
:type="collapsed ? 'menu-unfold' : 'menu-fold'"
|
||||
@click="toggle"/>
|
||||
|
||||
<span v-if="device === 'desktop'">欢迎进入 Jeecg-Boot 企业级快速开发平台</span>
|
||||
<span v-if="device === 'desktop'">欢迎进入 Jeecg-Boot 企业级低代码平台</span>
|
||||
<span v-else>Jeecg-Boot</span>
|
||||
|
||||
<user-menu :theme="theme"/>
|
||||
@ -31,7 +31,9 @@
|
||||
<s-menu
|
||||
mode="horizontal"
|
||||
:menu="menus"
|
||||
:theme="theme"></s-menu>
|
||||
:theme="theme"
|
||||
@updateMenuTitle="handleUpdateMenuTitle"
|
||||
></s-menu>
|
||||
</div>
|
||||
<a-icon
|
||||
v-else
|
||||
@ -42,6 +44,7 @@
|
||||
<user-menu class="header-index-right" :theme="theme" :style="topMenuStyle.headerIndexRight"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</a-layout-header>
|
||||
</template>
|
||||
|
||||
@ -49,7 +52,6 @@
|
||||
import UserMenu from '../tools/UserMenu'
|
||||
import SMenu from '../menu/'
|
||||
import Logo from '../tools/Logo'
|
||||
|
||||
import { mixin } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
@ -155,8 +157,15 @@
|
||||
this.topMenuStyle.headerIndexLeft = { 'width': `calc(100% - ${rightWidth})` }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮-----
|
||||
|
||||
// update-begin-author:sunjianlei date:20210508 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
handleUpdateMenuTitle(value) {
|
||||
this.$emit('updateMenuTitle', value)
|
||||
},
|
||||
// update-end-author:sunjianlei date:20210508 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
v-if="device === 'mobile'"
|
||||
:menus="menus"
|
||||
@menuSelect="menuSelect"
|
||||
@updateMenuTitle="handleUpdateMenuTitle"
|
||||
:theme="navTheme"
|
||||
:collapsed="false"
|
||||
:collapsible="true"></side-menu>
|
||||
@ -26,6 +27,7 @@
|
||||
mode="inline"
|
||||
:menus="menus"
|
||||
@menuSelect="myMenuSelect"
|
||||
@updateMenuTitle="handleUpdateMenuTitle"
|
||||
:theme="navTheme"
|
||||
:collapsed="collapsed"
|
||||
:collapsible="true"></side-menu>
|
||||
@ -45,6 +47,7 @@
|
||||
mode="inline"
|
||||
:menus="menus"
|
||||
@menuSelect="menuSelect"
|
||||
@updateMenuTitle="handleUpdateMenuTitle"
|
||||
:theme="navTheme"
|
||||
:collapsed="false"
|
||||
:collapsible="true"></side-menu>
|
||||
@ -62,6 +65,7 @@
|
||||
:collapsed="collapsed"
|
||||
:device="device"
|
||||
@toggle="toggle"
|
||||
@updateMenuTitle="handleUpdateMenuTitle"
|
||||
/>
|
||||
|
||||
<!-- layout content -->
|
||||
@ -85,15 +89,14 @@
|
||||
import SideMenu from '@/components/menu/SideMenu'
|
||||
import GlobalHeader from '@/components/page/GlobalHeader'
|
||||
import GlobalFooter from '@/components/page/GlobalFooter'
|
||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||
import { mapActions, mapState } from 'vuex'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
// update-start---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
|
||||
// import SettingDrawer from '@/components/setting/SettingDrawer'
|
||||
// 注释这个因为在个人设置模块已经加载了SettingDrawer页面
|
||||
// update-end ---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
|
||||
|
||||
import { triggerWindowResizeEvent } from '@/utils/util'
|
||||
import { mapState, mapActions } from 'vuex'
|
||||
import { mixin, mixinDevice } from '@/utils/mixin.js'
|
||||
|
||||
export default {
|
||||
name: 'GlobalLayout',
|
||||
components: {
|
||||
@ -131,6 +134,11 @@
|
||||
//--update-begin----author:scott---date:20190320------for:根据后台菜单配置,判断是否路由菜单字段,动态选择是否生成路由(为了支持参数URL菜单)------
|
||||
//this.menus = this.mainRouters.find((item) => item.path === '/').children;
|
||||
this.menus = this.permissionMenuList
|
||||
|
||||
//--update-begin----author:liusq---date:20210223------for:关于测边菜单遮挡内容问题详细说明 #2255
|
||||
this.collapsed=!this.sidebarOpened;
|
||||
//--update-begin----author:liusq---date:20210223------for:关于测边菜单遮挡内容问题详细说明 #2255
|
||||
|
||||
// 根据后台配置菜单,重新排序加载路由信息
|
||||
//console.log('----加载菜单逻辑----')
|
||||
//console.log(this.mainRouters)
|
||||
@ -155,10 +163,6 @@
|
||||
//此处触发动态路由被点击事件
|
||||
this.findMenuBykey(this.menus,value.key)
|
||||
this.$emit("dynamicRouterShow",value.key,this.activeMenu.meta.title)
|
||||
// update-begin-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||
let storeKey = 'route:title:' + this.activeMenu.path
|
||||
this.$ls.set(storeKey, this.activeMenu.meta.title)
|
||||
// update-end-author:sunjianlei date:20191223 for: 修复刷新后菜单Tab名字显示异常
|
||||
},
|
||||
findMenuBykey(menus,key){
|
||||
for(let i of menus){
|
||||
@ -168,8 +172,17 @@
|
||||
this.findMenuBykey(i.children,key)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
//update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title
|
||||
|
||||
// update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
handleUpdateMenuTitle(value) {
|
||||
this.findMenuBykey(this.menus, value.path)
|
||||
this.activeMenu.meta.title = value.meta.title
|
||||
this.$emit('dynamicRouterShow', value.path, this.activeMenu.meta.title)
|
||||
},
|
||||
// update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,43 +541,8 @@
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
/deep/ .ant-menu-dark{
|
||||
background-color: rgb(48, 65, 86);
|
||||
/deep/ .ant-menu-submenu:hover{
|
||||
background-color: #263445;
|
||||
}
|
||||
/deep/ .ant-menu-item:hover{
|
||||
background-color: #263445;
|
||||
}
|
||||
}
|
||||
/deep/ .ant-menu.ant-menu-dark .ant-menu-item-selected{
|
||||
background-color: #263445;
|
||||
}
|
||||
/deep/ .ant-menu.ant-menu-dark .ant-menu-item-selected i{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
/deep/ .ant-menu.ant-menu-dark .ant-menu-item-selected span{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
/deep/ .ant-menu-dark .ant-menu-submenu-active{
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
}
|
||||
.dark.header-index-right{
|
||||
background-color: rgb(48, 65, 86) !important;
|
||||
}
|
||||
.layout .top-nav-header-index.dark .user-wrapper .action:hover{
|
||||
background-color: #263445 !important;
|
||||
}
|
||||
.layout .top-nav-header-index .dark .user-wrapper .action i{
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
.layout .top-nav-header-index .user-wrapper .action .anticon{
|
||||
color: inherit !important;
|
||||
}
|
||||
.dark.ant-dropdown-menu{
|
||||
background-color: #999999;
|
||||
}
|
||||
|
||||
// drawer-sider 自定义
|
||||
.ant-drawer.drawer-sider {
|
||||
.sider {
|
||||
@ -715,22 +693,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-menu-dark .ant-menu-vertical.ant-menu-sub li:hover{
|
||||
background-color: #001528;
|
||||
}
|
||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected{
|
||||
background-color: #001528 !important;
|
||||
}
|
||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected span{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
.ant-menu-submenu-popup.ant-menu-dark .ant-menu-item-selected i{
|
||||
color: rgb(24, 144, 255);
|
||||
}
|
||||
.ant-menu-dark .ant-menu-sub{
|
||||
background: #1f2d3d !important;
|
||||
.ant-menu-submenu-open,.ant-menu-submenu-active{
|
||||
color: #FFFFFF !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
:closable="false"
|
||||
@close="onClose"
|
||||
:visible="visible"
|
||||
:style="{}"
|
||||
style="height: 100%;overflow: auto;"
|
||||
>
|
||||
<div class="setting-drawer-index-content">
|
||||
|
||||
@ -87,7 +87,7 @@
|
||||
</div>
|
||||
<div :style="{ marginTop: '24px' }">
|
||||
<a-list :split="false">
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-tooltip slot="actions">
|
||||
<template slot="title">
|
||||
该设定仅 [顶部栏导航] 时有效
|
||||
@ -101,19 +101,19 @@
|
||||
<div slot="title">内容区域宽度</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="fixedHeader" @change="handleFixedHeader" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">固定 Header</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :disabled="!fixedHeader" :defaultChecked="autoHideHeader" @change="handleFixedHeaderHidden" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title" :style="{ textDecoration: !fixedHeader ? 'line-through' : 'unset' }">下滑时隐藏 Header</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :disabled="(layoutMode === 'topmenu')" :checked="dataFixSiderbar" @change="handleFixSiderbar" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title" :style="{ textDecoration: layoutMode === 'topmenu' ? 'line-through' : 'unset' }">固定侧边菜单</div>
|
||||
@ -128,13 +128,13 @@
|
||||
<h3 class="setting-drawer-index-title">其他设置</h3>
|
||||
<div>
|
||||
<a-list :split="false">
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="colorWeak" @change="onColorWeak" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">色弱模式</div>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item, index">
|
||||
<a-list-item>
|
||||
<a-switch slot="actions" size="small" :defaultChecked="multipage" @change="onMultipageWeak" />
|
||||
<a-list-item-meta>
|
||||
<div slot="title">多页签模式</div>
|
||||
@ -178,19 +178,12 @@
|
||||
mixins: [mixin, mixinDevice],
|
||||
data() {
|
||||
return {
|
||||
visible: true,
|
||||
visible: false,
|
||||
colorList,
|
||||
dataFixSiderbar: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
},
|
||||
mounted () {
|
||||
const vm = this
|
||||
setTimeout(() => {
|
||||
vm.visible = false
|
||||
}, 16)
|
||||
// 当主题色不是默认色时,才进行主题编译
|
||||
if (this.primaryColor !== config.primaryColor) {
|
||||
updateTheme(this.primaryColor)
|
||||
|
||||
@ -185,8 +185,8 @@
|
||||
return that.Logout({}).then(() => {
|
||||
// update-begin author:wangshuai date:20200601 for: 退出登录跳转登录页面
|
||||
that.$router.push({ path: '/user/login' });
|
||||
window.location.reload()
|
||||
// update-end author:wangshuai date:20200601 for: 退出登录跳转登录页面
|
||||
//window.location.reload()
|
||||
}).catch(err => {
|
||||
that.$message.error({
|
||||
title: '错误',
|
||||
@ -225,11 +225,17 @@
|
||||
// update_begin author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
|
||||
searchMethods(value) {
|
||||
let route = this.searchMenuOptions.filter(item => item.id === value)[0]
|
||||
if (route.meta.internalOrExternal === true || route.component.includes('layouts/IframePageView')) {
|
||||
//update-begin-author:taoyan date:20210528 for: 【菜单问题】配置一个iframe地址的菜单,内部打开,在搜索菜单上打开却新开了一个窗口
|
||||
if (route.meta.internalOrExternal === true) {
|
||||
window.open(route.meta.url, '_blank')
|
||||
} else {
|
||||
this.$router.push({ path: route.path })
|
||||
if(route.component.includes('layouts/IframePageView')){
|
||||
this.$router.push(route)
|
||||
}else{
|
||||
this.$router.push({ path: route.path })
|
||||
}
|
||||
}
|
||||
//update-end-author:taoyan date:20210528 for: 【菜单问题】配置一个iframe地址的菜单,内部打开,在搜索菜单上打开却新开了一个窗口
|
||||
this.searchMenuVisible = false
|
||||
},
|
||||
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
|
||||
|
||||
@ -20,7 +20,6 @@ import 'ant-design-vue/dist/antd.less'; // or 'ant-design-vue/dist/antd.less'
|
||||
import '@/permission' // permission control
|
||||
import '@/utils/filter' // base filter
|
||||
import Print from 'vue-print-nb-jeecg'
|
||||
/*import '@babel/polyfill'*/
|
||||
import preview from 'vue-photo-preview'
|
||||
import 'vue-photo-preview/dist/skin.css'
|
||||
import SSO from '@/cas/sso.js'
|
||||
@ -47,7 +46,9 @@ import '@/assets/less/JAreaLinkage.less'
|
||||
import VueAreaLinkage from 'vue-area-linkage'
|
||||
import '@/components/jeecg/JVxeTable/install'
|
||||
import '@/components/JVxeCells/install'
|
||||
|
||||
//表单验证
|
||||
import { rules } from '@/utils/rules'
|
||||
Vue.prototype.rules = rules
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(Storage, config.storageOptions)
|
||||
Vue.use(Antd)
|
||||
|
||||
@ -50,6 +50,7 @@ export const JEditableTableMixin = {
|
||||
add() {
|
||||
//update-begin-author:lvdandan date:20201113 for:LOWCOD-1049 JEditaTable,子表默认添加一条数据,addDefaultRowNum设置无效 #1930
|
||||
return new Promise((resolve) => {
|
||||
this.tableReset();
|
||||
resolve();
|
||||
}).then(() => {
|
||||
// 默认新增空数据
|
||||
@ -68,6 +69,9 @@ export const JEditableTableMixin = {
|
||||
},
|
||||
/** 当点击了编辑(修改)按钮时调用此方法 */
|
||||
edit(record) {
|
||||
if(record && '{}'!=JSON.stringify(record)){
|
||||
this.tableReset();
|
||||
}
|
||||
if (typeof this.editBefore === 'function') this.editBefore(record)
|
||||
this.visible = true
|
||||
this.activeKey = this.refKeys[0]
|
||||
@ -78,12 +82,14 @@ export const JEditableTableMixin = {
|
||||
/** 关闭弹窗,并将所有JEditableTable实例回归到初始状态 */
|
||||
close() {
|
||||
this.visible = false
|
||||
this.eachAllTable((item) => {
|
||||
item.initialize()
|
||||
})
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
//清空子表table的数据
|
||||
tableReset(){
|
||||
this.eachAllTable((item) => {
|
||||
item.clearRow()
|
||||
})
|
||||
},
|
||||
/** 查询某个tab的数据 */
|
||||
requestSubTableData(url, params, tab, success) {
|
||||
tab.loading = true
|
||||
|
||||
190
ant-design-vue-jeecg/src/mixins/JEditableTableModelMixin.js
Normal file
190
ant-design-vue-jeecg/src/mixins/JEditableTableModelMixin.js
Normal file
@ -0,0 +1,190 @@
|
||||
import JEditableTable from '@/components/jeecg/JEditableTable'
|
||||
import { VALIDATE_NO_PASSED, getRefPromise,validateFormModelAndTables} from '@/utils/JEditableTableUtil'
|
||||
import { httpAction, getAction } from '@/api/manage'
|
||||
|
||||
export const JEditableTableModelMixin = {
|
||||
components: {
|
||||
JEditableTable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: '操作',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
model:{},
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 6 }
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 18 }
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** 获取所有的editableTable实例 */
|
||||
getAllTable() {
|
||||
if (!(this.refKeys instanceof Array)) {
|
||||
throw this.throwNotArray('refKeys')
|
||||
}
|
||||
let values = this.refKeys.map(key => getRefPromise(this, key))
|
||||
return Promise.all(values)
|
||||
},
|
||||
|
||||
/** 遍历所有的JEditableTable实例 */
|
||||
eachAllTable(callback) {
|
||||
// 开始遍历
|
||||
this.getAllTable().then(tables => {
|
||||
tables.forEach((item, index) => {
|
||||
if (typeof callback === 'function') {
|
||||
callback(item, index)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
/** 当点击新增按钮时调用此方法 */
|
||||
add() {
|
||||
//update-begin-author:lvdandan date:20201113 for:LOWCOD-1049 JEditaTable,子表默认添加一条数据,addDefaultRowNum设置无效 #1930
|
||||
return new Promise((resolve) => {
|
||||
this.tableReset();
|
||||
resolve();
|
||||
}).then(() => {
|
||||
// 默认新增空数据
|
||||
let rowNum = this.addDefaultRowNum
|
||||
if (typeof rowNum !== 'number') {
|
||||
rowNum = 1
|
||||
console.warn('由于你没有在 data 中定义 addDefaultRowNum 或 addDefaultRowNum 不是数字,所以默认添加一条空数据,如果不想默认添加空数据,请将定义 addDefaultRowNum 为 0')
|
||||
}
|
||||
this.eachAllTable((item) => {
|
||||
item.add(rowNum)
|
||||
})
|
||||
if (typeof this.addAfter === 'function') this.addAfter(this.model)
|
||||
this.edit(this.model)
|
||||
})
|
||||
//update-end-author:lvdandan date:20201113 for:LOWCOD-1049 JEditaTable,子表默认添加一条数据,addDefaultRowNum设置无效 #1930
|
||||
},
|
||||
/** 当点击了编辑(修改)按钮时调用此方法 */
|
||||
edit(record) {
|
||||
if(record && '{}'!=JSON.stringify(record)&&record.id){
|
||||
this.tableReset();
|
||||
}
|
||||
if (typeof this.editBefore === 'function') this.editBefore(record)
|
||||
this.visible = true
|
||||
this.activeKey = this.refKeys[0]
|
||||
this.$refs.form.resetFields()
|
||||
this.model = Object.assign({}, record)
|
||||
if (typeof this.editAfter === 'function') this.editAfter(this.model)
|
||||
},
|
||||
/** 关闭弹窗,并将所有JEditableTable实例回归到初始状态 */
|
||||
close() {
|
||||
this.visible = false
|
||||
this.$emit('close')
|
||||
},
|
||||
//清空子表table的数据
|
||||
tableReset(){
|
||||
this.eachAllTable((item) => {
|
||||
item.clearRow()
|
||||
})
|
||||
},
|
||||
/** 查询某个tab的数据 */
|
||||
requestSubTableData(url, params, tab, success) {
|
||||
tab.loading = true
|
||||
getAction(url, params).then(res => {
|
||||
let { result } = res
|
||||
let dataSource = []
|
||||
if (result) {
|
||||
if (Array.isArray(result)) {
|
||||
dataSource = result
|
||||
} else if (Array.isArray(result.records)) {
|
||||
dataSource = result.records
|
||||
}
|
||||
}
|
||||
tab.dataSource = dataSource
|
||||
typeof success === 'function' ? success(res) : ''
|
||||
}).finally(() => {
|
||||
tab.loading = false
|
||||
})
|
||||
},
|
||||
/** 发起请求,自动判断是执行新增还是修改操作 */
|
||||
request(formData) {
|
||||
let url = this.url.add, method = 'post'
|
||||
if (this.model.id) {
|
||||
url = this.url.edit
|
||||
method = 'put'
|
||||
}
|
||||
this.confirmLoading = true
|
||||
httpAction(url, formData, method).then((res) => {
|
||||
if (res.success) {
|
||||
this.$message.success(res.message)
|
||||
this.$emit('ok')
|
||||
this.close()
|
||||
} else {
|
||||
this.$message.warning(res.message)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/* --- handle 事件 --- */
|
||||
|
||||
/** ATab 选项卡切换事件 */
|
||||
handleChangeTabs(key) {
|
||||
// 自动重置scrollTop状态,防止出现白屏
|
||||
getRefPromise(this, key).then(editableTable => {
|
||||
editableTable.resetScrollTop()
|
||||
})
|
||||
},
|
||||
/** 关闭按钮点击事件 */
|
||||
handleCancel() {
|
||||
this.close()
|
||||
},
|
||||
/** 确定按钮点击事件 */
|
||||
handleOk() {
|
||||
/** 触发表单验证 */
|
||||
this.getAllTable().then(tables => {
|
||||
/** 一次性验证主表和所有的次表 */
|
||||
return validateFormModelAndTables(this.$refs.form,this.model, tables)
|
||||
}).then(allValues => {
|
||||
/** 一次性验证一对一的所有子表 */
|
||||
return this.validateSubForm(allValues)
|
||||
}).then(allValues => {
|
||||
if (typeof this.classifyIntoFormData !== 'function') {
|
||||
throw this.throwNotFunction('classifyIntoFormData')
|
||||
}
|
||||
let formData = this.classifyIntoFormData(allValues)
|
||||
// 发起请求
|
||||
return this.request(formData)
|
||||
}).catch(e => {
|
||||
if (e.error === VALIDATE_NO_PASSED) {
|
||||
// 如果有未通过表单验证的子表,就自动跳转到它所在的tab
|
||||
//update--begin--autor:liusq-----date:20210316------for:未通过表单验证跳转tab问题------
|
||||
this.activeKey = e.index == null ? this.activeKey : (e.paneKey?e.paneKey:this.refKeys[e.index])
|
||||
//update--end--autor:liusq-----date:20210316------for:未通过表单验证跳转tab问题------
|
||||
} else {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
//校验所有子表表单
|
||||
validateSubForm(allValues){
|
||||
return new Promise((resolve) => {
|
||||
resolve(allValues)
|
||||
})
|
||||
},
|
||||
/* --- throw --- */
|
||||
|
||||
/** not a function */
|
||||
throwNotFunction(name) {
|
||||
return `${name} 未定义或不是一个函数`
|
||||
},
|
||||
|
||||
/** not a array */
|
||||
throwNotArray(name) {
|
||||
return `${name} 未定义或不是一个数组`
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -52,10 +52,13 @@ export const JVxeTableMixin = {
|
||||
rowNum = 1
|
||||
console.warn('由于你没有在 data 中定义 addDefaultRowNum 或 addDefaultRowNum 不是数字,所以默认添加一条空数据,如果不想默认添加空数据,请将定义 addDefaultRowNum 为 0')
|
||||
}
|
||||
//update-begin-author:taoyan date:20210315 for: 一对多jvex 默认几行不好使了 LOWCOD-1349
|
||||
this.eachAllTable((item) => {
|
||||
item.addRows()
|
||||
//item.add(rowNum)
|
||||
setTimeout(()=>{
|
||||
item.addRows()
|
||||
}, 30)
|
||||
})
|
||||
//update-end-author:taoyan date:20210315 for: 一对多jvex 默认几行不好使了 LOWCOD-1349
|
||||
if (typeof this.addAfter === 'function') this.addAfter(this.model)
|
||||
this.edit({})
|
||||
},
|
||||
|
||||
181
ant-design-vue-jeecg/src/mixins/JVxeTableModelMixin.js
Normal file
181
ant-design-vue-jeecg/src/mixins/JVxeTableModelMixin.js
Normal file
@ -0,0 +1,181 @@
|
||||
import { VALIDATE_FAILED, getRefPromise, validateFormAndTables,validateFormModelAndTables} from '@/components/jeecg/JVxeTable/utils/vxeUtils.js'
|
||||
import { httpAction, getAction } from '@/api/manage'
|
||||
|
||||
export const JVxeTableModelMixin = {
|
||||
data() {
|
||||
return {
|
||||
title: '操作',
|
||||
visible: false,
|
||||
confirmLoading: false,
|
||||
scrolling: true,
|
||||
model: {},
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 6 }
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 18 }
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
/** 获取所有的JVxeTable实例 */
|
||||
getAllTable() {
|
||||
if (!(this.refKeys instanceof Array)) {
|
||||
throw this.throwNotArray('refKeys')
|
||||
}
|
||||
let values = this.refKeys.map(key => getRefPromise(this, key))
|
||||
return Promise.all(values)
|
||||
},
|
||||
|
||||
/** 遍历所有的JVxeTable实例 */
|
||||
eachAllTable(callback) {
|
||||
// 开始遍历
|
||||
this.getAllTable().then(tables => {
|
||||
console.log("tables",tables)
|
||||
tables.forEach((item, index) => {
|
||||
if (typeof callback === 'function') {
|
||||
callback(item, index)
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
/** 当点击新增按钮时调用此方法 */
|
||||
add() {
|
||||
if (typeof this.addBefore === 'function') this.addBefore()
|
||||
// 默认新增空数据
|
||||
let rowNum = this.addDefaultRowNum
|
||||
if (typeof rowNum !== 'number') {
|
||||
rowNum = 1
|
||||
console.warn('由于你没有在 data 中定义 addDefaultRowNum 或 addDefaultRowNum 不是数字,所以默认添加一条空数据,如果不想默认添加空数据,请将定义 addDefaultRowNum 为 0')
|
||||
}
|
||||
this.eachAllTable((item) => {
|
||||
//update-begin-author:taoyan date:20210315 for: 一对多jvex 默认几行不好使了 LOWCOD-1349
|
||||
setTimeout(()=>{
|
||||
item.addRows()
|
||||
}, 30)
|
||||
//update-end-author:taoyan date:20210315 for: 一对多jvex 默认几行不好使了 LOWCOD-1349
|
||||
})
|
||||
if (typeof this.addAfter === 'function') this.addAfter(this.model)
|
||||
this.edit(this.model)
|
||||
},
|
||||
/** 当点击了编辑(修改)按钮时调用此方法 */
|
||||
edit(record) {
|
||||
if (typeof this.editBefore === 'function') this.editBefore(record)
|
||||
this.visible = true
|
||||
this.activeKey = this.refKeys[0]
|
||||
this.$refs.form.resetFields()
|
||||
this.model = Object.assign({}, record)
|
||||
if (typeof this.editAfter === 'function') this.editAfter(this.model)
|
||||
},
|
||||
/** 关闭弹窗,并将所有JVxeTable实例回归到初始状态 */
|
||||
close() {
|
||||
this.visible = false
|
||||
this.eachAllTable((item) => {
|
||||
item._remove()
|
||||
})
|
||||
this.$emit('close')
|
||||
},
|
||||
|
||||
/** 查询某个tab的数据 */
|
||||
requestSubTableData(url, params, tab, success) {
|
||||
tab.loading = true
|
||||
getAction(url, params).then(res => {
|
||||
let { result } = res
|
||||
let dataSource = []
|
||||
if (result) {
|
||||
if (Array.isArray(result)) {
|
||||
dataSource = result
|
||||
} else if (Array.isArray(result.records)) {
|
||||
dataSource = result.records
|
||||
}
|
||||
}
|
||||
tab.dataSource = dataSource
|
||||
typeof success === 'function' ? success(res) : ''
|
||||
}).finally(() => {
|
||||
tab.loading = false
|
||||
})
|
||||
},
|
||||
/** 发起请求,自动判断是执行新增还是修改操作 */
|
||||
request(formData) {
|
||||
let url = this.url.add, method = 'post'
|
||||
if (this.model.id) {
|
||||
url = this.url.edit
|
||||
method = 'put'
|
||||
}
|
||||
this.confirmLoading = true
|
||||
console.log("formData===>",formData);
|
||||
httpAction(url, formData, method).then((res) => {
|
||||
if (res.success) {
|
||||
this.$message.success(res.message)
|
||||
this.$emit('ok')
|
||||
this.close()
|
||||
} else {
|
||||
this.$message.warning(res.message)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.confirmLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
/* --- handle 事件 --- */
|
||||
|
||||
/** ATab 选项卡切换事件 */
|
||||
handleChangeTabs(key) {
|
||||
// 自动重置scrollTop状态,防止出现白屏
|
||||
getRefPromise(this, key).then(vxeTable => {
|
||||
vxeTable.resetScrollTop()
|
||||
})
|
||||
},
|
||||
/** 关闭按钮点击事件 */
|
||||
handleCancel() {
|
||||
this.close()
|
||||
},
|
||||
/** 确定按钮点击事件 */
|
||||
handleOk() {
|
||||
/** 触发表单验证 */
|
||||
this.getAllTable().then(tables => {
|
||||
/** 一次性验证主表和所有的次表 */
|
||||
return validateFormModelAndTables(this.$refs.form,this.model, tables)
|
||||
}).then(allValues => {
|
||||
/** 一次性验证一对一的所有子表 */
|
||||
return this.validateSubForm(allValues)
|
||||
}).then(allValues => {
|
||||
if (typeof this.classifyIntoFormData !== 'function') {
|
||||
throw this.throwNotFunction('classifyIntoFormData')
|
||||
}
|
||||
let formData = this.classifyIntoFormData(allValues)
|
||||
// 发起请求
|
||||
return this.request(formData)
|
||||
}).catch(e => {
|
||||
if (e.error === VALIDATE_FAILED) {
|
||||
// 如果有未通过表单验证的子表,就自动跳转到它所在的tab
|
||||
this.activeKey = e.index == null ? this.activeKey : this.refKeys[e.index]
|
||||
} else {
|
||||
console.error(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
//校验所有子表表单
|
||||
validateSubForm(allValues){
|
||||
return new Promise((resolve) => {
|
||||
resolve(allValues)
|
||||
})
|
||||
},
|
||||
/* --- throw --- */
|
||||
|
||||
/** not a function */
|
||||
throwNotFunction(name) {
|
||||
return `${name} 未定义或不是一个函数`
|
||||
},
|
||||
|
||||
/** not a array */
|
||||
throwNotArray(name) {
|
||||
return `${name} 未定义或不是一个数组`
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -6,15 +6,13 @@
|
||||
import { filterObj } from '@/utils/util';
|
||||
import { deleteAction, getAction,downFile,getFileAccessHttpUrl } from '@/api/manage'
|
||||
import Vue from 'vue'
|
||||
import { ACCESS_TOKEN } from "@/store/mutation-types"
|
||||
import { ACCESS_TOKEN, TENANT_ID } from "@/store/mutation-types"
|
||||
import store from '@/store'
|
||||
import {Modal} from 'ant-design-vue'
|
||||
|
||||
export const JeecgListMixin = {
|
||||
data(){
|
||||
return {
|
||||
//token header
|
||||
tokenHeader: {'X-Access-Token': Vue.ls.get(ACCESS_TOKEN)},
|
||||
/* 查询条件-请不要在queryParam中声明非字符串值的属性 */
|
||||
queryParam: {},
|
||||
/* 数据源 */
|
||||
@ -62,6 +60,17 @@ export const JeecgListMixin = {
|
||||
this.initDictConfig();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
//token header
|
||||
tokenHeader(){
|
||||
let head = {'X-Access-Token': Vue.ls.get(ACCESS_TOKEN)}
|
||||
let tenantid = Vue.ls.get(TENANT_ID)
|
||||
if(tenantid){
|
||||
head['tenant-id'] = tenantid
|
||||
}
|
||||
return head;
|
||||
}
|
||||
},
|
||||
methods:{
|
||||
loadData(arg) {
|
||||
if(!this.url.list){
|
||||
@ -81,6 +90,8 @@ export const JeecgListMixin = {
|
||||
if(res.result.total)
|
||||
{
|
||||
this.ipagination.total = res.result.total;
|
||||
}else{
|
||||
this.ipagination.total = 0;
|
||||
}
|
||||
//update-end---author:zhangyafei Date:20201118 for:适配不分页的数据列表------------
|
||||
}
|
||||
@ -166,6 +177,8 @@ export const JeecgListMixin = {
|
||||
that.loading = true;
|
||||
deleteAction(that.url.deleteBatch, {ids: ids}).then((res) => {
|
||||
if (res.success) {
|
||||
//重新计算分页问题
|
||||
that.reCalculatePage(that.selectedRowKeys.length)
|
||||
that.$message.success(res.message);
|
||||
that.loadData();
|
||||
that.onClearSelected();
|
||||
@ -187,6 +200,8 @@ export const JeecgListMixin = {
|
||||
var that = this;
|
||||
deleteAction(that.url.delete, {id: id}).then((res) => {
|
||||
if (res.success) {
|
||||
//重新计算分页问题
|
||||
that.reCalculatePage(1)
|
||||
that.$message.success(res.message);
|
||||
that.loadData();
|
||||
} else {
|
||||
@ -194,6 +209,17 @@ export const JeecgListMixin = {
|
||||
}
|
||||
});
|
||||
},
|
||||
reCalculatePage(count){
|
||||
//总数量-count
|
||||
let total=this.ipagination.total-count;
|
||||
//获取删除后的分页数
|
||||
let currentIndex=Math.ceil(total/this.ipagination.pageSize);
|
||||
//删除后的分页数<所在当前页
|
||||
if(currentIndex<this.ipagination.current){
|
||||
this.ipagination.current=currentIndex;
|
||||
}
|
||||
console.log('currentIndex',currentIndex)
|
||||
},
|
||||
handleEdit: function (record) {
|
||||
this.$refs.modalForm.edit(record);
|
||||
this.$refs.modalForm.title = "编辑";
|
||||
@ -207,6 +233,7 @@ export const JeecgListMixin = {
|
||||
handleTableChange(pagination, filters, sorter) {
|
||||
//分页、排序、筛选变化时触发
|
||||
//TODO 筛选
|
||||
console.log(pagination)
|
||||
if (Object.keys(sorter).length > 0) {
|
||||
this.isorter.column = sorter.field;
|
||||
this.isorter.order = "ascend" == sorter.order ? "asc" : "desc"
|
||||
@ -224,6 +251,8 @@ export const JeecgListMixin = {
|
||||
modalFormOk() {
|
||||
// 新增/修改 成功时,重载列表
|
||||
this.loadData();
|
||||
//清空列表选中
|
||||
this.onClearSelected()
|
||||
},
|
||||
handleDetail:function(record){
|
||||
this.$refs.modalForm.edit(record);
|
||||
@ -278,8 +307,7 @@ export const JeecgListMixin = {
|
||||
let href = window._CONFIG['domianURL'] + fileUrl
|
||||
this.$warning({
|
||||
title: message,
|
||||
content: (
|
||||
<div>
|
||||
content: (<div>
|
||||
<span>{msg}</span><br/>
|
||||
<span>具体详情请 <a href={href} target="_blank" download={fileName}>点击下载</a> </span>
|
||||
</div>
|
||||
|
||||
@ -155,6 +155,8 @@ const user = {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_PERMISSIONLIST', [])
|
||||
Vue.ls.remove(ACCESS_TOKEN)
|
||||
Vue.ls.remove(USER_INFO)
|
||||
Vue.ls.remove(USER_NAME)
|
||||
Vue.ls.remove(UI_CACHE_DB_DICT_DATA)
|
||||
Vue.ls.remove(CACHE_INCLUDED_ROUTES)
|
||||
//console.log('logoutToken: '+ logoutToken)
|
||||
|
||||
@ -21,7 +21,6 @@ export const TENANT_ID = 'TENANT_ID'
|
||||
export const ONL_AUTH_FIELDS = 'ONL_AUTH_FIELDS'
|
||||
//路由缓存问题,关闭了tab页时再打开就不刷新 #842
|
||||
export const CACHE_INCLUDED_ROUTES = 'CACHE_INCLUDED_ROUTES'
|
||||
|
||||
export const CONTENT_WIDTH_TYPE = {
|
||||
Fluid: 'Fluid',
|
||||
Fixed: 'Fixed'
|
||||
|
||||
@ -14,10 +14,12 @@ const FormTypes = {
|
||||
popup:'popup',
|
||||
list_multi:"list_multi",
|
||||
sel_search:"sel_search",
|
||||
sel_search_async:"sel_search_async",
|
||||
radio:'radio',
|
||||
checkbox_meta:"checkbox_meta",
|
||||
input_pop:'input_pop',
|
||||
|
||||
sel_depart: 'sel_depart',
|
||||
sel_user: 'sel_user',
|
||||
slot: 'slot',
|
||||
hidden: 'hidden'
|
||||
}
|
||||
@ -75,6 +77,36 @@ export function validateFormAndTables(form, cases) {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
}
|
||||
/**
|
||||
* 一次性验证主表单和所有的次表单(新版本)
|
||||
* @param form 主表单 form 对象
|
||||
* @param cases 接收一个数组,每项都是一个JEditableTable实例
|
||||
* @returns {Promise<any>}
|
||||
* @author sunjianlei
|
||||
*/
|
||||
export function validateFormModelAndTables(form,values, cases) {
|
||||
|
||||
if (!(form && typeof form.validate === 'function')) {
|
||||
throw `form 参数需要的是一个form对象,而传入的却是${typeof form}`
|
||||
}
|
||||
let options = {}
|
||||
return new Promise((resolve, reject) => {
|
||||
// 验证主表表单
|
||||
form.validate((valid,obj) => {
|
||||
valid ?resolve(values):reject({ error: VALIDATE_NO_PASSED })
|
||||
})
|
||||
}).then(values => {
|
||||
Object.assign(options, { formValue: values })
|
||||
// 验证所有子表的表单
|
||||
return validateTables(cases)
|
||||
}).then(all => {
|
||||
Object.assign(options, { tablesValue: all })
|
||||
return Promise.resolve(options)
|
||||
}).catch(error => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -9,10 +9,10 @@ export function disabledAuthFilter(code,formData) {
|
||||
}
|
||||
|
||||
function nodeDisabledAuth(code,formData){
|
||||
console.log("页面权限禁用--NODE--开始");
|
||||
//console.log("页面权限禁用--NODE--开始");
|
||||
let permissionList = [];
|
||||
try {
|
||||
console.log("页面权限禁用--NODE--开始",formData);
|
||||
//console.log("页面权限禁用--NODE--开始",formData);
|
||||
if (formData) {
|
||||
let bpmList = formData.permissionList;
|
||||
permissionList = bpmList.filter(item=>item.type=='2')
|
||||
@ -53,7 +53,7 @@ function nodeDisabledAuth(code,formData){
|
||||
}
|
||||
|
||||
function globalDisabledAuth(code){
|
||||
console.log("全局页面禁用权限--Global--开始");
|
||||
//console.log("全局页面禁用权限--Global--开始");
|
||||
|
||||
let permissionList = [];
|
||||
let allPermissionList = [];
|
||||
@ -106,7 +106,7 @@ function globalDisabledAuth(code){
|
||||
}else{
|
||||
for (let item2 of permissionList) {
|
||||
if(code === item2.action){
|
||||
console.log("全局页面权限解除禁用--Global--生效");
|
||||
//console.log("全局页面权限解除禁用--Global--生效");
|
||||
gFlag = false;
|
||||
}
|
||||
}
|
||||
@ -206,6 +206,37 @@ export function getNoAuthCols(pre){
|
||||
return cols;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Online的行编辑按钮权限,添加至本地存储
|
||||
*/
|
||||
export function addOnlineBtAuth2Storage(pre, authList){
|
||||
let allAuthList = JSON.parse(sessionStorage.getItem(SYS_BUTTON_AUTH) || "[]");
|
||||
let newAuthList = allAuthList.filter(item=>{
|
||||
if(!item.action){
|
||||
return true
|
||||
}
|
||||
return item.action.indexOf(pre)<0
|
||||
})
|
||||
if(authList && authList.length>0){
|
||||
for(let item of authList){
|
||||
newAuthList.push({
|
||||
action: pre+item,
|
||||
type:1,
|
||||
status:1
|
||||
})
|
||||
}
|
||||
let temp = JSON.parse(sessionStorage.getItem(USER_AUTH) || "[]");
|
||||
let newArr = temp.filter(item=>{
|
||||
if(!item.action){
|
||||
return true
|
||||
}
|
||||
return item.action.indexOf(pre)<0 || authList.indexOf(item.action.replace(pre, ''))<0
|
||||
})
|
||||
sessionStorage.setItem(USER_AUTH, JSON.stringify(newArr))
|
||||
}
|
||||
sessionStorage.setItem(SYS_BUTTON_AUTH, JSON.stringify(newAuthList))
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user