Compare commits

..

176 Commits

Author SHA1 Message Date
8b3d83ae0b HW21-0499 表字典接口存在SQL注入漏洞,增加签名拦截器 2021-06-21 20:37:23 +08:00
081c2615be HW21-0499 表字典接口存在SQL注入漏洞,增加签名拦截器 2021-06-21 20:37:09 +08:00
f97c675771 online表单数据源配置,数据库类型识别错误 #2671 2021-06-21 19:29:37 +08:00
1beddbf8e8 online表单数据源配置,不支持数据库密码加密 #2672 2021-06-21 19:29:21 +08:00
8921e84303 群满,加新群 ④774126647 2021-06-17 17:44:43 +08:00
43329545d8 【gitee/I3HTFI】自定义树控件的表单里的外键直接显示id不显示name
新增监控在线用户
阿里监控去掉广告
2021-06-17 10:39:59 +08:00
50333488a5 解决issue#2639 2.4.5升级后出现后端排序报错 2021-06-07 18:21:13 +08:00
624444e3b9 用户添加页面无法修改手机号 2021-06-04 16:52:07 +08:00
1cd0f2627d JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-04 11:14:53 +08:00
18007b0524 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-03 14:04:31 +08:00
d92861ad77 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-03 13:59:37 +08:00
8a6181b108 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 16:25:47 +08:00
6840772959 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:51:21 +08:00
1bc7ee3345 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:38:47 +08:00
5f25f726c2 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:38:28 +08:00
9b14d2d6a5 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:38:14 +08:00
130f2bc4be JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:37:49 +08:00
832bc376be JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:32:35 +08:00
432385fc14 新增一种 Cron表达式 选择组件 2021-06-02 15:28:23 +08:00
4d5ac2b518 JeecgBoot低代码平台 2.4.5 版本发布,钉钉与企业微信集成版本 2021-06-02 15:26:58 +08:00
b83c26b8fd 熔断默认时间改成3秒 2021-06-02 15:25:58 +08:00
b59fc67696 新增图表API接口 2021-06-02 15:22:45 +08:00
af3afc7263 删除不需要的底层工具包 2021-06-02 15:21:16 +08:00
63c3dd26f5 即将发布新版 2021-06-02 09:37:32 +08:00
892196fe9a 外部URL菜单加载为空为空 2021-04-14 22:01:47 +08:00
bbda918cde 升级jimureport,修复已知bug 2021-04-13 16:15:10 +08:00
003ec82f48 阿里oos桶名字修改 2021-04-13 16:14:47 +08:00
4992faf66c minidao db类型说明、阿里oos桶名字修改 2021-04-13 16:14:35 +08:00
34c612d9e4 兼容数据库说明 2021-04-13 16:11:58 +08:00
844f1e228c 外部url菜单,内部打开是,也支持通过 ${token}方式传递当前登录TOKEN 2021-04-07 14:07:41 +08:00
cf5fde80d4 nacos建表语句优化 2021-04-06 14:06:55 +08:00
49ea36c50f 升级脚本到积木报表的最新版本 2021-04-06 14:06:35 +08:00
f6e2b67c61 升级SQL:积木报表的示例 2021-04-05 19:01:12 +08:00
69a4a7df6d 重构登录注册页面为a-form-model模式 2021-04-05 18:58:36 +08:00
649f99664e 积木报表升级到最新版本1.3.1-beta2 2021-04-05 18:53:14 +08:00
ef762ff21f 日志里把具体的文件加上吧 issues/I3BJDQ 2021-04-01 09:44:47 +08:00
02abd5c803 优化生成器模板:让代码更简洁,流程相关代码默认不生成 2021-04-01 09:42:47 +08:00
5e7342b27d 优化代码生成器模板:一对多代码生成(ERP模板)生成的子表实体ApiModel注释中value为附表名称 #2365 2021-04-01 09:40:43 +08:00
ca95d7090c minio上传文件,文件名包含点的时候拼接文件名有问题 issues/I3CLFL 2021-04-01 09:38:45 +08:00
cdec71999a spring-boot-starter-jimureport降低版本,公共仓库可以下载 2021-03-31 17:46:04 +08:00
7990eff7a4 JImageUpload组件单张无法预览和删除 #2382 2021-03-31 12:01:18 +08:00
280f8c26ac online报表配置支持多租户系统变量 issues/I3CL75 2021-03-31 12:00:51 +08:00
4e05eaa4c5 JEditableTable组件popup字段设置必填校验有问题 2021-03-31 11:59:47 +08:00
c6645ed800 描述文字写错修改 2021-03-28 19:51:53 +08:00
a674340c5e 微服务模式部署下,nacos的账户密码如果不使用默认提供的nacos/nacos,会导致gateway读取路由信息失败 #2375 2021-03-28 19:45:50 +08:00
cbd8890cb3 代码生成器,树列表新增,会默认加上上次选的父节点问题 2021-03-24 15:56:31 +08:00
b25fb55d10 代码生成器,树列表固定操作列,解决列表分类未翻译问题 2021-03-24 15:55:59 +08:00
88646bea1b 让不对接流程的表单,生成的页面代码更简洁 2021-03-23 22:26:19 +08:00
9915b84808 升级2.4.3后,微服务网关路由更新bug 2021-03-23 15:30:04 +08:00
35c1214de3 开发和测试环境取消swagger文档密码 2021-03-23 14:23:32 +08:00
434b1a7e63 BindingResult无法使用 #2219 2021-03-23 14:23:06 +08:00
5c7d84117c nacos分组配置问题 #2355 2021-03-23 14:22:37 +08:00
4b9890205e JeecgBoot2.4.3版本发布——企业级低代码平台 2021-03-18 13:43:13 +08:00
d5898139b5 2.3版本oracle、SqlServer数据库脚本 2021-03-18 12:57:39 +08:00
bf438069e2 2.4.3版本发布——企业级低代码平台 2021-03-17 18:46:12 +08:00
c5965b10d8 JeecgBoot2.4.3版本发布——企业级低代码平台 2021-03-17 18:43:44 +08:00
da5ace3397 JeecgBoot2.4.3版本发布——企业级低代码平台 2021-03-17 18:40:08 +08:00
4674097078 单体镜像制作脚本 2021-03-10 14:39:14 +08:00
fea1607f1b 单体镜像制作脚本 2021-03-10 14:35:50 +08:00
d2336bc5e1 依赖jar上传到maven官仓,简化使用 2021-03-09 22:20:12 +08:00
cf0d29557a 重写xxljob避免默认 9999端口冲突 2021-03-09 18:27:34 +08:00
bb4c3c86b0 官仓未同步成功,暂时用jeecg私服 2021-03-09 17:26:15 +08:00
84a6e28677 nacos server本地化采用jar方式启动,简化开发 2021-03-09 11:34:11 +08:00
5b70c1d8b8 nacos server本地化采用jar方式启动,简化开发 2021-03-09 11:33:03 +08:00
f942abe09b 微服务模式相关服务的链接改成host模式 2021-03-09 11:19:51 +08:00
ad4eb300f0 nacos server本地化采用jar方式启动,简化开发 2021-03-09 11:10:01 +08:00
064a5c4a0e nacos server本地化采用jar方式启动,简化开发 2021-03-09 10:33:28 +08:00
6d688a157b nacos server本地化采用jar方式启动,简化开发 2021-03-08 20:30:17 +08:00
d612af5e3b nacos server本地化采用jar方式启动,简化开发 2021-03-08 20:29:36 +08:00
e1c0b0fa38 system服务和demo服务有办法同时使用xxl-job吗 #2313 2021-03-05 17:13:44 +08:00
ac0979c824 system服务和demo服务有办法同时使用xxl-job吗 #2313 2021-03-05 17:08:56 +08:00
78ba7ccba8 system服务和demo服务有办法同时使用xxl-job吗 #2313 2021-03-05 17:02:49 +08:00
b8ff5ebd43 微服务部署下代码生成失效,单体模式下代码生成可用 #2324 2021-03-04 17:39:54 +08:00
5eb2541834 gateway访问默认进入swagger文档首页 2021-03-04 09:48:40 +08:00
462b0d17b1 字典【是否启用】按钮会错误的保存状态 #2311 2021-03-04 09:40:22 +08:00
7cc54084dc docker-compose脚本优化,nacos采用mysql方式自动初始化配置 2021-03-03 15:58:38 +08:00
32297110d9 docker-compose 微服务模式脚本优化 2021-03-02 19:25:55 +08:00
b7717d0461 docker-compose 微服务模式脚本优化 2021-03-02 19:09:39 +08:00
97c078c46a docker-compose 微服务模式脚步优化 2021-03-02 19:09:18 +08:00
17019e6261 docker-compose 镜像制作脚步 2021-03-01 10:31:54 +08:00
4a49479985 关于测边菜单遮挡内容问题详细说明 #2255 2021-02-24 15:26:21 +08:00
e49d76bc80 部门管理员添加上级用户时缺失负责部门列issues/I2SDU1 2021-02-24 15:25:31 +08:00
d6cf2b502b 批量导入部门以后,不能追加下一级部门 #2245 2021-02-24 15:23:13 +08:00
c741d779f2 【严重问题】issues/I37PNL 微服务化后-cloud-demo项目导出无法和字典关联 2021-02-21 15:45:24 +08:00
7f847c9721 删除jeecg-cloud-example例子模块,测试示例重构到jeecg-cloud-system-start中--- 2021-02-21 14:37:07 +08:00
fa2c5ecb73 删除jeecg-cloud-example例子模块,测试示例重构到jeecg-cloud-system-start中--- 2021-02-21 14:36:55 +08:00
eb1578ada3 删除jeecg-cloud-example例子模块,测试示例重构到jeecg-cloud-system-start中--- 2021-02-21 14:36:44 +08:00
90758f3b2a 有个小Bug issues/I3854N 2021-02-21 09:40:03 +08:00
766c48bdbf feign 动态创建client,拦截器执行多次 #2275 2021-02-20 20:59:13 +08:00
d16520cc59 swagger密码访问不生效 #2253 2021-02-17 23:04:22 +08:00
0252213b6e 微服务Feign调用Provider报错Token为空的问题 #2263 2021-02-17 21:05:14 +08:00
ce44147e6e 集成xxl-job-2.2.0之后,注解没有删掉,导致启动报端口冲突 #2228 2021-02-06 12:14:22 +08:00
0ea4ac910a 代码生成单表开关控件有问题 2021-02-06 12:13:28 +08:00
4f61f0ad48 重复check接口,sql注入检查 2021-02-01 20:33:10 +08:00
4a5ff61ef7 导入excel校验示例代码 2021-02-01 20:32:41 +08:00
88a0bb2d2d 文档地址写错了 2021-02-01 20:32:14 +08:00
b153669b69 图片导出报错,本地upload情况下,ImageBasePath未设置 2021-02-01 20:31:59 +08:00
449a7759be JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-25 18:31:46 +08:00
337920964d JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-25 16:43:09 +08:00
2a7946ae42 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-25 15:03:14 +08:00
c233f95f5f JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-25 14:13:20 +08:00
f87cc2d97f 更新数据库脚本 2021-01-25 12:55:15 +08:00
02bb521b8f Cloud demo 命名让人误解,改名为example 2021-01-25 12:38:31 +08:00
53e84ae34b Cloud demo 命名让人误解,更名 2021-01-25 12:32:41 +08:00
d6feeef7b5 Cloud demo 命名让人误解,更名 2021-01-25 12:32:25 +08:00
18fc7b146a Cloud demo 命名让人误解,改名为example 2021-01-25 12:31:42 +08:00
3792f46388 FeignConfig 重复注册问题处理 2021-01-25 12:01:40 +08:00
f35236609c TomcatServletWebServerFactory重复注册问题处理 2021-01-25 11:43:50 +08:00
e46b653bc4 JeecgBoot 2.4.2 积木报表版本发布(注释掉可以不用的测试类) 2021-01-25 11:29:00 +08:00
4437c749ca JeecgBoot 2.4.2 积木报表版本发布(微服务启动报错) 2021-01-25 11:26:50 +08:00
74ebac4967 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 14:44:10 +08:00
a9f21795cb JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 14:12:28 +08:00
a5ca8183cd JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 01:14:43 +08:00
e7970e52bc JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 01:14:13 +08:00
74a9e10ce6 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 01:01:12 +08:00
df5c106d94 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 00:13:15 +08:00
ae0f9edb27 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 00:06:48 +08:00
3d4bb704f1 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-24 00:02:38 +08:00
85efec3730 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-23 23:59:55 +08:00
8b0ee2d0a2 JeecgBoot 2.4.2 积木报表版本发布,基于SpringBoot的低代码平台 2021-01-23 23:59:31 +08:00
41c1572ad8 简化项目默认单体 2021-01-12 19:02:55 +08:00
5d555158fe 文字修改 2021-01-12 18:29:09 +08:00
1fd0b5d4db --date:20201226--for:--升级aliyun短信依赖、aliyun.oss云存储依赖、minio依赖、qiniu云依赖、justauth授权登录okhttp冲突问题----
jeecg-boot-base/jeecg-boot-base-core/org/jeecg/common/util/MinioUtil.java
jeecg-boot-base/jeecg-boot-base-core/pom.xml
pom.xml
2020-12-26 14:12:51 +08:00
693d86cf00 上传图片报错 #2090 cn.hutool.core.lang.Singleton.get(Ljava/lang/String;Lcn/hutool/core/lang/func/Func0;)Ljava/lang/Object; 2020-12-24 22:19:52 +08:00
9a3f872d63 Merge pull request #2107 from Junvary/master
修复  菜单管理-编辑-默认跳转地址   不显示内容的bug
2020-12-24 22:03:49 +08:00
5b82a1aa06 Merge pull request #1967 from tank99tank/char_400
SpringBoot 请求参数包含 [] 特殊符号 返回400状态
2020-12-24 22:01:03 +08:00
3cb88452dc 增量升级脚步语法错误修复 2020-12-15 19:40:39 +08:00
2fa1c7c17b 修复 菜单管理-编辑-默认跳转地址 不显示内容的bug
菜单管理-编辑-默认跳转地址   如果填写了内容并保存,再次编辑时,不会显示这些内容,实际上是有的。
2020-12-15 09:29:09 +08:00
b6a3085083 2,4版本问题如果url中有包括中文(已编码),就报400 Bad Request #2069 2020-12-14 11:06:02 +08:00
8a7fc033cd demo示例设置展示列效果优化
系统设置菜单消失 #2079
Failed to execute 'getComputedStyle' on 'Window
升级代码生成器模板

1、支持自定义下拉树的生成
2、oracle下 三级联动配置了,导致生成报错
3、高级查询支持下拉搜索和下拉多选
4、树表单支持更多的控件生成
2020-12-11 20:06:21 +08:00
e0cf946d18 字典明细禁用样式
上传图片组件大小不一致问题
注册用户总是提示“手机验证码错误” #2081
接口测试支持更多请求方式
菜单删除确认按钮样式变形问题
示例模板优化TableInnerEditList.vue
当用户单租户多部门时存在未setTenant的BUG #2053
2020-12-09 17:44:15 +08:00
c5b33b6bd1 解决前端增加用户模块 密码的校验规则没有生效 #2063 2020-12-08 15:42:43 +08:00
aec00d9ba2 上传中文文件名转为拼音、Long类型精度丢失问题 issues/I24KXI、达梦数据库兼容修改 2020-12-06 17:46:10 +08:00
341830c5a0 2.4版本更新后子表onlChange方法不生效 #2059 2020-12-04 11:23:05 +08:00
ff45fe4858 解决性能监控(请求追踪、tomcat信息)菜单,打开报错的问题 2020-12-03 15:09:17 +08:00
c13ed675a7 单体和微服务启动类加注释 2020-12-02 20:13:45 +08:00
6917e91398 system微服务启动类更名,方便区分单机和微服务 2020-12-02 13:39:20 +08:00
18a5c247d8 解决QRTZ_*表区分大小写的问题 2020-12-02 13:27:49 +08:00
51bf9a7c14 【通知公告】发送指定人,admin收不到信息 2020-12-02 11:15:36 +08:00
8278041aeb 解决SqlServer下online表单普通同步,会删除了表,未保留数据 2020-12-02 10:44:53 +08:00
39bb7a46fd gateway路由采用database方式加载,失败问题解决 2020-12-02 10:12:08 +08:00
1c234fbaff 更新文档地址 2020-12-01 23:01:59 +08:00
ca1f5872be 解决oracle数据库,代码生成报错的问题 2020-12-01 22:50:34 +08:00
2ae3844d5e 解决jeecgboot-mysql-5.7.sql导入不成功 #2051 2020-12-01 17:30:24 +08:00
c2db7691d1 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-30 22:20:59 +08:00
543a49fcb6 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-30 18:59:37 +08:00
df6cf7137c 路由配置修改 2020-11-30 12:44:22 +08:00
d7450cab04 修复发现的 JeecgBoot 2.4版本问题 2020-11-29 17:41:29 +08:00
496d85265b JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 22:04:12 +08:00
b4b1162ea0 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 18:59:33 +08:00
33e39941fb 低代码和零代码在线开发概念 2020-11-28 18:43:50 +08:00
1b5ba9f56b 低代码和零代码在线开发概念 2020-11-28 18:36:06 +08:00
0aadc70e74 JEECG 低代码和零代码在线开发概念 2020-11-28 18:34:19 +08:00
94aed3ade4 JEECG 低代码和零代码在线开发概念 2020-11-28 18:32:16 +08:00
9657eac673 jeecg 零代码和低代码开发介绍 2020-11-28 18:29:31 +08:00
680a8b3c42 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 18:21:31 +08:00
6e6f88620a JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 18:19:18 +08:00
14f4f92d84 低代码模块说明 2020-11-28 18:05:29 +08:00
2c4597c0a9 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 18:03:53 +08:00
757f1cd5a8 低代码功能说明 2020-11-28 18:00:48 +08:00
3c62a58d64 JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 17:56:34 +08:00
bec39867a9 mysql脚本位置文档 2020-11-28 17:48:50 +08:00
dca8713a2e 数据库脚步 2020-11-28 17:46:36 +08:00
a004acee4b JeecgBoot 2.4 微服务正式版本发布,基于SpringBoot的低代码平台 2020-11-28 17:20:10 +08:00
35ef0eff90 文档更新 2020-11-27 14:23:47 +08:00
c70fd3383e 文档更新 2020-11-27 14:20:16 +08:00
3e2f640b68 autopoi导入导出组件系列问题
导出excel实体反射,时间格式转换错误 #1573
配置groupName多生成一列
导出列表数据时, 不支持合并后的单元格.提前结束列的循环了 #1426
Excel导出错误原因,value为""字符串,gitee I249JF
一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B
2020-11-18 22:40:28 +08:00
bf6c5f4623 Merge branch 'master' of https://github.com/zhangdaiscott/jeecg-boot.git 2020-11-14 18:31:43 +08:00
df259385ec jeecgboot-mysql-5.7.sql被别人提交导致不完整 #1985 2020-11-14 18:30:20 +08:00
c5f51a17da Merge pull request #1966 from tank99tank/no_query_params
导出参数没有高级查询参数
2020-11-11 15:47:27 +08:00
94c0610496 SpringBoot 请求参数包含 [] 特殊符号 返回400状态 #1795 2020-11-11 13:04:29 +08:00
ccf4946b70 导出参数没有高级查询参数 #1860 2020-11-11 12:59:12 +08:00
3b4a65ba04 Merge pull request #1731 from CharlieJ0hn/master
修改 qutz_ 前缀的表名为大写,用于修复 jeecg 项目中 Qrutz 表名不区分大小写在 Linux 和 Mac 上的报错
2020-11-10 15:13:07 +08:00
3a8ae4c089 Merge pull request #1900 from Pa-Star-Home/master
bugfix: fix mybatis param import error; fix integer object compare use == error
2020-11-10 15:05:20 +08:00
63048d8c64 bugfix: fix mybatis param import error; fix integer object compare use == error 2020-10-27 15:49:27 +08:00
8775472470 Update jeecgboot-mysql-5.7.sql
修改 qutz_ 前缀的表名为大写,用于修复 jeecg 项目中 Qrutz 表名不区分大小写在 Linux 和 Mac 上的报错
2020-09-14 15:22:41 +08:00
862 changed files with 446898 additions and 24061 deletions

1
.gitattributes vendored
View File

@ -2,3 +2,4 @@
*.css linguist-language=Java *.css linguist-language=Java
*.html linguist-language=Java *.html linguist-language=Java
*.vue linguist-language=Java *.vue linguist-language=Java
*.sql linguist-language=Java

View File

@ -7,12 +7,12 @@
JEECG BOOT 低代码开发平台(前后端分离版本) JEECG BOOT 低代码开发平台(前后端分离版本)
=============== ===============
当前最新版本: 2.3发布日期2020-09-14 当前最新版本: 2.4.5发布日期2021-06-07
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE) [![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://www.jeecg.com) [![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://www.jeecg.com)
[![](https://img.shields.io/badge/version-2.3-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot) [![](https://img.shields.io/badge/version-2.4.5-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot) [![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot) [![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
@ -23,11 +23,14 @@ JEECG BOOT 低代码开发平台(前后端分离版本)
<h3 align="center">Java Low Code Platform for Enterprise web applications</h3> <h3 align="center">Java Low Code Platform for Enterprise web applications</h3>
JeecgBoot 是一款基于代码生成器的`低代码`开发平台,零代码开发!采用前后端分离架构SpringBoot2.xAnt Design&VueMybatis-plusShiroJWT。强大的代码生成器让前后端代码一键生成无需写任何代码! JeecgBoot引领新的开发模式(Online Coding模式-> 代码生成器模式-> 手工MERGE智能开发) 帮助解决Java项目70%的重复工作,让开发更多关注业务逻辑。既能快速提高开发效率,帮助公司节省成本,同时又不失灵活性!JeecgBoot还独创在线开发模式No代码概念在线表单配置表单设计器、移动配置能力、工作流配置在线设计流程、报表配置能力、在线图表配置、插件能力可插拔等等 JeecgBoot 是一款基于代码生成器的`低代码平台`前后端分离架构 SpringBoot2.xSpringCloudAnt Design&VueMybatis-plusShiroJWT,支持微服务。强大的代码生成器让前后端代码一键生成,实现低代码开发! JeecgBoot 引领新的低代码开发模式(OnlineCoding-> 代码生成器-> 手工MERGE) 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省研发成本,同时又不失灵活性!
JeecgBoot 提供了一系列`低代码模块`,实现在线开发`真正的零代码`Online表单开发、Online报表、报表配置能力、在线图表设计、大屏设计、移动配置能力、表单设计器、在线设计流程、流程自动化配置、插件能力可插拔等等
`JEECG宗旨是:` 简单功能由Online Coding配置实现`零代码开发`(在线配置表单、在线配置报表、在线图表设计、在线设计流程、在线设计表单),复杂功能由代码生成器生成进行手工Merge既保证了`智能`又兼顾`灵活`; `JEECG宗旨是:` 简单功能由OnlineCoding配置实现,做到`零代码开发`复杂功能由代码生成器生成进行手工Merge 实现`低代码开发`,既保证了`智能`又兼顾`灵活`;实现了低代码开发的同时又支持灵活编码,解决了当前低代码产品普遍不灵活的弊端!
业务流程采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计松耦合、并支持任务节点灵活配置既保证了公司流程的保密性又减少了开发人员的工作量。
`JEECG业务流程:` 采用工作流来实现、扩展出任务接口,供开发编写业务逻辑,表单提供多种解决方案: 表单设计器、online配置表单、编码表单。同时实现了流程与表单的分离设计松耦合、并支持任务节点灵活配置既保证了公司流程的保密性又减少了开发人员的工作量。
适用项目 适用项目
@ -41,13 +44,15 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
- 技术官网: [http://www.jeecg.com](http://www.jeecg.com) - 技术官网: [http://www.jeecg.com](http://www.jeecg.com)
- 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com/1273753) - 开发文档: [http://doc.jeecg.com](http://doc.jeecg.com)
- 微服务启动: [单体升级为微服务启动文档2.4+](http://doc.jeecg.com/2043906)
- 在线演示 [http://boot.jeecg.com](http://boot.jeecg.com) - 在线演示 [http://boot.jeecg.com](http://boot.jeecg.com)
- 视频教程 [JeecgBoot入门视频教程](http://www.jeecg.com/doc/video) - 视频教程 [JeecgBoot入门视频](http://www.jeecg.com/doc/video)
- 常见问题: [入门常见问题大全](http://bbs.jeecg.com/forum.php?mod=viewthread&tid=7816&extra=page%3D1) - 常见问题: [入门常见问题Q&A](http://jeecg.com/doc/qa)
- 更新日志: [版本日志](http://www.jeecg.com/doc/log) - 更新日志: [版本日志](http://www.jeecg.com/doc/log)
@ -56,7 +61,7 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
交流互动 交流互动
----------------------------------- -----------------------------------
- QQ交流群 ③816531124、②769925425、①284271917 - QQ交流群 ④774126647、③816531124(满)、②769925425、①284271917
- 反馈问题: [反馈问题请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new) - 反馈问题: [反馈问题请按格式发Issues](https://github.com/zhangdaiscott/jeecg-boot/issues/new)
@ -68,7 +73,7 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
为什么选择JEECG-BOOT? 为什么选择JEECG-BOOT?
----------------------------------- -----------------------------------
* 1.采用最新主流前后分离框架Springboot+Mybatis+antd容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发; * 1.采用最新主流前后分离框架Springboot+Mybatis+antd容易上手; 代码生成器依赖性低,灵活的扩展能力,可快速实现二次开发;
* 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywarking),提供切换机制支持单体和微服务自由切换 * 2.支持微服务SpringCloud Alibaba(Nacos、Gateway、Sentinel、Skywalking),提供切换机制支持单体和微服务自由切换
* 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用; * 3.开发效率高,采用代码生成器,单表、树列表、一对多、一对一等数据模型,增删改查功能一键生成,菜单配置直接使用;
* 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套) * 4.代码生成器提供强大模板机制,支持自定义模板,目前提供四套风格模板(单表两套、树模型一套、一对多三套)
* 5.代码生成器非常智能在线业务建模、在线配置、所见即所得支持23种类控件一键生成前后端代码大幅度提升开发效率不再为重复工作发愁。 * 5.代码生成器非常智能在线业务建模、在线配置、所见即所得支持23种类控件一键生成前后端代码大幅度提升开发效率不再为重复工作发愁。
@ -85,7 +90,7 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
* 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等); * 16.页面校验自动生成(必须输入、数字校验、金额校验、时间空间等);
* 17.支持SAAS服务模式提供SaaS多租户架构方案。 * 17.支持SAAS服务模式提供SaaS多租户架构方案。
* 18.分布式文件服务集成minio、阿里OSS等优秀的第三方提供便捷的文件上传与管理同时也支持本地存储。 * 18.分布式文件服务集成minio、阿里OSS等优秀的第三方提供便捷的文件上传与管理同时也支持本地存储。
* 19.主流数据库兼容一套代码完全兼容Mysql、Postgresql、Oracle三大主流数据库。 * 19.主流数据库兼容一套代码完全兼容Mysql、Postgresql、Oracle、Sqlserver、MariaDB、达梦等主流数据库。
* 20.集成工作流activiti并实现了只需在页面配置流程转向可极大的简化bpm工作流的开发用bpm的流程设计器画出了流程走向一个工作流基本就完成了只需写很少量的java代码 * 20.集成工作流activiti并实现了只需在页面配置流程转向可极大的简化bpm工作流的开发用bpm的流程设计器画出了流程走向一个工作流基本就完成了只需写很少量的java代码
* 21.低代码能力在线流程设计采用开源Activiti流程引擎实现在线画流程,自定义表单,表单挂靠,业务流转 * 21.低代码能力在线流程设计采用开源Activiti流程引擎实现在线画流程,自定义表单,表单挂靠,业务流转
* 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据; * 22.多数据源:及其简易的使用方式,在线配置数据源配置,便捷的从其他数据抓取数据;
@ -130,15 +135,17 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
#### 后端 #### 后端
- 基础框架Spring Boot 2.1.3.RELEASE \ Spring Cloud Alibaba 2.1.0.RELEASE - 基础框架Spring Boot 2.3.5.RELEASE
- 持久层框架Mybatis-plus_3.1.2 - 微服务框架: Spring Cloud Alibaba 2.2.3.RELEASE
- 安全框架Apache Shiro 1.4.0Jwt_3.7.0 - 持久层框架Mybatis-plus 3.4.1
- 微服务技术Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywarking - 安全框架Apache Shiro 1.7.0Jwt 3.11.0
- 数据库连接池阿里巴巴Druid 1.1.10 - 微服务技术栈Spring Cloud Alibaba、Nacos、Gateway、Sentinel、Skywalking
- 数据库连接池阿里巴巴Druid 1.1.22
- 缓存框架redis - 缓存框架redis
@ -182,7 +189,7 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
├─消息中心 ├─消息中心
│ ├─消息管理 │ ├─消息管理
│ ├─模板管理 │ ├─模板管理
├─智能化功能 ├─代码生成器(低代码)
│ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音) │ ├─代码生成器功能(一键生成前后端代码,生成后无需修改直接用,绝对是后端开发福音)
│ ├─代码生成器模板提供4套模板分别支持单表和一对多模型不同风格选择 │ ├─代码生成器模板提供4套模板分别支持单表和一对多模型不同风格选择
│ ├─代码生成器模板生成代码自带excel导入导出 │ ├─代码生成器模板生成代码自带excel导入导出
@ -271,14 +278,19 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
│ ├─提供单点登录CAS集成方案 │ ├─提供单点登录CAS集成方案
│ ├─提供APP发布方案 │ ├─提供APP发布方案
│ ├─集成Websocket消息通知机制 │ ├─集成Websocket消息通知机制
├─Online在线低代码开发(暂未开源) ├─Online在线开发(低代码)
│ ├─Online在线表单 - 功能已开放 │ ├─Online在线表单 - 功能已开放
│ ├─在线代码生成器 - 功能已开放 │ ├─Online代码生成器 - 功能已开放
│ ├─Online在线报表 - 功能已开放 │ ├─Online在线报表 - 功能已开放
│ ├─多数据源管理 │ ├─Online在线图表(暂不开源)
│ ├─Online在线图表 │ ├─Online图表模板配置(暂不开源)
│ ├─Online图表模板配置 │ ├─Online布局设计(暂不开源)
│ ├─高级表单设计器 │ ├─多数据源管理 - 功能已开放
├─积木报表设计器(低代码)
│ ├─打印设计器
│ ├─数据报表设计
│ ├─图形报表设计支持echart
│ ├─大屏设计器(暂不开源)
│─流程模块功能 (暂不开源) │─流程模块功能 (暂不开源)
│ ├─流程设计器 │ ├─流程设计器
│ ├─在线表单设计 │ ├─在线表单设计
@ -297,14 +309,14 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
``` ```
## 微服务整体解决方案(2.3+版本) ## 微服务整体解决方案(2.4+版本)
1、服务注册和发现 Nacos √ 1、服务注册和发现 Nacos √
2、统一配置中心 Nacos √ 2、统一配置中心 Nacos √
3、路由网关 gateway √ 3、路由网关 gateway(三种加载方式)
4、分布式 http feign √ 4、分布式 http feign √
@ -314,27 +326,30 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
7、统一权限控制 JWT + Shiro √ 7、统一权限控制 JWT + Shiro √
8、服务监控 SpringBootAdmin [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1761865) 8、服务监控 SpringBootAdmin
9、链路跟踪 Skywarking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670) 9、链路跟踪 Skywalking [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1771670)
10、消息中间件 SpringCloudStream+RabbitMQ [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1744409) 10、消息中间件 RabbitMQ √
11、分布式任务 xxl-job [参考文档](https://www.kancloud.cn/zhangdaiscott/jeecgcloud/1801263) 11、分布式任务 xxl-job
12、分布式事务 Seata 12、分布式事务 Seata
13、分布式日志 elk + kafa 13、分布式日志 elk + kafka
14、支持 docker-compose、k8s、jenkins 14、支持 docker-compose、k8s、jenkins
15、CAS 单点登录 √ 15、CAS 单点登录 √
16、路由限流 √
#### 微服务架构图 #### 微服务架构图
![微服务架构图](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/jeecgboot-weifuwu-cloud.png "在这里输入图片标题") ![微服务架构图](https://jeecgos.oss-cn-beijing.aliyuncs.com/files/jeecgboot-weifuwu-cloud.png "在这里输入图片标题")
### Jeecg Boot 产品功能蓝图 ### Jeecg Boot 产品功能蓝图
![功能蓝图](https://static.jeecg.com/upload/test/Jeecg-Boot-lantu202005_1590912449914.jpg "在这里输入图片标题") ![功能蓝图](https://jeecgos.oss-cn-beijing.aliyuncs.com/upload/test/Jeecg-Boot-lantu202005_1590912449914.jpg "在这里输入图片标题")
后台开发环境和依赖 后台开发环境和依赖
@ -344,7 +359,7 @@ Jeecg-Boot低代码开发平台可以应用在任何J2EE项目的开发中
- jdk8 - jdk8
- mysql - mysql
- redis - redis
- 数据库脚本jeecg-boot\docs\jeecg-boot-mysql.sql - 数据库脚本jeecg-boot/db/jeecgboot-mysql-5.7.sql
- 默认登录账号: admin/123456 - 默认登录账号: admin/123456

View File

@ -0,0 +1,3 @@
NODE_ENV=production
VUE_APP_PLATFORM_NAME=JeecgBoot 企业级低代码平台
VUE_APP_SSO=false

View File

@ -0,0 +1,4 @@
NODE_ENV=development
VUE_APP_API_BASE_URL=http://localhost:8080/jeecg-boot
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview

View File

@ -0,0 +1,4 @@
NODE_ENV=production
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

View File

@ -0,0 +1,4 @@
NODE_ENV=production
VUE_APP_API_BASE_URL=http://boot.jeecg.com:8080/jeecg-boot
VUE_APP_CAS_BASE_URL=http://cas.example.org:8443/cas
VUE_APP_ONLINE_BASE_URL=http://fileview.jeecg.com/onlinePreview

View File

@ -1,13 +1,13 @@
Ant Design Jeecg Vue Ant Design Jeecg Vue
==== ====
当前最新版本: 2.3.0发布日期20200914 当前最新版本: 2.4.5发布日期20210607
Overview Overview
---- ----
基于 [Ant Design of Vue](https://vuecomponent.github.io/ant-design-vue/docs/vue/introduce-cn/) 实现的 Ant Design Pro Vue 版 基于 [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一贯的强大 前端页面代码和后端功能代码一键生成不需要写任何代码保持jeecg一贯的强大
@ -111,7 +111,7 @@ Docker 镜像使用
``` ```
# 1.修改前端项目的后台域名 # 1.修改前端项目的后台域名
public/index.html .env.development
域名改成: http://jeecg-boot-system:8080/jeecg-boot 域名改成: http://jeecg-boot-system:8080/jeecg-boot
# 2.先进入打包前端项目 # 2.先进入打包前端项目

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,17 @@
{ {
"name": "vue-antd-jeecg", "name": "vue-antd-jeecg",
"version": "2.3.0", "version": "2.4.5",
"private": true, "private": true,
"scripts": { "scripts": {
"pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ", "pre": "cnpm install || yarn --registry https://registry.npm.taobao.org || npm install --registry https://registry.npm.taobao.org ",
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build:test": "vue-cli-service build --mode test",
"build": "vue-cli-service build", "build": "vue-cli-service build",
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"ant-design-vue": "^1.6.3", "ant-design-vue": "^1.7.2",
"@jeecg/antd-online-mini": "2.3.0", "@jeecg/antd-online-mini": "2.4.5-RC",
"@antv/data-set": "^0.11.4", "@antv/data-set": "^0.11.4",
"viser-vue": "^2.4.8", "viser-vue": "^2.4.8",
"axios": "^0.18.0", "axios": "^0.18.0",
@ -39,11 +40,11 @@
"@toast-ui/editor": "^2.1.2", "@toast-ui/editor": "^2.1.2",
"vue-area-linkage": "^5.1.0", "vue-area-linkage": "^5.1.0",
"area-data": "^5.0.6", "area-data": "^5.0.6",
"jsoneditor": "^9.0.0",
"dom-align": "1.12.0", "dom-align": "1.12.0",
"xe-utils": "2.4.8", "xe-utils": "2.4.8",
"vxe-table": "2.9.13", "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": { "devDependencies": {
"@babel/polyfill": "^7.2.5", "@babel/polyfill": "^7.2.5",
@ -58,8 +59,7 @@
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"vue-template-compiler": "^2.6.10", "vue-template-compiler": "^2.6.10",
"html-webpack-plugin": "^4.2.0", "html-webpack-plugin": "^4.2.0",
"compression-webpack-plugin": "^3.1.0", "compression-webpack-plugin": "^3.1.0"
"babel-plugin-import": "^1.13.0"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

File diff suppressed because one or more lines are too long

View File

@ -2421,7 +2421,9 @@ a.listItemMetaTitle {
color: rgba(0, 0, 0, 0.85); color: rgba(0, 0, 0, 0.85);
} }
.main { .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 { .main .leftmenu {
border-right: 1px solid #e8e8e8; border-right: 1px solid #e8e8e8;
@ -7687,9 +7689,6 @@ font.weak {
color: @primary-color; color: @primary-color;
} }
} }
.ant-menu-submenu-selected {
color: @primary-color;
}
// begin -------- JAreaLinkage 三级联动样式 -------------- // begin -------- JAreaLinkage 三级联动样式 --------------
.cascader-menu-list .cascader-menu-option.hover, .cascader-menu-list .cascader-menu-option.hover,

View File

@ -5,10 +5,9 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <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"> <link rel="icon" href="<%= BASE_URL %>logo.png">
<script src="/cdn/babel-polyfill/polyfill_7_2_5.js"></script> <script src="<%= BASE_URL %>cdn/babel-polyfill/polyfill_7_2_5.js"></script>
<style> <style>
html, html,
body, body,
@ -243,23 +242,16 @@
<!-- 全局配置 --> <!-- 全局配置 -->
<script> <script>
window._CONFIG = {}; window._CONFIG = {};
window._CONFIG['domianURL'] = 'http://127.0.0.1:8080/jeecg-boot';
window._CONFIG['casPrefixUrl'] = 'http://cas.example.org:8443/cas';
window._CONFIG['onlinePreviewDomainURL'] = 'http://fileview.jeecg.com/onlinePreview'
window._CONFIG['staticDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/static';
//window._CONFIG['downloadUrl'] = window._CONFIG['domianURL'] + '/sys/common/download';
window._CONFIG['pdfDomainURL'] = window._CONFIG['domianURL'] + '/sys/common/pdf/pdfPreviewIframe';
</script> </script>
</head> </head>
<body> <body>
<!-- built files will be auto injected -->
<div id="app"> <div id="app">
<div id="loader-wrapper"> <div id="loader-wrapper">
<div id="loader"></div> <div id="loader"></div>
<div class="loader-section section-left"></div> <div class="loader-section section-left"></div>
<div class="loader-section section-right"></div> <div class="loader-section section-right"></div>
<div class="load_title">正在加载 Jeecg-Boot 快速开发平台,请耐心等待 <div class="load_title">正在加载 JeecgBoot 低代码平台,请耐心等待
</div> </div>
</div> </div>

View File

@ -2,17 +2,9 @@ import { getAction, deleteAction, putAction, postAction, httpAction } from '@/ap
import Vue from 'vue' import Vue from 'vue'
import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types" import {UI_CACHE_DB_DICT_DATA } from "@/store/mutation-types"
////根路径
// const doMian = "/jeecg-boot/";
////图片预览请求地址
// const imgView = "http://localhost:8080/jeecg-boot/sys/common/view/";
//角色管理 //角色管理
const addRole = (params)=>postAction("/sys/role/add",params); const addRole = (params)=>postAction("/sys/role/add",params);
const editRole = (params)=>putAction("/sys/role/edit",params); const editRole = (params)=>putAction("/sys/role/edit",params);
// const getRoleList = (params)=>getAction("/sys/role/list",params);
// const deleteRole = (params)=>deleteAction("/sys/role/delete",params);
// const deleteRoleList = (params)=>deleteAction("/sys/role/deleteBatch",params);
const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params); const checkRoleCode = (params)=>getAction("/sys/role/checkRoleCode",params);
const queryall = (params)=>getAction("/sys/role/queryall",params); const queryall = (params)=>getAction("/sys/role/queryall",params);
@ -21,8 +13,6 @@ const addUser = (params)=>postAction("/sys/user/add",params);
const editUser = (params)=>putAction("/sys/user/edit",params); const editUser = (params)=>putAction("/sys/user/edit",params);
const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params); const queryUserRole = (params)=>getAction("/sys/user/queryUserRole",params);
const getUserList = (params)=>getAction("/sys/user/list",params); const getUserList = (params)=>getAction("/sys/user/list",params);
// const deleteUser = (params)=>deleteAction("/sys/user/delete",params);
// const deleteUserList = (params)=>deleteAction("/sys/user/deleteBatch",params);
const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params); const frozenBatch = (params)=>putAction("/sys/user/frozenBatch",params);
//验证用户是否存在 //验证用户是否存在
const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params); const checkOnlyUser = (params)=>getAction("/sys/user/checkOnlyUser",params);
@ -33,27 +23,22 @@ const changePassword = (params)=>putAction("/sys/user/changePassword",params);
const addPermission= (params)=>postAction("/sys/permission/add",params); const addPermission= (params)=>postAction("/sys/permission/add",params);
const editPermission= (params)=>putAction("/sys/permission/edit",params); const editPermission= (params)=>putAction("/sys/permission/edit",params);
const getPermissionList = (params)=>getAction("/sys/permission/list",params); const getPermissionList = (params)=>getAction("/sys/permission/list",params);
/*update_begin author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params); const getSystemMenuList = (params)=>getAction("/sys/permission/getSystemMenuList",params);
const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params); const getSystemSubmenu = (params)=>getAction("/sys/permission/getSystemSubmenu",params);
const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params) const getSystemSubmenuBatch = (params) => getAction('/sys/permission/getSystemSubmenuBatch', params)
/*update_end author:wuxianquan date:20190908 for:添加查询一级菜单和子菜单查询api */
// const deletePermission = (params)=>deleteAction("/sys/permission/delete",params);
// const deletePermissionList = (params)=>deleteAction("/sys/permission/deleteBatch",params);
const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params); const queryTreeList = (params)=>getAction("/sys/permission/queryTreeList",params);
const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params); const queryTreeListForRole = (params)=>getAction("/sys/role/queryTreeList",params);
const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params); const queryListAsync = (params)=>getAction("/sys/permission/queryListAsync",params);
const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params); const queryRolePermission = (params)=>getAction("/sys/permission/queryRolePermission",params);
const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params); const saveRolePermission = (params)=>postAction("/sys/permission/saveRolePermission",params);
//const queryPermissionsByUser = (params)=>getAction("/sys/permission/queryByUser",params); const queryPermissionsByUser = ()=>getAction("/sys/permission/getUserPermissionByToken");
const queryPermissionsByUser = (params)=>getAction("/sys/permission/getUserPermissionByToken",params);
const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params); const loadAllRoleIds = (params)=>getAction("/sys/permission/loadAllRoleIds",params);
const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params); const getPermissionRuleList = (params)=>getAction("/sys/permission/getPermRuleListByPermId",params);
const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params); const queryPermissionRule = (params)=>getAction("/sys/permission/queryPermissionRule",params);
// 部门管理 // 部门管理
const queryDepartTreeList = (params)=>getAction("/sys/sysDepart/queryTreeList",params); 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 queryIdTree = (params)=>getAction("/sys/sysDepart/queryIdTree",params);
const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params); const queryParentName = (params)=>getAction("/sys/sysDepart/queryParentName",params);
const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params); const searchByKeywords = (params)=>getAction("/sys/sysDepart/searchBy",params);
@ -68,21 +53,15 @@ const saveDeptRolePermission = (params)=>postAction("/sys/sysDepartPermission/sa
const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params); const queryMyDepartTreeList = (params)=>getAction("/sys/sysDepart/queryMyDeptTreeList",params);
//日志管理 //日志管理
//const getLogList = (params)=>getAction("/sys/log/list",params);
const deleteLog = (params)=>deleteAction("/sys/log/delete",params); const deleteLog = (params)=>deleteAction("/sys/log/delete",params);
const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params); const deleteLogList = (params)=>deleteAction("/sys/log/deleteBatch",params);
//数据字典 //数据字典
const addDict = (params)=>postAction("/sys/dict/add",params); const addDict = (params)=>postAction("/sys/dict/add",params);
const editDict = (params)=>putAction("/sys/dict/edit",params); const editDict = (params)=>putAction("/sys/dict/edit",params);
//const getDictList = (params)=>getAction("/sys/dict/list",params);
const treeList = (params)=>getAction("/sys/dict/treeList",params); const treeList = (params)=>getAction("/sys/dict/treeList",params);
// const delDict = (params)=>deleteAction("/sys/dict/delete",params);
//const getDictItemList = (params)=>getAction("/sys/dictItem/list",params);
const addDictItem = (params)=>postAction("/sys/dictItem/add",params); const addDictItem = (params)=>postAction("/sys/dictItem/add",params);
const editDictItem = (params)=>putAction("/sys/dictItem/edit",params); const editDictItem = (params)=>putAction("/sys/dictItem/edit",params);
//const delDictItem = (params)=>deleteAction("/sys/dictItem/delete",params);
//const delDictItemList = (params)=>deleteAction("/sys/dictItem/deleteBatch",params);
//字典标签专用通过code获取字典数组 //字典标签专用通过code获取字典数组
export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params); export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItems/${code}`,params);
@ -90,7 +69,7 @@ export const ajaxGetDictItems = (code, params)=>getAction(`/sys/dict/getDictItem
function getDictItemsFromCache(dictCode) { function getDictItemsFromCache(dictCode) {
if (Vue.ls.get(UI_CACHE_DB_DICT_DATA) && Vue.ls.get(UI_CACHE_DB_DICT_DATA)[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]; 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; return dictItems;
} }
} }
@ -101,14 +80,10 @@ const doReovkeData = (params)=>getAction("/sys/annountCement/doReovkeData",param
//获取系统访问量 //获取系统访问量
const getLoginfo = (params)=>getAction("/sys/loginfo",params); const getLoginfo = (params)=>getAction("/sys/loginfo",params);
const getVisitInfo = (params)=>getAction("/sys/visitInfo",params); const getVisitInfo = (params)=>getAction("/sys/visitInfo",params);
//数据日志访问
// const getDataLogList = (params)=>getAction("/sys/dataLog/list",params);
// 根据部门主键查询用户信息 // 根据部门主键查询用户信息
const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params); const queryUserByDepId = (params)=>getAction("/sys/user/queryUserByDepId",params);
// 查询用户角色表里的所有信息
// const queryUserRoleMap = (params)=>getAction("/sys/user/queryUserRoleMap",params);
// 重复校验 // 重复校验
const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params); const duplicateCheck = (params)=>getAction("/sys/duplicate/check",params);
// 加载分类字典 // 加载分类字典
@ -151,6 +126,7 @@ export {
getPermissionRuleList, getPermissionRuleList,
queryPermissionRule, queryPermissionRule,
queryDepartTreeList, queryDepartTreeList,
queryDepartTreeSync,
queryIdTree, queryIdTree,
queryParentName, queryParentName,
searchByKeywords, searchByKeywords,

View File

@ -36,15 +36,15 @@ export function getSmsCaptcha(parameter) {
}) })
} }
export function getInfo() { // export function getInfo() {
return axios({ // return axios({
url: '/api/user/info', // url: '/api/user/info',
method: 'get', // method: 'get',
headers: { // headers: {
'Content-Type': 'application/json;charset=UTF-8' // 'Content-Type': 'application/json;charset=UTF-8'
} // }
}) // })
} // }
export function logout(logoutToken) { export function logout(logoutToken) {
return axios({ return axios({
@ -60,14 +60,28 @@ export function logout(logoutToken) {
/** /**
* 第三方登录 * 第三方登录
* @param token * @param token
* @param thirdType
* @returns {*} * @returns {*}
*/ */
export function thirdLogin(token) { export function thirdLogin(token,thirdType) {
return axios({ return axios({
url: `/thirdLogin/getLoginUser/${token}`, url: `/sys/thirdLogin/getLoginUser/${token}/${thirdType}`,
method: 'get', method: 'get',
headers: { headers: {
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
} }
}) })
} }
/**
* 强退其他账号
* @param token
* @returns {*}
*/
export function forceLogout(parameter) {
return axios({
url: '/sys/online/forceLogout',
method: 'post',
data: parameter
})
}

View File

@ -1,31 +1,42 @@
import Vue from 'vue' import Vue from 'vue'
import { axios } from '@/utils/request' import { axios } from '@/utils/request'
import signMd5Utils from '@/utils/encryption/signMd5Utils'
const api = { const api = {
user: '/api/user', user: '/mock/api/user',
role: '/api/role', role: '/mock/api/role',
service: '/api/service', service: '/mock/api/service',
permission: '/api/permission', permission: '/mock/api/permission',
permissionNoPager: '/api/permission/no-pager' permissionNoPager: '/mock/api/permission/no-pager'
} }
export default api export default api
//post //post
export function postAction(url,parameter) { export function postAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({ return axios({
url: url, url: url,
method:'post' , method:'post' ,
data: parameter data: parameter,
headers: signHeader
}) })
} }
//post method= {post | put} //post method= {post | put}
export function httpAction(url,parameter,method) { export function httpAction(url,parameter,method) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({ return axios({
url: url, url: url,
method:method , method:method ,
data: parameter data: parameter,
headers: signHeader
}) })
} }
@ -40,10 +51,15 @@ export function putAction(url,parameter) {
//get //get
export function getAction(url,parameter) { export function getAction(url,parameter) {
let sign = signMd5Utils.getSign(url, parameter);
//将签名和时间戳,添加在请求接口 Header
let signHeader = {"X-Sign": sign,"X-TIMESTAMP": signMd5Utils.getDateTimeToString()};
return axios({ return axios({
url: url, url: url,
method: 'get', method: 'get',
params: parameter params: parameter,
headers: signHeader
}) })
} }

View File

@ -5,6 +5,7 @@ import store from '@/store'
* 单点登录 * 单点登录
*/ */
const init = (callback) => { const init = (callback) => {
if (process.env.VUE_APP_SSO == 'true') {
console.log("-------单点登录开始-------"); console.log("-------单点登录开始-------");
let token = Vue.ls.get(ACCESS_TOKEN); let token = Vue.ls.get(ACCESS_TOKEN);
let st = getUrlParam("ticket"); let st = getUrlParam("ticket");
@ -20,6 +21,9 @@ const init = (callback) => {
} }
} }
console.log("-------单点登录结束-------"); console.log("-------单点登录结束-------");
}else{
callback && callback()
}
}; };
const SSO = { const SSO = {
init: init init: init

View File

@ -33,7 +33,7 @@
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile"> <a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
<span><a-icon type="delete"/>&nbsp;删除</span> <span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item> </a-menu-item>
<a-menu-item @click="handleMoreOperation"> <a-menu-item @click="handleMoreOperation(originColumn)">
<span><a-icon type="bars"/> 更多</span> <span><a-icon type="bars"/> 更多</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -55,7 +55,7 @@
> >
<a-button icon="upload">{{originColumn.btnText || '上传文件'}}</a-button> <a-button icon="upload">{{originColumn.btnText || '上传文件'}}</a-button>
</a-upload> </a-upload>
<j-file-pop ref="filePop" @ok="handleFileSuccess"/> <j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"/>
</div> </div>
</template> </template>
@ -75,6 +75,7 @@
data() { data() {
return { return {
innerFile: null, innerFile: null,
number:0,
} }
}, },
computed: { computed: {
@ -137,7 +138,18 @@
methods: { methods: {
// 点击更多按钮 // 点击更多按钮
handleMoreOperation() { handleMoreOperation(originColumn) {
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if (originColumn.number) {
this.number = originColumn.number
} else {
this.number = 0
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(originColumn && originColumn.fieldExtendJson){
let json = JSON.parse(originColumn.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
let path = '' let path = ''
if (this.innerFile) { if (this.innerFile) {
path = this.innerFile.path path = this.innerFile.path

View File

@ -41,7 +41,7 @@
<a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile"> <a-menu-item v-if="originColumn.allowRemove !== false" @click="handleClickDeleteFile">
<span><a-icon type="delete"/>&nbsp;删除</span> <span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item> </a-menu-item>
<a-menu-item @click="handleMoreOperation"> <a-menu-item @click="handleMoreOperation(originColumn)">
<span><a-icon type="bars"/> 更多</span> <span><a-icon type="bars"/> 更多</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -63,7 +63,7 @@
> >
<a-button icon="upload">{{originColumn.btnText || '上传图片'}}</a-button> <a-button icon="upload">{{originColumn.btnText || '上传图片'}}</a-button>
</a-upload> </a-upload>
<j-file-pop ref="filePop" @ok="handleFileSuccess"/> <j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"/>
</div> </div>
</template> </template>
@ -83,6 +83,7 @@
data() { data() {
return { return {
innerFile: null, innerFile: null,
number:0
} }
}, },
computed: { computed: {
@ -146,7 +147,18 @@
methods: { methods: {
// 点击更多按钮 // 点击更多按钮
handleMoreOperation() { handleMoreOperation(originColumn) {
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if (originColumn.number) {
this.number = originColumn.number
} else {
this.number = 0
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(originColumn && originColumn.fieldExtendJson){
let json = JSON.parse(originColumn.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
let path = '' let path = ''
if (this.innerFile) { if (this.innerFile) {
path = this.innerFile.path path = this.innerFile.path

View File

@ -6,7 +6,7 @@
</template> </template>
<script> <script>
import JVxeCellMixins, { vModel, dispatchEvent } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins' import JVxeCellMixins, { dispatchEvent, vModel } from '@/components/jeecg/JVxeTable/mixins/JVxeCellMixins'
export default { export default {
name: 'JVxePopupCell', name: 'JVxePopupCell',
@ -22,6 +22,8 @@
orgFields: col.orgFields, orgFields: col.orgFields,
destFields: col.destFields, destFields: col.destFields,
groupId: caseId, groupId: caseId,
param: col.param,
sorter: col.sorter,
} }
}, },
}, },
@ -48,7 +50,9 @@
// 【组件增强】注释详见JVxeCellMixins.js // 【组件增强】注释详见JVxeCellMixins.js
enhanced: { enhanced: {
aopEvents: { aopEvents: {
editActived: event => dispatchEvent(event, 'ant-input'), editActived(event) {
dispatchEvent.call(this, event, 'ant-input')
},
}, },
}, },
} }

View File

@ -254,7 +254,9 @@ export const DictSearchInputCell = {
// 【组件增强】注释详见JVxeCellMixins.js // 【组件增强】注释详见JVxeCellMixins.js
enhanced: { enhanced: {
aopEvents: { aopEvents: {
editActived: event => dispatchEvent(event, 'ant-select'), editActived(event) {
dispatchEvent.call(this, event, 'ant-select')
},
}, },
} }
} }

View File

@ -39,5 +39,5 @@ UserMenu.vue:首页右上侧的内容
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201226_laQK.png "在这里输入图片标题") ![输入图片说明](https://static.oschina.net/uploads/img/201904/12201226_laQK.png "在这里输入图片标题")
####16.trend包 趋势显示组件(如下图) ####16.trend包 趋势显示组件(如下图)
![输入图片说明](https://static.oschina.net/uploads/img/201904/12201600_Wo8K.png "在这里输入图片标题") ![输入图片说明](https://static.oschina.net/uploads/img/201904/12201600_Wo8K.png "在这里输入图片标题")
![corn表达式](https://oscimg.oschina.net/oscnet/661f9ac09016395f9f49286143af3241623.jpg) ![cron表达式](https://oscimg.oschina.net/oscnet/661f9ac09016395f9f49286143af3241623.jpg)
![corn控件添加清除按钮](https://oscimg.oschina.net/oscnet/15096e49f2e29bd829e304d56770025d03c.jpg) ![cron控件添加清除按钮](https://oscimg.oschina.net/oscnet/15096e49f2e29bd829e304d56770025d03c.jpg)

View File

@ -12,13 +12,13 @@ export default class Area {
let arr = [] let arr = []
const province = pcaa['86'] const province = pcaa['86']
Object.keys(province).map(key=>{ 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]; const city = pcaa[key];
Object.keys(city).map(key2=>{ 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]; const qu = pcaa[key2];
Object.keys(qu).map(key3=>{ 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 '' return ''
} }
let arr = [] let arr = []
this.getAreaBycode(code,arr); this.getAreaBycode(code, arr, 3);
return arr.join('/') return arr.join('/')
} }
getRealCode(code){ getRealCode(code){
let arr = [] let arr = []
this.getPcode(code, arr) this.getPcode(code, arr, 3)
return arr; return arr;
} }
getPcode(id, arr){ getPcode(id, arr, index){
for(let item of this.all){ for(let item of this.all){
if(item.id === id){ if(item.id === id && item.index == index){
arr.unshift(id) arr.unshift(id)
if(item.pid != '86'){ if(item.pid != '86'){
this.getPcode(item.pid,arr) this.getPcode(item.pid, arr, --index)
} }
} }
} }
} }
getAreaBycode(code,arr){ getAreaBycode(code, arr, index){
//console.log("this.all.length",this.all)
for(let item of this.all){ for(let item of this.all){
if(item.id === code){ if(item.id === code && item.index == index){
arr.unshift(item.text); arr.unshift(item.text);
this.getAreaBycode(item.pid,arr) if(item.pid != '86'){
this.getAreaBycode(item.pid, arr, --index)
}
} }
} }
} }

View File

@ -25,7 +25,6 @@
props: { props: {
dictCode: String, dictCode: String,
placeholder: String, placeholder: String,
triggerChange: Boolean,
disabled: Boolean, disabled: Boolean,
value: [String, Number], value: [String, Number],
type: String, type: String,
@ -82,19 +81,15 @@
} }
}) })
}, },
handleInput(e) { handleInput(e='') {
let val; let val;
if(this.tagType=="radio"){ if(Object.keys(e).includes('target')){
val = e.target.value val = e.target.value
}else{ }else{
val = e val = e
} }
console.log(val); console.log(val);
if(this.triggerChange){
this.$emit('change', val); this.$emit('change', val);
}else{
this.$emit('input', val);
}
}, },
setCurrentDictOptions(dictOptions){ setCurrentDictOptions(dictOptions){
this.dictOptions = dictOptions this.dictOptions = dictOptions
@ -102,6 +97,10 @@
getCurrentDictOptions(){ getCurrentDictOptions(){
return this.dictOptions return this.dictOptions
} }
},
model:{
prop: 'value',
event: 'change'
} }
} }
</script> </script>

View File

@ -10,7 +10,9 @@
:disabled="disabled" :disabled="disabled"
mode="multiple" mode="multiple"
:placeholder="placeholder" :placeholder="placeholder"
:getPopupContainer="(node) => node.parentNode" :getPopupContainer="getParentContainer"
optionFilterProp="children"
:filterOption="filterOption"
allowClear> allowClear>
<a-select-option <a-select-option
v-for="(item,index) in dictOptions" v-for="(item,index) in dictOptions"
@ -34,13 +36,23 @@
disabled: Boolean, disabled: Boolean,
value: String, value: String,
type: String, type: String,
options:Array options:Array,
spliter:{
type: String,
required: false,
default: ','
},
popContainer:{
type:String,
default:'',
required:false
},
}, },
data() { data() {
return { return {
dictOptions: [], dictOptions: [],
tagType:"", tagType:"",
arrayValue:!this.value?[]:this.value.split(",") arrayValue:!this.value?[]:this.value.split(this.spliter)
} }
}, },
created() { created() {
@ -66,7 +78,7 @@
if(!val){ if(!val){
this.arrayValue = [] this.arrayValue = []
}else{ }else{
this.arrayValue = this.value.split(",") this.arrayValue = this.value.split(this.spliter)
} }
} }
}, },
@ -76,8 +88,9 @@
this.dictOptions = [...this.options] this.dictOptions = [...this.options]
}else{ }else{
//优先从缓存中读取字典配置 //优先从缓存中读取字典配置
if(getDictItemsFromCache(this.dictCode)){ let cacheOption = getDictItemsFromCache(this.dictCode)
this.dictOptions = getDictItemsFromCache(this.dictCode); if(cacheOption && cacheOption.length>0){
this.dictOptions = cacheOption
return return
} }
//根据字典Code, 初始化字典数组 //根据字典Code, 初始化字典数组
@ -90,15 +103,27 @@
}, },
onChange (selectedValue) { onChange (selectedValue) {
this.$emit('change', selectedValue.join(",")); this.$emit('change', selectedValue.join(this.spliter));
}, },
setCurrentDictOptions(dictOptions){ setCurrentDictOptions(dictOptions){
this.dictOptions = dictOptions this.dictOptions = dictOptions
}, },
getCurrentDictOptions(){ getCurrentDictOptions(){
return this.dictOptions return this.dictOptions
},
getParentContainer(node){
if(!this.popContainer){
return node.parentNode
}else{
return document.querySelector(this.popContainer)
} }
}, },
// update--begin--autor:lvdandan-----date:20201120------forLOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
filterOption(input, option) {
return option.componentOptions.children[0].children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
// update--end--autor:lvdandan-----date:20201120------forLOWCOD-1086 下拉多选框,搜索时只字典code进行搜索不能通过字典text搜索
},
model: { model: {
prop: 'value', prop: 'value',
event: 'change' event: 'change'

View File

@ -5,7 +5,7 @@
showSearch showSearch
labelInValue labelInValue
:disabled="disabled" :disabled="disabled"
:getPopupContainer="(node) => node.parentNode" :getPopupContainer="getParentContainer"
@search="loadData" @search="loadData"
:placeholder="placeholder" :placeholder="placeholder"
v-model="selectedAsyncValue" v-model="selectedAsyncValue"
@ -21,7 +21,7 @@
<a-select <a-select
v-else v-else
:getPopupContainer="(node) => node.parentNode" :getPopupContainer="getParentContainer"
showSearch showSearch
:disabled="disabled" :disabled="disabled"
:placeholder="placeholder" :placeholder="placeholder"
@ -55,7 +55,21 @@
type:String, type:String,
default:"请选择", default:"请选择",
required:false required:false
} },
popContainer:{
type:String,
default:'',
required:false
},
pageSize:{
type: Number,
default: 10,
required: false
},
getPopupContainer: {
type:Function,
default: null
},
}, },
data(){ data(){
this.loadData = debounce(this.loadData, 800);//消抖 this.loadData = debounce(this.loadData, 800);//消抖
@ -126,7 +140,7 @@
this.options = [] this.options = []
this.loading=true this.loading=true
// 字典code格式table,text,code // 字典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 this.loading=false
if(res.success){ if(res.success){
if(currentLoad!=this.lastLoad){ 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) { filterOption(input, option) {
@ -182,9 +207,18 @@
this.callback() this.callback()
}, },
handleAsyncChange(selectedObj){ handleAsyncChange(selectedObj){
//update-begin-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
if(selectedObj){
this.selectedAsyncValue = selectedObj this.selectedAsyncValue = selectedObj
this.selectedValue = selectedObj.key this.selectedValue = selectedObj.key
}else{
this.selectedAsyncValue = null
this.selectedValue = null
this.options = null
this.loadData("")
}
this.callback() this.callback()
//update-end-author:scott date:20201222 for:【搜索】搜索查询组件,删除条件,默认下拉还是上次的缓存数据,不好 JT-191
}, },
callback(){ callback(){
this.$emit('change', this.selectedValue); this.$emit('change', this.selectedValue);
@ -194,7 +228,16 @@
}, },
getCurrentDictOptions(){ getCurrentDictOptions(){
return this.options 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: { model: {

View File

@ -1,7 +1,16 @@
import T from './JDictSelectTag.vue' import JDictSelectTag from './JDictSelectTag.vue'
const JDictSelectTag = { import JMultiSelectTag from './JMultiSelectTag.vue'
import JSearchSelectTag from './JSearchSelectTag.vue'
import { filterMultiDictText,filterDictText,initDictOptions,filterDictTextByCache } from './JDictSelectUtil'
export default {
install: function (Vue) { install: function (Vue) {
Vue.component('JDictSelectTag',T); 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)
} }
} }
export default JDictSelectTag;

View File

@ -251,6 +251,9 @@
}, },
style: {} style: {}
} }
if(isIE() || isIE11()){
props.style['height'] = '240px'
}
if (this.fullCoder) { if (this.fullCoder) {
props.style['z-index'] = this.zIndex props.style['z-index'] = this.zIndex
} }

View File

@ -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>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="components-input-demo-presuffix"> <div class="components-input-demo-presuffix">
<a-input @click="openModal" placeholder="corn表达式" v-model="cron" @change="handleOK"> <a-input @click="openModal" placeholder="cron表达式" v-model="cron" @change="(e)=>handleOK(e.target.value)">
<a-icon slot="prefix" type="schedule" title="corn控件"/> <a-icon slot="prefix" type="schedule" title="cron控件"/>
<a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/> <a-icon v-if="cron" slot="suffix" type="close-circle" @click="handleEmpty" title="清空"/>
</a-input> </a-input>
<JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal> <JCronModal ref="innerVueCron" :data="cron" @ok="handleOK"></JCronModal>

View 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>

View File

@ -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>

View File

@ -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

View File

@ -0,0 +1,6 @@
// 原开源项目地址https://gitee.com/toktok/easy-cron
import InputCron from './InputCron.vue'
InputCron.name = 'JEasyCron'
export default InputCron

View File

@ -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
}

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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
}
}
}
}

View File

@ -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
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
}

View File

@ -11,13 +11,13 @@
<a-col> <a-col>
<!-- 操作按钮 --> <!-- 操作按钮 -->
<div v-if="actionButton" class="action-button"> <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> <span class="gap"></span>
<template v-if="selectedRowIds.length>0"> <template v-if="selectedRowIds.length>0">
<a-popconfirm <a-popconfirm
:title="`确定要删除这 ${selectedRowIds.length} 项吗?`" :title="`确定要删除这 ${selectedRowIds.length} 项吗?`"
@confirm="handleConfirmDelete"> @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> <span class="gap"></span>
</a-popconfirm> </a-popconfirm>
<template v-if="showClearSelectButton"> <template v-if="showClearSelectButton">
@ -188,6 +188,7 @@
:getPopupContainer="getParentContainer" :getPopupContainer="getParentContainer"
:placeholder="replaceProps(col, col.placeholder)" :placeholder="replaceProps(col, col.placeholder)"
:filterOption="(i,o)=>handleSelectFilterOption(i,o,col)" :filterOption="(i,o)=>handleSelectFilterOption(i,o,col)"
:maxTagCount="1"
@change="(v)=>handleChangeSelectCommon(v,id,row,col)" @change="(v)=>handleChangeSelectCommon(v,id,row,col)"
@search="(v)=>handleSearchSelect(v,id,row,col)" @search="(v)=>handleSearchSelect(v,id,row,col)"
@blur="(v)=>handleBlurSearch(v,id,row,col)" @blur="(v)=>handleBlurSearch(v,id,row,col)"
@ -201,6 +202,55 @@
>{{ getSelectTranslateText(selectValues[id], row, col) }}</span> >{{ getSelectTranslateText(selectValues[id], row, col) }}</span>
</a-tooltip> </a-tooltip>
</template> </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 --> <!-- date -->
<template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime"> <template v-else-if="col.type === formTypes.date || col.type === formTypes.datetime">
<a-tooltip v-bind="buildTooltipProps(row, col, id)"> <a-tooltip v-bind="buildTooltipProps(row, col, id)">
@ -300,7 +350,7 @@
<a-tooltip v-bind="buildTooltipProps(row, col, id)"> <a-tooltip v-bind="buildTooltipProps(row, col, id)">
<a-upload <a-upload
name="file" name="file"
:data="{'isup':1}" :data="{'isup':1, ...(col.data||{})}"
:multiple="false" :multiple="false"
:action="col.action" :action="col.action"
:headers="uploadGetHeaders(row,col)" :headers="uploadGetHeaders(row,col)"
@ -331,6 +381,8 @@
:dest-fields="col.destFields" :dest-fields="col.destFields"
:code="col.popupCode" :code="col.popupCode"
:groupId="caseId" :groupId="caseId"
:param="col.param"
:sorter="col.sorter"
@input="(value,others)=>popupCallback(value,others,id,row,col,rowIndex)" @input="(value,others)=>popupCallback(value,others,id,row,col,rowIndex)"
/> />
<span <span
@ -375,7 +427,7 @@
<a-menu-item @click="handleClickDelFile(id)"> <a-menu-item @click="handleClickDelFile(id)">
<span><a-icon type="delete"/>&nbsp;删除</span> <span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item> </a-menu-item>
<a-menu-item @click="handleMoreOperation(id)"> <a-menu-item @click="handleMoreOperation(id,col,col)">
<span><a-icon type="bars" /> 更多</span> <span><a-icon type="bars" /> 更多</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -410,7 +462,7 @@
<a-icon type="loading"/> <a-icon type="loading"/>
</template> </template>
<template v-else-if="uploadValues[id]['path']"> <template v-else-if="uploadValues[id]['path']">
<img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img')"/> <img class="j-editable-image" :src="getCellImageView(id)" alt="无图片" @click="handleMoreOperation(id,'img',col)"/>
</template> </template>
<template v-else> <template v-else>
<a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/> <a-icon type="exclamation-circle" style="color: red;" @click="handleClickShowImageError(id)"/>
@ -443,7 +495,7 @@
<a-menu-item @click="handleClickDelFile(id)"> <a-menu-item @click="handleClickDelFile(id)">
<span><a-icon type="delete"/>&nbsp;删除</span> <span><a-icon type="delete"/>&nbsp;删除</span>
</a-menu-item> </a-menu-item>
<a-menu-item @click="handleMoreOperation(id,'img')"> <a-menu-item @click="handleMoreOperation(id,'img',col)">
<span><a-icon type="bars" /> 更多</span> <span><a-icon type="bars" /> 更多</span>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -545,6 +597,33 @@
</template> </template>
<!-- select搜索 -end --> <!-- 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"> <div v-else-if="col.type === formTypes.slot" :key="i">
<a-tooltip v-bind="buildTooltipProps(row, col, id)"> <a-tooltip v-bind="buildTooltipProps(row, col, id)">
<slot <slot
@ -565,7 +644,7 @@
</div> </div>
<!-- else (normal) --> <!-- 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> </template>
</div> </div>
</div> </div>
@ -612,7 +691,7 @@
</div> </div>
</div> </div>
<j-file-pop ref="filePop" @ok="handleFileSuccess"></j-file-pop> <j-file-pop ref="filePop" @ok="handleFileSuccess" :number="number"></j-file-pop>
</div> </div>
</a-spin> </a-spin>
</template> </template>
@ -622,12 +701,13 @@
import Draggable from 'vuedraggable' import Draggable from 'vuedraggable'
import { ACCESS_TOKEN } from '@/store/mutation-types' import { ACCESS_TOKEN } from '@/store/mutation-types'
import { FormTypes, VALIDATE_NO_PASSED } from '@/utils/JEditableTableUtil' 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 JDate from '@/components/jeecg/JDate'
import { filterDictText, initDictOptions } from '@/components/dict/JDictSelectUtil' 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 JInputPop from '@/components/jeecg/minipop/JInputPop'
import JFilePop from '@/components/jeecg/minipop/JFilePop' import JFilePop from '@/components/jeecg/minipop/JFilePop'
import { getNoAuthCols } from '@/utils/authFilter'
// 行高,需要在实例加载完成前用到 // 行高,需要在实例加载完成前用到
let rowHeight = 61 let rowHeight = 61
@ -704,6 +784,11 @@
type: Boolean, type: Boolean,
default: true default: true
}, },
authPre: {
type: String,
required: false,
default: ''
},
}, },
data() { data() {
return { return {
@ -749,11 +834,16 @@
uploadValues: {}, uploadValues: {},
//popup信息 //popup信息
popupValues: {}, popupValues: {},
//部门组件信息
departCompValues:{},
//用户组件信息
userCompValues: {},
radioValues: {}, radioValues: {},
metaCheckboxValues: {}, metaCheckboxValues: {},
multiSelectValues: {}, multiSelectValues: {},
searchSelectValues: {}, searchSelectValues: {},
searchSelectAsyncValues: {},
// 绑定左侧选择框已选择的id // 绑定左侧选择框已选择的id
selectedRowIds: [], selectedRowIds: [],
// 存储被删除行的id // 存储被删除行的id
@ -774,6 +864,9 @@
currentEditRows: {}, currentEditRows: {},
// 上次push数据的事件用于判断是否点击过快 // 上次push数据的事件用于判断是否点击过快
lastPushTimeMap: new Map(), lastPushTimeMap: new Map(),
number:0,
//不显示的按钮编码
excludeCode:[]
} }
}, },
created() { created() {
@ -882,6 +975,8 @@
columns: { columns: {
immediate: true, immediate: true,
handler(columns) { handler(columns) {
//列改变的时候重新设置按钮权限信息
this.loadExcludeCode()
// 兼容IE // 兼容IE
this.getElementPromise('tbody').then(() => { this.getElementPromise('tbody').then(() => {
columns.forEach(column => { columns.forEach(column => {
@ -963,6 +1058,13 @@
this.visibleTrEls = [] this.visibleTrEls = []
// 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据 // 判断是否是首次进入该方法,如果是就不清空行,防止删除了预添加的数据
if (!this.isFirst) { if (!this.isFirst) {
this.clearRow();
} else {
this.isFirst = false
}
},
/**清空行*/
clearRow(){
// inputValues用来存储input表单的值 // inputValues用来存储input表单的值
// 数组里的每项都是一个对象对象里每个key都是input的rowKey值就是input的值其中有个id的字段来区分 // 数组里的每项都是一个对象对象里每个key都是input的rowKey值就是input的值其中有个id的字段来区分
// 示例: // 示例:
@ -976,28 +1078,32 @@
this.inputValues = [] this.inputValues = []
this.rows = [] this.rows = []
this.deleteIds = [] this.deleteIds = []
this.selectedRowIds = []
this.tooltips = {}
this.notPassedIds = []
// 重置values
this.selectValues = {} this.selectValues = {}
this.checkboxValues = {} this.checkboxValues = {}
this.jdateValues = {} this.jdateValues = {}
this.jInputPopValues = {} this.jInputPopValues = {}
this.departCompValues = {}
this.userCompValues = {}
this.slotValues = {} this.slotValues = {}
this.selectedRowIds = [] //update-begin-author:shunjlei date:20210415 for:类型赋值错误
this.tooltips = {} this.uploadValues = {}
this.notPassedIds = [] this.popupValues = {}
this.uploadValues = [] this.radioValues = {}
this.popupValues = [] this.multiSelectValues = {}
this.radioValues = [] this.searchSelectValues = {}
this.multiSelectValues = [] this.searchSelectAsyncValues = {}
this.searchSelectValues = [] //update-end-author:shunjlei date:20210415 for:类型赋值错误
// 重置滚动条
this.scrollTop = 0 this.scrollTop = 0
this.$nextTick(() => { this.$nextTick(() => {
this.getElement('tbody').scrollTop = 0 this.getElement('tbody').scrollTop = 0
}) })
} else {
this.isFirst = false
}
}, },
/** 同步滚动条状态 */ /** 同步滚动条状态 */
syncScrollBar(scrollLeft) { syncScrollBar(scrollLeft) {
// this.style.tbody.left = `${scrollLeft}px` // this.style.tbody.left = `${scrollLeft}px`
@ -1057,6 +1163,8 @@
let checkboxValues = { ...this.checkboxValues } let checkboxValues = { ...this.checkboxValues }
let selectValues = { ...this.selectValues } let selectValues = { ...this.selectValues }
let jdateValues = { ...this.jdateValues } let jdateValues = { ...this.jdateValues }
let departCompValues = { ...this.departCompValues }
let userCompValues = { ...this.userCompValues }
let jInputPopValues = { ...this.jInputPopValues } let jInputPopValues = { ...this.jInputPopValues }
let slotValues = { ...this.slotValues } let slotValues = { ...this.slotValues }
let uploadValues = { ...this.uploadValues } let uploadValues = { ...this.uploadValues }
@ -1064,6 +1172,7 @@
let radioValues = { ...this.radioValues } let radioValues = { ...this.radioValues }
let multiSelectValues = { ...this.multiSelectValues } let multiSelectValues = { ...this.multiSelectValues }
let searchSelectValues = { ...this.searchSelectValues } let searchSelectValues = { ...this.searchSelectValues }
let searchSelectAsyncValues = { ...this.searchSelectAsyncValues }
// 禁用行的id // 禁用行的id
let disabledRowIds = (this.disabledRowIds || []) let disabledRowIds = (this.disabledRowIds || [])
dataSource.forEach((data, newValueIndex) => { dataSource.forEach((data, newValueIndex) => {
@ -1143,12 +1252,18 @@
} else if (column.type === FormTypes.popup) { } else if (column.type === FormTypes.popup) {
popupValues[inputId] = sourceValue 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) { } else if (column.type === FormTypes.input_pop) {
jInputPopValues[inputId] = sourceValue jInputPopValues[inputId] = sourceValue
} else if (column.type === FormTypes.radio) { } else if (column.type === FormTypes.radio) {
radioValues[inputId] = sourceValue radioValues[inputId] = sourceValue
} else if (column.type === FormTypes.sel_search) { } else if (column.type === FormTypes.sel_search) {
searchSelectValues[inputId] = sourceValue searchSelectValues[inputId] = sourceValue
} else if (column.type === FormTypes.sel_search_async) {
searchSelectAsyncValues[inputId] = sourceValue
} else if (column.type === FormTypes.list_multi) { } else if (column.type === FormTypes.list_multi) {
if (typeof sourceValue === 'string' && sourceValue.length > 0) { if (typeof sourceValue === 'string' && sourceValue.length > 0) {
multiSelectValues[inputId] = sourceValue.split(',') multiSelectValues[inputId] = sourceValue.split(',')
@ -1169,6 +1284,8 @@
status: 'done', status: 'done',
path: sourceValue path: sourceValue
} }
} else {
uploadValues[inputId] = null
} }
} else { } else {
value[column.key] = sourceValue value[column.key] = sourceValue
@ -1203,6 +1320,12 @@
this.inputValues.splice(insertIndex, 0, value) this.inputValues.splice(insertIndex, 0, value)
} }
} }
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id且和现有数据一致时替换患有数据
if(-1 !== rows.findIndex(item => item.id === row.id)){
added = true
this.inputValues = this.inputValues.map(item => item.id === row.id ? value : item)
}
//update-begin-author:lvdandan date:20201105 for:LOWCOD-987 【online】js增强的问题--数据对象带有id且和现有数据一致时替换患有数据
if (!added) { if (!added) {
rows.push(row) rows.push(row)
this.inputValues.push(value) this.inputValues.push(value)
@ -1218,6 +1341,8 @@
this.checkboxValues = checkboxValues this.checkboxValues = checkboxValues
this.selectValues = selectValues this.selectValues = selectValues
this.jdateValues = jdateValues this.jdateValues = jdateValues
this.departCompValues = departCompValues
this.userCompValues = userCompValues
this.jInputPopValues = jInputPopValues this.jInputPopValues = jInputPopValues
this.slotValues = slotValues this.slotValues = slotValues
this.uploadValues = uploadValues this.uploadValues = uploadValues
@ -1225,6 +1350,7 @@
this.radioValues = radioValues this.radioValues = radioValues
this.multiSelectValues = multiSelectValues this.multiSelectValues = multiSelectValues
this.searchSelectValues = searchSelectValues this.searchSelectValues = searchSelectValues
this.searchSelectAsyncValues = searchSelectAsyncValues
// 重新计算所有统计列 // 重新计算所有统计列
this.recalcAllStatisticsColumns() this.recalcAllStatisticsColumns()
// 更新到 dom // 更新到 dom
@ -1433,6 +1559,12 @@
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
value[column.key] = this.jdateValues[inputId] 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) { } else if (column.type === FormTypes.input_pop) {
value[column.key] = this.jInputPopValues[inputId] value[column.key] = this.jInputPopValues[inputId]
@ -1453,6 +1585,8 @@
value[column.key] = this.radioValues[inputId] value[column.key] = this.radioValues[inputId]
} else if (column.type === FormTypes.sel_search) { } else if (column.type === FormTypes.sel_search) {
value[column.key] = this.searchSelectValues[inputId] 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) { } else if (column.type === FormTypes.list_multi) {
if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) { if (!this.multiSelectValues[inputId] || this.multiSelectValues[inputId].length === 0) {
value[column.key] = '' value[column.key] = ''
@ -1572,6 +1706,8 @@
selectValues: this.selectValues, selectValues: this.selectValues,
checkboxValues: this.checkboxValues, checkboxValues: this.checkboxValues,
jdateValues: this.jdateValues, jdateValues: this.jdateValues,
departCompValues: this.departCompValues,
userCompValues: this.userCompValues,
jInputPopValues: this.jInputPopValues, jInputPopValues: this.jInputPopValues,
slotValues: this.slotValues, slotValues: this.slotValues,
uploadValues: this.uploadValues, uploadValues: this.uploadValues,
@ -1579,6 +1715,7 @@
radioValues: this.radioValues, radioValues: this.radioValues,
multiSelectValues: this.multiSelectValues, multiSelectValues: this.multiSelectValues,
searchSelectValues: this.searchSelectValues, searchSelectValues: this.searchSelectValues,
searchSelectAsyncValues: this.searchSelectAsyncValues,
}) })
}, },
/** 设置某行某列的值 */ /** 设置某行某列的值 */
@ -1626,6 +1763,10 @@
edited = true edited = true
} else if (column.type === FormTypes.date || column.type === FormTypes.datetime) { } else if (column.type === FormTypes.date || column.type === FormTypes.datetime) {
edited = this.setOneValue(this.jdateValues, modelKey, newValue) 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) { } else if (column.type === FormTypes.input_pop) {
edited = this.setOneValue(this.jInputPopValues, modelKey, newValue) edited = this.setOneValue(this.jInputPopValues, modelKey, newValue)
} else if (column.type === FormTypes.slot) { } else if (column.type === FormTypes.slot) {
@ -1640,6 +1781,8 @@
edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true) edited = this.setOneValue(this.multiSelectValues, modelKey, newValue, true)
} else if (column.type === FormTypes.sel_search) { } else if (column.type === FormTypes.sel_search) {
edited = this.setOneValue(this.searchSelectValues, modelKey, newValue) edited = this.setOneValue(this.searchSelectValues, modelKey, newValue)
} else if (column.type === FormTypes.sel_search_async) {
edited = this.setOneValue(this.searchSelectAsyncValues, modelKey, newValue)
} else { } else {
edited = false edited = false
} }
@ -1802,7 +1945,7 @@
// 兼容 online 的规则 // 兼容 online 的规则
let foo = [ 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到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/ },
{ title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/ }, { 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+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ }, { title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/ },
@ -2143,8 +2286,12 @@
} }
target.value = value target.value = value
} }
//update--begin--autor:lvdandan-----date:20201126------forLOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
setTimeout(()=>{
// 做单个表单验证 // 做单个表单验证
this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur') this.validateOneInput(value, row, column, this.notPassedIds, true, 'blur')
}, 100)
//update--end--autor:lvdandan-----date:20201126------forLOWCOD-1088 JEditableTable输入校验提示框位置偏移 #2005
}, },
handleChangeCheckboxCommon(event, row, column) { handleChangeCheckboxCommon(event, row, column) {
let { id, checked } = event.target let { id, checked } = event.target
@ -2172,6 +2319,20 @@
this.elemValueChange(FormTypes.date, row, column, value) 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){ handleChangeJInputPopCommon(value, id, row, column){
this.jInputPopValues = this.bindValuesChange(value, id, 'jInputPopValues') this.jInputPopValues = this.bindValuesChange(value, id, 'jInputPopValues')
// 做单个表单验证 // 做单个表单验证
@ -2201,7 +2362,18 @@
// 触发valueChange 事件 // 触发valueChange 事件
this.elemValueChange(column.type, row, column, value) this.elemValueChange(column.type, row, column, value)
}, },
handleMoreOperation(id,flag){ handleMoreOperation(id,flag,column){
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(column.number){
this.number = column.number;
}else{
this.number = 0;
}
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 判断传过来的字段是否存在number用于控制上传文件
if(column && column.fieldExtendJson){
let json = JSON.parse(column.fieldExtendJson);
this.number = json.uploadnum?json.uploadnum:0;
}
//console.log("this.uploadValues[id]",this.uploadValues[id]) //console.log("this.uploadValues[id]",this.uploadValues[id])
let path = '' let path = ''
if(this.uploadValues && this.uploadValues[id]){ if(this.uploadValues && this.uploadValues[id]){
@ -2452,6 +2624,19 @@
} else { } else {
style['width'] = '120px' style['width'] = '120px'
} }
//update-begin-author:lvdandan date:20201116 for:LOWCOD-984 默认风格功能测试附表样式问题 日期时间控件长度太大
//如果是时间控件设为200px
if(col.type === FormTypes.datetime){
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 默认风格功能测试附表样式问题 日期时间控件长度太大
// checkbox 居中显示 // checkbox 居中显示
let isCheckbox = col.type === FormTypes.checkbox let isCheckbox = col.type === FormTypes.checkbox
if (isCheckbox) { if (isCheckbox) {
@ -2566,7 +2751,7 @@
} }
this.setOneValue(this.popupValues, id, popupValue) 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 事件 // 触发valueChange 事件
this.elemValueChange('input', row, column, value) this.elemValueChange('input', row, column, value)
}, },
@ -2593,6 +2778,11 @@
this.validateOneInput(value, row, column, this.notPassedIds, true, 'change') this.validateOneInput(value, row, column, this.notPassedIds, true, 'change')
this.elemValueChange(FormTypes.sel_search, row, column, value) 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) { filterOption(input, option) {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0 return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}, },
@ -2685,15 +2875,35 @@
removeEventListener() { removeEventListener() {
window.removeEventListener('mouseup', this.handleMouseup) window.removeEventListener('mouseup', this.handleMouseup)
}, },
/* --------------------------- 2020年5月18日 默认span模式 ------------------------------ */ /* --------------------------- 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() { beforeDestroy() {
this.removeEventListener() this.removeEventListener()
this.destroyCleanGroupRequest = true this.destroyCleanGroupRequest = true
}, }
} }
</script> </script>
@ -2834,6 +3044,8 @@
border-bottom: @border; border-bottom: @border;
transition: background-color 300ms; transition: background-color 300ms;
width: 100%; width: 100%;
height: 61px;
overflow: hidden;
position: absolute; position: absolute;
left: 0; left: 0;
z-index: 10; z-index: 10;
@ -2943,6 +3155,12 @@
} }
} }
.comp-normal {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.j-td-span { .j-td-span {
position: relative; position: relative;
padding: 4px 11px; padding: 4px 11px;

View File

@ -128,6 +128,9 @@
this.reload() this.reload()
} }
}) })
//update--begin--autor:liusq-----date:20210316------for富文本编辑器tab父组件可能导致的赋值问题------
this.reload()
//update--end--autor:liusq-----date:20210316------for富文本编辑器tab父组件可能导致的赋值问题------
}else{ }else{
//update--begin--autor:wangshuai-----date:20200724------for富文本编辑器切换tab无法修改------ //update--begin--autor:wangshuai-----date:20200724------for富文本编辑器切换tab无法修改------
let tabLayout = getVmParentByName(this, 'TabLayout') let tabLayout = getVmParentByName(this, 'TabLayout')

View File

@ -11,15 +11,17 @@
:beforeUpload="beforeUpload" :beforeUpload="beforeUpload"
:disabled="disabled" :disabled="disabled"
:isMultiple="isMultiple" :isMultiple="isMultiple"
:showUploadList="isMultiple"
@change="handleChange" @change="handleChange"
@preview="handlePreview" @preview="handlePreview"
:class="!isMultiple?'imgupload':''"> :class="[!isMultiple?'imgupload':'', (!isMultiple && picUrl)?'image-upload-single-over':'' ]">
<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="height:104px;max-width:300px"/> <div>
<div v-else class="iconp"> <!--<img v-if="!isMultiple && picUrl" :src="getAvatarView()" style="width:100%;height:100%"/>-->
<div class="iconp">
<a-icon :type="uploadLoading ? 'loading' : 'plus'" /> <a-icon :type="uploadLoading ? 'loading' : 'plus'" />
<div class="ant-upload-text">{{ text }}</div> <div class="ant-upload-text">{{ text }}</div>
</div> </div>
</div>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()"> <a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel()">
<img alt="example" style="width: 100%" :src="previewImage"/> <img alt="example" style="width: 100%" :src="previewImage"/>
</a-modal> </a-modal>
@ -80,10 +82,18 @@
type:Boolean, type:Boolean,
required:false, required:false,
default: false default: false
},
//update-begin-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性用于判断上传数量
number:{
type:Number,
required:false,
default:0
} }
//update-end-author:wangshuai date:20201021 for:LOWCOD-969 新增number属性用于判断上传数量
}, },
watch:{ watch:{
value(val){ value: {
handler(val,oldValue) {
if (val instanceof Array) { if (val instanceof Array) {
this.initFileList(val.join(',')) this.initFileList(val.join(','))
} else { } else {
@ -92,6 +102,9 @@
if(!val || val.length==0){ if(!val || val.length==0){
this.picUrl = false; this.picUrl = false;
} }
},
//立刻执行handler
immediate: true
} }
}, },
created(){ created(){
@ -132,6 +145,11 @@
handleChange(info) { handleChange(info) {
this.picUrl = false; this.picUrl = false;
let fileList = info.fileList let fileList = info.fileList
//update-begin-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选返回选定的元素。
if(this.number>0 && this.isMultiple){
fileList = fileList.slice(-this.number);
}
//update-end-author:wangshuai date:20201022 for:LOWCOD-969 判断number是否大于0和是否多选返回选定的元素。
if(info.file.status==='done'){ if(info.file.status==='done'){
if(info.file.response.success){ if(info.file.response.success){
this.picUrl = true; this.picUrl = true;
@ -171,7 +189,7 @@
path = '' path = ''
} }
let arr = []; let arr = [];
if(!this.isMultiple){ if(!this.isMultiple && uploadFiles.length>0){
arr.push(uploadFiles[uploadFiles.length-1].response.message) arr.push(uploadFiles[uploadFiles.length-1].response.message)
}else{ }else{
for(let a=0;a<uploadFiles.length;a++){ for(let a=0;a<uploadFiles.length;a++){
@ -213,8 +231,9 @@
* https://github.com/zhangdaiscott/jeecg-boot/issues/1810 * https://github.com/zhangdaiscott/jeecg-boot/issues/1810
* https://github.com/zhangdaiscott/jeecg-boot/issues/1779 * 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:20px;}
/deep/ .imgupload .iconp{padding:32px;}
/* update--end--autor:lvdandan-----date:20201016------forj-image-upload图片组件单张图片详情回显空白*/ /* update--end--autor:lvdandan-----date:20201016------forj-image-upload图片组件单张图片详情回显空白*/
/deep/ .image-upload-single-over .ant-upload-select{display: none}
</style> </style>

View File

@ -6,6 +6,13 @@
:confirmLoading="uploading" :confirmLoading="uploading"
@cancel="handleClose"> @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 <a-upload
name="file" name="file"
:multiple="true" :multiple="true"
@ -47,6 +54,12 @@
type: String, type: String,
default: '', default: '',
required: false required: false
},
//是否online导入
online:{
type: Boolean,
default: false,
required: false
} }
}, },
data(){ data(){
@ -55,7 +68,8 @@
uploading:false, uploading:false,
fileList:[], fileList:[],
uploadAction:'', uploadAction:'',
foreignKeys:'' foreignKeys:'',
validateStatus: 0
} }
}, },
watch: { watch: {
@ -78,6 +92,7 @@
this.uploading = false this.uploading = false
this.visible = true this.visible = true
this.foreignKeys = arg; this.foreignKeys = arg;
this.validateStatus = 0
}, },
handleRemove(file) { handleRemove(file) {
const index = this.fileList.indexOf(file); const index = this.fileList.indexOf(file);
@ -98,6 +113,9 @@
if(this.foreignKeys && this.foreignKeys.length>0){ if(this.foreignKeys && this.foreignKeys.length>0){
formData.append('foreignKeys',this.foreignKeys); formData.append('foreignKeys',this.foreignKeys);
} }
if(this.online==true){
formData.append('validateStatus',this.validateStatus);
}
fileList.forEach((file) => { fileList.forEach((file) => {
formData.append('files[]', file); formData.append('files[]', file);
}); });
@ -105,14 +123,41 @@
postAction(this.uploadAction, formData).then((res) => { postAction(this.uploadAction, formData).then((res) => {
this.uploading = false this.uploading = false
if(res.success){ if(res.success){
if(res.code == 201){
this.errorTip(res.message, res.result)
}else{
this.$message.success(res.message) this.$message.success(res.message)
}
this.visible=false this.visible=false
this.$emit('ok') this.$emit('ok')
}else{ }else{
this.$message.warning(res.message) 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() {},
});
},
} }
} }

View File

@ -21,7 +21,6 @@ export default {
'outdent', 'outdent',
'divider', 'divider',
'table', 'table',
'image',
'link', 'link',
'divider', 'divider',
'code', 'code',

View File

@ -1,5 +1,28 @@
<template> <template>
<div>
<div class="j-markdown-editor" :id="id"/> <div class="j-markdown-editor" :id="id"/>
<div v-if="isShow">
<j-modal
title="图片上传"
:visible.sync="dialogVisible"
width="30%"
:before-close="handleClose"
@ok="handleOk">
<a-tabs default-active-key="1" @change="handleChange">
<a-tab-pane tab="本地图片上传" key="1" :forceRender="true">
<j-upload v-model="fileList" :number="1"></j-upload>
<div style="margin-top: 20px">
<a-input v-model="remark" placeholder="请填写备注"></a-input>
</div>
</a-tab-pane>
<a-tab-pane tab="网络图片地址" key="2" :forceRender="true">
<a-input v-model="networkPic" placeholder="请填写网络图片地址"></a-input>
<a-input style="margin-top: 20px" v-model="remark" placeholder="请填写备注"></a-input>
</a-tab-pane>
</a-tabs>
</j-modal>
</div>
</div>
</template> </template>
<script> <script>
@ -9,9 +32,14 @@ import '@toast-ui/editor/dist/i18n/zh-cn';
import Editor from '@toast-ui/editor'; import Editor from '@toast-ui/editor';
import defaultOptions from './default-options' import defaultOptions from './default-options'
import JUpload from '@/components/jeecg/JUpload'
import { getFileAccessHttpUrl } from '@/api/manage'
export default { export default {
name: 'JMarkdownEditor', name: 'JMarkdownEditor',
components: {
JUpload,
},
props: { props: {
value: { value: {
type: String, type: String,
@ -47,7 +75,16 @@ export default {
}, },
data() { data() {
return { return {
editor: null editor: null,
isShow:false,
activeIndex:"1",
dialogVisible:false,
index:"1",
fileList:[],
remark:"",
imageName:"",
imageUrl:"",
networkPic:""
} }
}, },
computed: { computed: {
@ -94,6 +131,40 @@ export default {
this.editor.on('change', () => { this.editor.on('change', () => {
this.$emit('change', this.editor.getMarkdown()) this.$emit('change', this.editor.getMarkdown())
}) })
//--begin 添加自定义上传按钮
/*
* 添加自定义按钮
*/
//获取编辑器上的功能条
let toolbar = this.editor.getUI().getToolbar();
let fileDom = this.$refs.files;
//添加图片点击事件
this.editor.eventManager.addEventType('isShowClickEvent');
this.editor.eventManager.listen('isShowClickEvent', () => {
this.isShow = true
this.dialogVisible = true
});
//addImageBlobHook图片上传、剪切、拖拽都会走此方法
// 删除默认监听事件
this.editor.eventManager.removeEventHandler('addImageBlobHook')
// 添加自定义监听事件
this.editor.eventManager.listen('addImageBlobHook', (blob, callback) => {
this.upload(blob, url => {
callback(url)
})
})
// 添加自定义按钮 第二个参数代表位置,不传默认放在最后
toolbar.insertItem(15,{
type: 'button',
options:{
name: 'customize',
className: 'tui-image tui-toolbar-icons',
event: 'isShowClickEvent',
tooltip: '上传图片',
}
//
});
//--end 添加自定义上传按钮
}, },
destroyEditor() { destroyEditor() {
if (!this.editor) return if (!this.editor) return
@ -111,7 +182,57 @@ export default {
}, },
getHtml() { getHtml() {
return this.editor.getHtml() return this.editor.getHtml()
},
handleOk(){
if(this.index=='1'){
this.imageUrl = getFileAccessHttpUrl(this.fileList)
if(this.remark){
this.addImgToMd(this.imageUrl,this.remark)
}else{
this.addImgToMd(this.imageUrl,"")
} }
}else{
if(this.remark){
this.addImgToMd(this.networkPic,this.remark)
}else{
this.addImgToMd(this.networkPic,"")
}
}
this.index="1"
this.fileList=[]
this.imageName="";
this.imageUrl="";
this.remark=""
this.networkPic=""
this.dialogVisible=false
this.isShow=false;
},
handleClose(done) {
done();
},
handleChange(val){
this.fileList=[]
this.remark=""
this.imageName=""
this.imageUrl=""
this.networkPic=""
this.index=val
},
//添加图片到markdown
addImgToMd(data,name) {
let editor = this.editor.getCodeMirror();
let editorHtml = this.editor.getCurrentModeEditor();
let isMarkdownMode = this.editor.isMarkdownMode();
if (isMarkdownMode) {
editor.replaceSelection(`![${name}](${data})`);
} else {
let range = editorHtml.getRange();
let img = document.createElement('img');
img.src = `${data}`;
img.alt = name;
range.insertNode(img);
}
},
}, },
model: { model: {
prop: 'value', prop: 'value',

View File

@ -8,10 +8,11 @@
v-on="$listeners" v-on="$listeners"
@ok="handleOk" @ok="handleOk"
@cancel="handleCancel" @cancel="handleCancel"
destroyOnClose
> >
<slot></slot> <slot></slot>
<!--有设置标题-->
<template v-if="!isNoTitle" slot="title"> <template v-if="!isNoTitle" slot="title">
<a-row class="j-modal-title-row" type="flex"> <a-row class="j-modal-title-row" type="flex">
<a-col class="left"> <a-col class="left">
@ -22,6 +23,14 @@
</a-col> </a-col>
</a-row> </a-row>
</template> </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 --> <!-- 处理 scopedSlots -->
<template v-for="slotName of scopedSlotsKeys" :slot="slotName"> <template v-for="slotName of scopedSlotsKeys" :slot="slotName">
@ -161,7 +170,6 @@
<style lang="less"> <style lang="less">
.j-modal-box { .j-modal-box {
&.fullscreen { &.fullscreen {
top: 0; top: 0;
left: 0; left: 0;
@ -190,7 +198,6 @@
height: calc(100% - 55px); height: calc(100% - 55px);
} }
} }
&.no-title.no-footer { &.no-title.no-footer {
.ant-modal-body { .ant-modal-body {
height: 100%; height: 100%;
@ -217,6 +224,12 @@
} }
} }
} }
&.no-title{
.ant-modal-header {
padding: 0px 24px;
border-bottom: 0px !important;
}
}
} }
@media (max-width: 767px) { @media (max-width: 767px) {

View File

@ -10,7 +10,9 @@
ref="jPopupOnlReport" ref="jPopupOnlReport"
:code="code" :code="code"
:multi="multi" :multi="multi"
:sorter="sorter"
:groupId="uniqGroupId" :groupId="uniqGroupId"
:param="param"
@ok="callBack" @ok="callBack"
/> />
@ -46,6 +48,11 @@
default: '', default: '',
required: false required: false
}, },
/** 排序列,指定要排序的列,使用方式:列名=desc|asc */
sorter: {
type: String,
default: ''
},
width: { width: {
type: Number, type: Number,
default: 1200, default: 1200,
@ -75,6 +82,17 @@
required: false, required: false,
default: false default: false
}, },
//popup动态参数 支持系统变量语法
param:{
type: Object,
required: false,
default: ()=>{}
},
spliter:{
type: String,
required: false,
default: ','
},
/** 分组ID用于将多个popup的请求合并到一起不传不分组 */ /** 分组ID用于将多个popup的请求合并到一起不传不分组 */
groupId: String groupId: String
@ -101,7 +119,7 @@
if (!val) { if (!val) {
this.showText = '' this.showText = ''
} else { } else {
this.showText = val this.showText = val.split(this.spliter).join(',')
} }
} }
} }
@ -181,7 +199,11 @@
} else { } else {
//v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值 //v-model时 需要传一个参数field 表示当前这个字段 从而根据这个字段的顺序找到原始值
// this.$emit("input",row[orgFieldsArr[destFieldsArr.indexOf(this.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)
} }
} }
} }

View File

@ -3,6 +3,7 @@
<a-select-option <a-select-option
v-for="(item,index) in options" v-for="(item,index) in options"
:key="index" :key="index"
:getPopupContainer="getParentContainer"
:value="item.value"> :value="item.value">
{{ item.text || item.label }} {{ item.text || item.label }}
</a-select-option> </a-select-option>
@ -36,11 +37,21 @@
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false
} },
spliter:{
type: String,
required: false,
default: ','
},
popContainer:{
type:String,
default:'',
required:false
},
}, },
data(){ data(){
return { return {
arrayValue:!this.value?[]:this.value.split(",") arrayValue:!this.value?[]:this.value.split(this.spliter)
} }
}, },
watch:{ watch:{
@ -48,18 +59,25 @@
if(!val){ if(!val){
this.arrayValue = [] this.arrayValue = []
}else{ }else{
this.arrayValue = this.value.split(",") this.arrayValue = this.value.split(this.spliter)
} }
} }
}, },
methods:{ methods:{
onChange (selectedValue) { onChange (selectedValue) {
if(this.triggerChange){ if(this.triggerChange){
this.$emit('change', selectedValue.join(",")); this.$emit('change', selectedValue.join(this.spliter));
}else{ }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)
}
}
}, },
} }

View File

@ -101,7 +101,15 @@
</a-col> </a-col>
<a-col :md="8" :xs="24" style="margin-bottom: 12px;"> <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'"> <template v-if="item.type === 'table-dict'">
<j-popup <j-popup
v-model="item.val" v-model="item.val"
@ -109,6 +117,7 @@
:field="item.dictCode" :field="item.dictCode"
:orgFields="item.dictCode" :orgFields="item.dictCode"
:destFields="item.dictCode" :destFields="item.dictCode"
:multi="true"
></j-popup> ></j-popup>
</template> </template>
<template v-else> <template v-else>
@ -116,7 +125,13 @@
<j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/> <j-dict-select-tag v-show="!allowMultiple(item)" v-model="item.val" :dictCode="item.dictCode" placeholder="请选择"/>
</template> </template>
</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 <j-select-multi-user
v-else-if="item.type === 'select-user' || item.type === 'sel_user'" v-else-if="item.type === 'select-user' || item.type === 'sel_user'"
v-model="item.val" v-model="item.val"
@ -338,6 +353,17 @@
} }
this.visible = true 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() { handleOk() {
if (!this.isNullArray(this.queryParamsModel)) { if (!this.isNullArray(this.queryParamsModel)) {
let event = { let event = {
@ -386,11 +412,12 @@
this.queryParamsModel.splice(index, 1) this.queryParamsModel.splice(index, 1)
}, },
handleSelected(node, item) { 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['type'] = type
item['options'] = options item['options'] = options
item['dictCode'] = dictCode item['dictCode'] = dictCode
item['dictTable'] = dictTable item['dictTable'] = dictTable
item['dictText'] = dictText
item['customReturnField'] = customReturnField item['customReturnField'] = customReturnField
if (popup) { if (popup) {
item['popup'] = popup item['popup'] = popup

View File

@ -12,7 +12,7 @@
<a-upload <a-upload
name="file" name="file"
:multiple="true" :multiple="multiple"
:action="uploadAction" :action="uploadAction"
:headers="headers" :headers="headers"
:data="{'biz':bizPath}" :data="{'biz':bizPath}"
@ -135,6 +135,10 @@
required:false, required:false,
default: true default: true
}, },
multiple: {
type: Boolean,
default: true
},
}, },
watch:{ watch:{
value:{ value:{
@ -374,6 +378,7 @@
}, },
mounted(){ mounted(){
const moverObj = document.getElementById(this.containerId+'-mover'); const moverObj = document.getElementById(this.containerId+'-mover');
if(moverObj){
moverObj.addEventListener('mouseover',()=>{ moverObj.addEventListener('mouseover',()=>{
this.moverHold = true this.moverHold = true
this.moveDisplay = 'block'; this.moveDisplay = 'block';
@ -382,6 +387,8 @@
this.moverHold = false this.moverHold = false
this.moveDisplay = 'none'; this.moveDisplay = 'none';
}); });
}
let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[]; let picList = document.getElementById(this.containerId)?document.getElementById(this.containerId).getElementsByClassName('ant-upload-list-picture-card'):[];
if(picList && picList.length>0){ if(picList && picList.length>0){
picList[0].addEventListener('mouseover',(ev)=>{ picList[0].addEventListener('mouseover',(ev)=>{

View File

@ -1,5 +1,5 @@
<template> <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 class="j-vxe-popover-title" slot="title">
<div>子表</div> <div>子表</div>
<div class="j-vxe-popover-title-close" @click="close"> <div class="j-vxe-popover-title-close" @click="close">
@ -34,6 +34,7 @@
width: null, width: null,
zIndex: 100 zIndex: 100
}, },
placement: 'bottom'
} }
}, },
created() { created() {
@ -41,6 +42,14 @@
methods: { methods: {
toggle(event) { 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) { if (this.row == null) {
this.open(event) this.open(event)
} else { } else {
@ -83,13 +92,22 @@
this.$refs.div.style.height = clientHeight + 'px' this.$refs.div.style.height = clientHeight + 'px'
this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px' this.overlayStyle.width = Number.parseInt((clientWidth - clientWidth * 0.04)) + 'px'
this.overlayStyle.maxWidth = this.overlayStyle.width 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'], points: ['tl', 'tl'],
offset: [0, 0], offset: [0, h],
overflow: { overflow: {
alwaysByViewport: true alwaysByViewport: true
}, },
}) })
//update-end-author:taoyan date:20200921 for: 子表弹出位置存在现实位置问题。
this.$nextTick(() => { this.$nextTick(() => {
this.visible = true this.visible = true
this.$nextTick(() => { this.$nextTick(() => {

View File

@ -1,6 +1,6 @@
import XEUtils from 'xe-utils' import XEUtils from 'xe-utils'
import PropTypes from 'ant-design-vue/es/_util/vue-types' 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 VxeWebSocketMixins from '../mixins/vxe.web.socket.mixins'
import { initDictOptions } from '@/components/dict/JDictSelectUtil' import { initDictOptions } from '@/components/dict/JDictSelectUtil'
@ -13,7 +13,7 @@ import JVxeDetailsModal from './JVxeDetailsModal'
import JVxePagination from './JVxePagination' import JVxePagination from './JVxePagination'
import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util' import { cloneObject, getVmParentByName, pushIfNotExist, randomString, simpleDebounce } from '@/utils/util'
import { UtilTools } from 'vxe-table/packages/tools/src/utils' import { UtilTools } from 'vxe-table/packages/tools/src/utils'
import { getNoAuthCols } from "@/utils/authFilter" import { getNoAuthCols } from '@/utils/authFilter'
export default { export default {
name: 'JVxeTable', name: 'JVxeTable',
@ -95,6 +95,9 @@ export default {
// 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启, // 是否异步删除行,如果你要实现异步删除,那么需要把这个选项开启,
// 在remove事件里调用confirmRemove方法才会真正删除除非删除的全是新增的行 // 在remove事件里调用confirmRemove方法才会真正删除除非删除的全是新增的行
asyncRemove: PropTypes.bool.def(false), asyncRemove: PropTypes.bool.def(false),
// 是否一直显示组件如果为false则只有点击的时候才出现组件
// 注:该参数不能动态修改;如果行、列字段多的情况下,会根据机器性能造成不同程度的卡顿。
alwaysEdit: PropTypes.bool.def(false),
}, },
data() { data() {
return { return {
@ -181,6 +184,28 @@ export default {
if (column.cellRender) { if (column.cellRender) {
Object.assign(column.cellRender, renderOptions) Object.assign(column.cellRender, renderOptions)
} }
// update--begin--autor:lvdandan-----date:20201019------for:LOWCOD-882 【新行编辑】列表上带按钮的遮挡问题
if (column.$type === JVXETypes.file || column.$type === JVXETypes.image) {
if (column.width && column.width.endsWith('px')) {
column.width = Number.parseInt(column.width.substr(0,column.width.length-2))+Number.parseInt(1)+'px';
}
}
// 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 return this._innerColumns
}, },
@ -332,7 +357,7 @@ export default {
col.visible = false col.visible = false
} else if (enhanced.switches.editRender) { } else if (enhanced.switches.editRender) {
renderName = 'editRender' renderName = 'editRender'
renderOptions.type = enhanced.switches.visible ? 'visible' : 'default' renderOptions.type = (enhanced.switches.visible || this.alwaysEdit) ? 'visible' : 'default'
} }
} else { } else {
renderOptions.name = JVXETypes._prefix + JVXETypes.normal renderOptions.name = JVXETypes._prefix + JVXETypes.normal
@ -702,6 +727,11 @@ export default {
deleteData: this.getDeleteData() deleteData: this.getDeleteData()
} }
}, },
/** 获取表格表单里的值 */
getValues(callback, rowIds) {
let tableData = this.getTableData({rowIds: rowIds})
callback('', tableData)
},
/** 获取表格数据 */ /** 获取表格数据 */
getTableData(options = {}) { getTableData(options = {}) {
let {rowIds} = options let {rowIds} = options
@ -727,6 +757,11 @@ export default {
newData.forEach(row => delete row.id) newData.forEach(row => delete row.id)
return newData return newData
}, },
/** 仅获取新增的数据,带有id */
getNewDataWithId() {
let newData = cloneObject(this.$refs.vxe.getInsertRecords())
return newData
},
/** 根据ID获取行新增的行也能查出来 */ /** 根据ID获取行新增的行也能查出来 */
getIfRowById(id) { getIfRowById(id) {
let row = this.getRowById(id), isNew = false let row = this.getRowById(id), isNew = false
@ -760,8 +795,8 @@ export default {
* @param rows * @param rows
* @return * @return
*/ */
async addRows(rows = {}) { async addRows(rows = {}, isOnlJs) {
return this._addOrInsert(rows, -1, 'added') return this._addOrInsert(rows, -1, 'added', isOnlJs)
}, },
/** /**
@ -852,6 +887,8 @@ export default {
trigger(name, event = {}) { trigger(name, event = {}) {
event.$target = this event.$target = this
event.$table = this.$refs.vxe event.$table = this.$refs.vxe
//online增强参数兼容
event.target = this
this.$emit(name, event) this.$emit(name, event)
}, },
@ -873,7 +910,11 @@ export default {
} }
}) })
}, },
//options自定义赋值 刷新
virtualRefresh(){
this.scrolling = true
this.closeScrolling()
},
// 设置 this.scrolling 防抖模式 // 设置 this.scrolling 防抖模式
closeScrolling: simpleDebounce(function () { closeScrolling: simpleDebounce(function () {
this.scrolling = false this.scrolling = false
@ -1005,7 +1046,7 @@ export default {
return await xTable.updateData() return await xTable.updateData()
}, },
async _addOrInsert(rows = {}, index, triggerName) { async _addOrInsert(rows = {}, index, triggerName, isOnlJs) {
let {xTable} = this.$refs.vxe.$refs let {xTable} = this.$refs.vxe.$refs
let records let records
if (Array.isArray(rows)) { if (Array.isArray(rows)) {
@ -1017,6 +1058,9 @@ export default {
records.forEach(record => this._createRow(record)) records.forEach(record => this._createRow(record))
let result = await this.pushRows(records, {index: index, setActive: true}) let result = await this.pushRows(records, {index: index, setActive: true})
// 遍历插入的行 // 遍历插入的行
// update--begin--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
// online js增强时以传过来值为准不再赋默认值
if (isOnlJs != true) {
for (let i = 0; i < result.rows.length; i++) { for (let i = 0; i < result.rows.length; i++) {
let row = result.rows[i] let row = result.rows[i]
this.trigger(triggerName, { this.trigger(triggerName, {
@ -1025,6 +1069,8 @@ export default {
target: this, target: this,
}) })
} }
}
// update--end--autor:lvdandan-----date:20201117------for:LOWCOD-987 【新行编辑】js增强附表内置方法调用问题 #1819
return result return result
}, },
// 创建新行,自动添加默认值 // 创建新行,自动添加默认值
@ -1033,9 +1079,9 @@ export default {
// 添加默认值 // 添加默认值
xTable.tableFullColumn.forEach(column => { xTable.tableFullColumn.forEach(column => {
let col = column.own 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, 'createValue') let createValue = getEnhancedMixins(col.$type || col.type, 'createValue')
record[col.key] = createValue({row: record, column, $table: xTable}) record[col.key] = createValue({row: record, column, $table: xTable})
} }
}) })
@ -1184,7 +1230,7 @@ export default {
// 兼容 online 的规则 // 兼容 online 的规则
const fooPatterns = [ const fooPatterns = [
{title: '非空', value: '*', pattern: /^.+$/}, {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到16位任意字符', value: '*6-16', pattern: /^.{6,16}$/},
{title: '6到18位字母', value: 's6-18', pattern: /^[a-z|A-Z]{6,18}$/}, {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+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/}, {title: '网址', value: 'url', pattern: /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/},

View File

@ -59,7 +59,7 @@
// TODO 需要将remove替换batch_delete // TODO 需要将remove替换batch_delete
// 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下 // 系统默认的批量删除编码配置为 batch_delete 此处需要转化一下
if(exclude.indexOf('batch_delete')>=0){ if(exclude.indexOf('batch_delete')>=0){
exclude.add('remove') exclude.push('remove')
} }
// 按钮权限 需要去掉不被授权的按钮 // 按钮权限 需要去掉不被授权的按钮
return arr.filter(item=>{ return arr.filter(item=>{

View File

@ -55,7 +55,9 @@
// 【组件增强】注释详见JVxeCellMixins.js // 【组件增强】注释详见JVxeCellMixins.js
enhanced: { enhanced: {
aopEvents: { 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))
},
}, },
} }
} }

View File

@ -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>

View File

@ -34,7 +34,7 @@
return this.rowIndex === 0 return this.rowIndex === 0
}, },
disabledMoveDown() { disabledMoveDown() {
return this.rowIndex === (this.rows.length - 1) return this.rowIndex === (this.fullDataLength - 1)
}, },
}, },
methods: { methods: {

View File

@ -116,7 +116,9 @@
// 【组件增强】注释详见JVxeCellMixins.js // 【组件增强】注释详见JVxeCellMixins.js
enhanced: { enhanced: {
aopEvents: { aopEvents: {
editActived: event => dispatchEvent(event, 'ant-select'), editActived(event) {
dispatchEvent.call(this, event, 'ant-select')
},
}, },
translate: {enabled: true}, translate: {enabled: true},
getValue(value) { getValue(value) {

View File

@ -23,7 +23,9 @@
autofocus: '.ant-input', autofocus: '.ant-input',
}, },
aopEvents: { aopEvents: {
editActived: event => dispatchEvent(event, 'anticon-fullscreen'), editActived(event) {
dispatchEvent.call(this, event, 'anticon-fullscreen')
},
}, },
}, },
} }

View File

@ -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>

View File

@ -1,3 +1,4 @@
import * as jvxeTypes from './jvxeTypes'
import { installCell, mapCell } from './install' import { installCell, mapCell } from './install'
import JVxeTable from './components/JVxeTable' import JVxeTable from './components/JVxeTable'
@ -12,46 +13,13 @@ import { TagsInputCell, TagsSpanCell } from './components/cells/JVxeTagsCell'
import JVxeProgressCell from './components/cells/JVxeProgressCell' import JVxeProgressCell from './components/cells/JVxeProgressCell'
import JVxeTextareaCell from './components/cells/JVxeTextareaCell' import JVxeTextareaCell from './components/cells/JVxeTextareaCell'
import JVxeDragSortCell from './components/cells/JVxeDragSortCell' import JVxeDragSortCell from './components/cells/JVxeDragSortCell'
import JVxeDepartSelectCell from './components/cells/JVxeDepartSelectCell'
import JVxeUserSelectCell from './components/cells/JVxeUserSelectCell'
//update--begin--autor:lvdandan-----date:20201216------forJVxeTable--JVXETypes 【online】代码结构调整便于online打包
// 组件类型 // 组件类型
export const JVXETypes = { export const JVXETypes = jvxeTypes.JVXETypes
// 为了防止和 vxe 内置的类型冲突,所以加上一个前缀 //update--end--autor:lvdandan-----date:20201216------forJVxeTable--JVXETypes 【online】代码结构调整便于online打包
// 前缀是自动加的代码中直接用就行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 AllCells = { export const AllCells = {
@ -72,6 +40,8 @@ export const AllCells = {
...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell), ...mapCell(JVXETypes.rowDragSort, JVxeDragSortCell),
...mapCell(JVXETypes.slot, JVxeSlotCell), ...mapCell(JVXETypes.slot, JVxeSlotCell),
...mapCell(JVXETypes.departSelect, JVxeDepartSelectCell),
...mapCell(JVXETypes.userSelect, JVxeUserSelectCell)
/* hidden 是特殊的组件,不在这里注册 */ /* hidden 是特殊的组件,不在这里注册 */
} }

View File

@ -62,8 +62,8 @@ VXETable.interceptor.add('event.clearActived', function (params, event, target)
if (className.includes('j-input-pop')) { if (className.includes('j-input-pop')) {
return false return false
} }
// 点击的标签是JPopup的弹出层 // 点击的标签是JPopup的弹出层、部门选择、用户选择
if (className.includes('j-popup-modal')) { if (className.includes('j-popup-modal') || className.includes('j-depart-select-modal') || className.includes('j-user-select-modal')) {
return false return false
} }
// 执行增强 // 执行增强

View File

@ -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',
}

View File

@ -36,6 +36,9 @@ export default {
rows() { rows() {
return this.params.data return this.params.data
}, },
fullDataLength() {
return this.params.$table.tableFullData.length
},
rowIndex() { rowIndex() {
return this.params.rowIndex return this.params.rowIndex
}, },
@ -149,6 +152,8 @@ export default {
packageEvent(name, event = {}) { packageEvent(name, event = {}) {
event.row = this.row event.row = this.row
event.column = this.column event.column = this.column
//online增强参数兼容
event.column['key'] = this.column['property']
event.cellTarget = this event.cellTarget = this
if (!event.type) { if (!event.type) {
event.type = name event.type = name
@ -289,6 +294,10 @@ export function vModel(value, row, property) {
/** 模拟触发事件 */ /** 模拟触发事件 */
export function dispatchEvent({cell, $event}, className, handler) { export function dispatchEvent({cell, $event}, className, handler) {
// alwaysEdit 下不模拟触发事件,否者会导致触发两次
if (this && this.alwaysEdit) {
return
}
window.setTimeout(() => { window.setTimeout(() => {
let element = cell.getElementsByClassName(className) let element = cell.getElementsByClassName(className)
if (element && element.length > 0) { if (element && element.length > 0) {
@ -296,8 +305,10 @@ export function dispatchEvent({cell, $event}, className, handler) {
handler(element[0]) handler(element[0])
} else { } else {
// 模拟触发点击事件 // 模拟触发点击事件
if($event){
element[0].dispatchEvent($event) element[0].dispatchEvent($event)
} }
} }
}
}, 10) }, 10)
} }

View File

@ -141,6 +141,33 @@ export async function validateFormAndTables(form, cases, autoJumpTab) {
return dataMap 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
}
/** /**
* 验证并获取一个或多个表格的所有值 * 验证并获取一个或多个表格的所有值
* *

View File

@ -258,7 +258,7 @@ export default {
components: { JTreeTable }, components: { JTreeTable },
data() { data() {
return { return {
url: '/api/asynTreeList', url: '/mock/api/asynTreeList',
columns: [ columns: [
{ title: '菜单名称', dataIndex: 'name' }, { title: '菜单名称', dataIndex: 'name' },
{ title: '组件', dataIndex: 'component' }, { title: '组件', dataIndex: 'component' },

View File

@ -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 &nbsp; 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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
}

View File

@ -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;
}
});

View File

@ -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)};
});
});

View File

@ -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

View File

@ -1,11 +1,77 @@
import JModal from './JModal' import JModal from './JModal'
import JFormContainer from './JFormContainer.vue' import JFormContainer from './JFormContainer.vue'
import JPopup from './JPopup.vue' import JPopup from './JPopup.vue'
import JMarkdownEditor from './JMarkdownEditor'
import JCodeEditor from './JCodeEditor.vue'
import JEditor from './JEditor.vue'
import JEditableTable from './JEditableTable.vue'
import JAreaLinkage from './JAreaLinkage.vue'
import JSuperQuery from './JSuperQuery.vue'
import JUpload from './JUpload.vue'
import JTreeSelect from './JTreeSelect.vue'
import JCategorySelect from './JCategorySelect.vue'
import JImageUpload from './JImageUpload.vue'
import JImportModal from './JImportModal.vue'
import JTreeDict from './JTreeDict.vue'
import JCheckbox from './JCheckbox.vue'
import JCron from './JCron.vue'
import JDate from './JDate.vue'
import JEllipsis from './JEllipsis.vue'
import JInput from './JInput.vue'
import JPopupOnlReport from './modal/JPopupOnlReport.vue'
import JFilePop from './minipop/JFilePop.vue'
import JInputPop from './minipop/JInputPop.vue'
import JSelectMultiple from './JSelectMultiple.vue'
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 { export default {
install(Vue) { install(Vue) {
Vue.component('JFormContainer', JFormContainer) Vue.component('JMarkdownEditor', JMarkdownEditor)
Vue.component('JPopup', JPopup)
Vue.component(JModal.name, JModal) Vue.component(JModal.name, JModal)
Vue.component('JPopupOnlReport', JPopupOnlReport)
Vue.component('JFilePop', JFilePop)
Vue.component('JInputPop', JInputPop)
Vue.component('JAreaLinkage', JAreaLinkage)
Vue.component('JCategorySelect', JCategorySelect)
Vue.component('JCheckbox', JCheckbox)
Vue.component('JCodeEditor', JCodeEditor)
Vue.component('JCron', JCron)
Vue.component('JDate', JDate)
Vue.component('JEditableTable', JEditableTable)
Vue.component('JEditor', JEditor)
Vue.component('JEllipsis', JEllipsis)
Vue.component('JFormContainer', JFormContainer)
Vue.component('JImageUpload', JImageUpload)
Vue.component('JImportModal', JImportModal)
Vue.component('JInput', JInput)
Vue.component('JPopup', JPopup)
Vue.component('JSelectMultiple', JSelectMultiple)
Vue.component('JSlider', JSlider)
Vue.component('JSuperQuery', JSuperQuery)
Vue.component('JSwitch', JSwitch)
Vue.component('JTime', JTime)
Vue.component('JTreeDict', JTreeDict)
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)
} }
} }

View File

@ -8,13 +8,12 @@
cancelText="取消" cancelText="取消"
@cancel="close"> @cancel="close">
<!--style="top: 20px;"--> <!--style="top: 20px;"-->
<j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled"></j-upload> <j-upload :file-type="fileType" :value="filePath" @change="handleChange" :disabled="disabled" :number="number"></j-upload>
</a-modal> </a-modal>
</div> </div>
</template> </template>
<script> <script>
import JUpload from '@/components/jeecg/JUpload'
import { getFileAccessHttpUrl } from '@/api/manage'; import { getFileAccessHttpUrl } from '@/api/manage';
const getFileName=(path)=>{ const getFileName=(path)=>{
@ -27,7 +26,7 @@
export default { export default {
name: 'JFilePop', name: 'JFilePop',
components: { JUpload }, components: { },
props:{ props:{
title:{ title:{
type:String, type:String,
@ -59,6 +58,11 @@
type:Boolean, type:Boolean,
default:false, default:false,
required:false required:false
},
number:{
type:Number,
required:false,
default: 0
} }
}, },
data(){ data(){

View File

@ -1,6 +1,6 @@
<template> <template>
<a-modal <a-modal
title="corn表达式" title="cron表达式"
:width="modalWidth" :width="modalWidth"
:visible="visible" :visible="visible"
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"

View File

@ -78,7 +78,7 @@
const MODAL_WIDTH = 1200; const MODAL_WIDTH = 1200;
export default { export default {
name: 'JPopupOnlReport', name: 'JPopupOnlReport',
props: ['multi', 'code', 'groupId'], props: ['multi', 'code', 'sorter', 'groupId', 'param'],
components:{ components:{
}, },
data(){ data(){
@ -121,17 +121,47 @@
}, },
cgRpConfigId:"", cgRpConfigId:"",
modalWidth:MODAL_WIDTH, modalWidth:MODAL_WIDTH,
tableScroll:{x:MODAL_WIDTH-100} tableScroll:{x:true},
dynamicParam:{},
// 排序字段,默认无排序
iSorter: null,
} }
}, },
mounted() { mounted() {
this.loadColumnsInfo() //this.loadColumnsInfo()
}, },
watch: { watch: {
code() { code() {
this.loadColumnsInfo() this.loadColumnsInfo()
},
param:{
deep:true,
handler(){
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:{ computed:{
showSearchFlag(){ showSearchFlag(){
@ -159,10 +189,13 @@
return filterMultiDictText(this.dictOptions[dictCode], text+""); 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.table.columns = [...currColumns]
this.initQueryInfo() this.initQueryInfo()
this.loadData(1)
} }
}) })
}, },
@ -176,12 +209,43 @@
httpGroupRequest(() => getAction(url), groupIdKey).then((res) => { httpGroupRequest(() => getAction(url), groupIdKey).then((res) => {
// console.log("获取查询条件", res); // console.log("获取查询条件", res);
if (res.success) { if (res.success) {
this.dynamicParamHandler(res.result)
this.queryInfo = res.result this.queryInfo = res.result
//查询条件加载后再请求数据
this.loadData(1)
} else { } else {
this.$message.warning(res.message) this.$message.warning(res.message)
} }
}) })
}, },
//处理动态参数
dynamicParamHandler(arr){
if(arr && arr.length>0){
//第一次加载查询条件前 初始化queryParam为空对象
let queryTemp = {}
for(let item of arr){
if(item.mode==='single'){
queryTemp[item.field] = ''
}
}
this.queryParam = {...queryTemp}
}
let dynamicTemp = {}
if(this.param){
Object.keys(this.param).map(key=>{
let str = this.param[key]
if(key in this.queryParam){
if(str && str.startsWith("'") && str.endsWith("'")){
str = str.substring(1,str.length-1)
}
//如果查询条件包含参数 设置值
this.queryParam[key]=str
}
dynamicTemp[key] = this.param[key]
})
}
this.dynamicParam = {...dynamicTemp}
},
loadData(arg) { loadData(arg) {
if (arg == 1) { if (arg == 1) {
this.table.pagination.current = 1 this.table.pagination.current = 1
@ -208,7 +272,14 @@
}) })
}, },
getQueryParams() { getQueryParams() {
let param = Object.assign({}, this.queryParam, this.sorter); let paramTarget = {}
if(this.dynamicParam){
//处理自定义参数
Object.keys(this.dynamicParam).map(key=>{
paramTarget['self_'+key] = this.dynamicParam[key]
})
}
let param = Object.assign(paramTarget, this.queryParam, this.iSorter);
param.pageNo = this.table.pagination.current; param.pageNo = this.table.pagination.current;
param.pageSize = this.table.pagination.pageSize; param.pageSize = this.table.pagination.pageSize;
return filterObj(param); return filterObj(param);
@ -243,8 +314,18 @@
handleChangeInTable(pagination, filters, sorter) { handleChangeInTable(pagination, filters, sorter) {
//分页、排序、筛选变化时触发 //分页、排序、筛选变化时触发
if (Object.keys(sorter).length > 0) { if (Object.keys(sorter).length > 0) {
this.sorter.column = sorter.field this.iSorter = {
this.sorter.order = 'ascend' == sorter.order ? 'asc' : 'desc' 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.table.pagination = pagination
this.loadData() this.loadData()
@ -272,7 +353,8 @@
this.onClearSelected() this.onClearSelected()
}, },
show(){ show(){
this.visible = true; this.visible = true
this.loadColumnsInfo()
}, },
handleToggleSearch(){ handleToggleSearch(){
this.toggleSearchStatus = !this.toggleSearchStatus; this.toggleSearchStatus = !this.toggleSearchStatus;
@ -296,7 +378,13 @@
combineRowKey(record){ combineRowKey(record){
let res = '' let res = ''
Object.keys(record).forEach(key=>{ Object.keys(record).forEach(key=>{
//update-begin---author:liusq Date:20210203 forpop选择器列主键问题 issues/I29P9Q------------
if(key=='id'){
res=record[key]+res
}else{
res+=record[key] res+=record[key]
}
//update-end---author:liusq Date:20210203 forpop选择器列主键问题 issues/I29P9Q------------
}) })
if(res.length>50){ if(res.length>50){
res = res.substring(0,50) res = res.substring(0,50)

View File

@ -12,7 +12,7 @@
:open="selectOpen" :open="selectOpen"
style="width: 100%;" style="width: 100%;"
@dropdownVisibleChange="handleDropdownVisibleChange" @dropdownVisibleChange="handleDropdownVisibleChange"
@click.native="visible=(buttons?visible:true)" @click.native="visible=(buttons || disabled ?visible:true)"
/> />
</slot> </slot>
</a-col> </a-col>

View File

@ -53,6 +53,11 @@
customReturnField: { customReturnField: {
type: String, type: String,
default: 'id' default: 'id'
},
backDepart: {
type: Boolean,
default: false,
required: false
} }
}, },
data(){ data(){
@ -68,9 +73,11 @@
}, },
watch:{ watch:{
value(val){ value(val){
if (this.customReturnField === 'id') { //update-begin-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
// if (this.customReturnField === 'id') {
this.departIds = val this.departIds = val
} // }
//update-end-author:wangshuai date:20201124 for:组件 JSelectDepart.vue不是默认id时新内容编辑问题 gitee I247X2
} }
}, },
methods:{ methods:{
@ -89,6 +96,23 @@
} }
//update-end-author:lvdandan date:20200513 for:TESTA-438 部门选择组件自定义返回值,数据无法回填 //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(){ openModal(){
this.$refs.innerDepartSelectModal.show() this.$refs.innerDepartSelectModal.show()
}, },
@ -103,6 +127,7 @@
this.departIds = idstr this.departIds = idstr
} }
this.$emit("change", value) this.$emit("change", value)
this.backDeparInfo()
}, },
getDepartNames(){ getDepartNames(){
return this.departNames return this.departNames

View File

@ -38,6 +38,11 @@
default: true, default: true,
required: false required: false
}, },
backUser: {
type: Boolean,
default: false,
required: false
}
}, },
data() { data() {
return { return {
@ -61,6 +66,23 @@
initComp(userNames) { initComp(userNames) {
this.userNames = 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() { onSearchDepUser() {
this.$refs.selectModal.showModal() this.$refs.selectModal.showModal()
}, },

View File

@ -6,6 +6,7 @@
:confirmLoading="confirmLoading" :confirmLoading="confirmLoading"
@ok="handleSubmit" @ok="handleSubmit"
@cancel="handleCancel" @cancel="handleCancel"
wrapClassName="j-depart-select-modal"
switchFullscreen switchFullscreen
cancelText="关闭"> cancelText="关闭">
<a-spin tip="Loading..." :spinning="false"> <a-spin tip="Loading..." :spinning="false">
@ -166,7 +167,9 @@
if(!this.checkedKeys || this.checkedKeys.length==0){ if(!this.checkedKeys || this.checkedKeys.length==0){
this.$emit("ok",'') this.$emit("ok",'')
}else{ }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() this.handleClear()
}, },

View File

@ -4,6 +4,7 @@
:visible="visible" :visible="visible"
:title="title" :title="title"
switchFullscreen switchFullscreen
wrapClassName="j-user-select-modal"
@ok="handleSubmit" @ok="handleSubmit"
@cancel="close" @cancel="close"
style="top:50px" style="top:50px"
@ -55,8 +56,9 @@
</template> </template>
<script> <script>
import {filterObj} from '@/utils/util' import { pushIfNotExist, filterObj } from '@/utils/util'
import {queryDepartTreeList, getUserList, queryUserByDepId} from '@/api/api' import {queryDepartTreeList, getUserList, queryUserByDepId} from '@/api/api'
import { getAction } from '@/api/manage'
export default { export default {
name: 'JSelectUserByDepModal', name: 'JSelectUserByDepModal',
@ -100,11 +102,12 @@
{ {
title: '部门', title: '部门',
align: 'center', align: 'center',
dataIndex: 'orgCode' dataIndex: 'orgCodeTxt'
} }
], ],
scrollTrigger: {}, scrollTrigger: {},
dataSource: [], dataSource: [],
selectionRows: [],
selectedRowKeys: [], selectedRowKeys: [],
selectUserRows: [], selectUserRows: [],
selectUserIds: [], selectUserIds: [],
@ -162,11 +165,13 @@
pageSize: values.length pageSize: values.length
}).then((res) => { }).then((res) => {
if (res.success) { if (res.success) {
this.selectionRows = []
let selectedRowKeys = [] let selectedRowKeys = []
let realNames = [] let realNames = []
res.result.records.forEach(user => { res.result.records.forEach(user => {
realNames.push(user['realname']) realNames.push(user['realname'])
selectedRowKeys.push(user['id']) selectedRowKeys.push(user['id'])
this.selectionRows.push(user)
}) })
this.selectedRowKeys = selectedRowKeys this.selectedRowKeys = selectedRowKeys
this.$emit('initComp', realNames.join(',')) this.$emit('initComp', realNames.join(','))
@ -181,12 +186,9 @@
if (arg === 1) { if (arg === 1) {
this.ipagination.current = 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()//查询条件 let params = this.getQueryParams()//查询条件
await getUserList(params).then((res) => { this.loading = true
getAction('/sys/user/queryUserComponentData', params).then(res=>{
if (res.success) { if (res.success) {
this.dataSource = res.result.records this.dataSource = res.result.records
this.ipagination.total = res.result.total this.ipagination.total = res.result.total
@ -194,7 +196,6 @@
}).finally(() => { }).finally(() => {
this.loading = false this.loading = false
}) })
}
}, },
// 触发屏幕自适应 // 触发屏幕自适应
resetScreenSize() { resetScreenSize() {
@ -217,6 +218,7 @@
param.field = this.getQueryField(); param.field = this.getQueryField();
param.pageNo = this.ipagination.current; param.pageNo = this.ipagination.current;
param.pageSize = this.ipagination.pageSize; param.pageSize = this.ipagination.pageSize;
param.departId = this.selectedDepIds.join(',')
return filterObj(param); return filterObj(param);
}, },
getQueryField() { getQueryField() {
@ -228,13 +230,13 @@
}, },
searchReset(num) { searchReset(num) {
let that = this; let that = this;
that.selectedRowKeys = [];
that.selectUserIds = [];
that.selectedDepIds = [];
if (num !== 0) { if (num !== 0) {
that.queryParam = {}; that.queryParam = {};
that.loadData(1); that.loadData(1);
} }
that.selectedRowKeys = [];
that.selectUserIds = [];
that.selectedDepIds = [];
}, },
close() { close() {
this.searchReset(0); this.searchReset(0);
@ -257,30 +259,27 @@
that.close(); that.close();
}, },
//获取选择用户信息 //获取选择用户信息
getSelectUserRows(rowId) { getSelectUserRows() {
let dataSource = this.dataSource; this.selectUserRows = []
let userIds = ""; for (let row of this.selectionRows) {
this.selectUserRows = []; if (this.selectedRowKeys.includes(row.id)) {
for (let i = 0, len = dataSource.length; i < len; i++) { this.selectUserRows.push(row)
if (this.selectedRowKeys.includes(dataSource[i].id)) {
this.selectUserRows.push(dataSource[i]);
userIds = userIds + "," + dataSource[i].username
} }
} }
this.selectUserIds = userIds.substring(1); this.selectUserIds = this.selectUserRows.map(row => row.username).join(',')
}, },
// 点击树节点,筛选出对应的用户 // 点击树节点,筛选出对应的用户
onDepSelect(selectedDepIds) { onDepSelect(selectedDepIds) {
if (selectedDepIds[0] != null) { if (selectedDepIds[0] != null) {
this.initQueryUserByDepId(selectedDepIds); // 调用方法根据选选择的id查询用户信息
if (this.selectedDepIds[0] !== selectedDepIds[0]) { if (this.selectedDepIds[0] !== selectedDepIds[0]) {
this.selectedDepIds = [selectedDepIds[0]]; this.selectedDepIds = [selectedDepIds[0]];
} }
this.loadData(1);
} }
}, },
onSelectChange(selectedRowKeys, selectionRows) { onSelectChange(selectedRowKeys, selectionRows) {
this.selectedRowKeys = selectedRowKeys; this.selectedRowKeys = selectedRowKeys;
this.selectionRows = selectionRows; selectionRows.forEach(row => pushIfNotExist(this.selectionRows, row, 'id'))
}, },
onSearch() { onSearch() {
this.loadData(1); this.loadData(1);

View File

@ -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>

View File

@ -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>

View File

@ -38,16 +38,20 @@
//url = "http://www.baidu.com" //url = "http://www.baidu.com"
console.log("------url------"+url) console.log("------url------"+url)
if (url !== null && url !== undefined) { if (url !== null && url !== undefined) {
this.url = url; //-----------------------------------------------------------------------------------------
/*update_begin author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */ //url支持通过 ${token}方式传递当前登录TOKEN
if(this.$route.meta.internalOrExternal != undefined && this.$route.meta.internalOrExternal==true){
this.closeCurrent();
//外部url加入token
let tokenStr = "${token}"; let tokenStr = "${token}";
if(url.indexOf(tokenStr)!=-1) { if(url.indexOf(tokenStr)!=-1) {
let token = Vue.ls.get(ACCESS_TOKEN); let token = Vue.ls.get(ACCESS_TOKEN);
this.url = url.replace(tokenStr, 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();
window.open(this.url); window.open(this.url);
} }
/*update_end author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */ /*update_end author:wuxianquan date:20190908 for:判断打开方式新窗口打开时this.$route.meta.internalOrExternal==true */

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="main"> <div class="main">
<keep-alive> <keep-alive :include="includedComponents">
<router-view v-if="keepAlive" /> <router-view v-if="keepAlive" />
</keep-alive> </keep-alive>
<router-view v-if="!keepAlive" /> <router-view v-if="!keepAlive" />
@ -8,9 +8,32 @@
</template> </template>
<script> <script>
import Vue from 'vue'
import { CACHE_INCLUDED_ROUTES } from "@/store/mutation-types"
export default { export default {
name: "RouteView", name: "RouteView",
computed: { computed: {
//update-begin--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
includedComponents() {
const includedRouters = Vue.ls.get(CACHE_INCLUDED_ROUTES)
console.log("includedRouters" + includedRouters)
//如果是缓存路由,则加入到 cache_included_routes
if (this.$route.meta.keepAlive && this.$route.meta.componentName) {
let cacheRouterArray = Vue.ls.get(CACHE_INCLUDED_ROUTES) || []
if(!cacheRouterArray.includes(this.$route.meta.componentName)){
cacheRouterArray.push(this.$route.meta.componentName)
// cacheRouterArray.push("OnlCgformHeadList")
console.log("Vue ls set componentName " + this.$route.meta.componentName)
Vue.ls.set(CACHE_INCLUDED_ROUTES, cacheRouterArray)
console.log("Vue ls includedRouterArrays " + Vue.ls.get(CACHE_INCLUDED_ROUTES))
return cacheRouterArray;
}
}
return includedRouters;
},
//update-end--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
keepAlive () { keepAlive () {
return this.$route.meta.keepAlive return this.$route.meta.keepAlive
} }

View File

@ -14,19 +14,19 @@
@change="changePage" @change="changePage"
@tabClick="tabCallBack" @tabClick="tabCallBack"
@edit="editPage"> @edit="editPage">
<a-tab-pane :id="page.fullPath" :key="page.fullPath" v-for="page in pageList"> <a-tab-pane :id="page.fullPath" :key="page.fullPath" v-for="page in pageList" :closable="!(page.meta.title=='首页')">
<span slot="tab" :pagekey="page.fullPath">{{ page.meta.title }}</span> <span slot="tab" :pagekey="page.fullPath">{{ page.meta.title }}</span>
</a-tab-pane> </a-tab-pane>
</a-tabs> </a-tabs>
<div style="margin: 12px 12px 0;"> <div style="margin: 12px 12px 0;">
<transition name="page-toggle"> <!-- update-begin-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
<keep-alive v-if="multipage"> <keep-alive v-if="multipage">
<router-view v-if="reloadFlag"/> <router-view v-if="reloadFlag"/>
</keep-alive> </keep-alive>
<template v-else> <template v-else>
<router-view v-if="reloadFlag"/> <router-view v-if="reloadFlag"/>
</template> </template>
</transition> <!-- update-end-author:taoyan date:20201221 for:此处删掉transition标签 不知道为什么加上后 页面路由切换的时候即1及菜单切到2及菜单的时候 两个菜单页面会同时出现300-500秒左右 -->
</div> </div>
</global-layout> </global-layout>
</template> </template>
@ -36,6 +36,8 @@
import Contextmenu from '@/components/menu/Contextmenu' import Contextmenu from '@/components/menu/Contextmenu'
import { mixin, mixinDevice } from '@/utils/mixin.js' import { mixin, mixinDevice } from '@/utils/mixin.js'
import { triggerWindowResizeEvent } from '@/utils/util' import { triggerWindowResizeEvent } from '@/utils/util'
import Vue from 'vue'
import { CACHE_INCLUDED_ROUTES } from '@/store/mutation-types'
const indexKey = '/dashboard/analysis' const indexKey = '/dashboard/analysis'
@ -85,13 +87,6 @@
// 复制一个route对象出来不能影响原route // 复制一个route对象出来不能影响原route
let currentRoute = Object.assign({}, this.$route) let currentRoute = Object.assign({}, this.$route)
currentRoute.meta = Object.assign({}, currentRoute.meta) 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.pageList.push(currentRoute)
this.linkList.push(currentRoute.fullPath) this.linkList.push(currentRoute.fullPath)
this.activePage = currentRoute.fullPath this.activePage = currentRoute.fullPath
@ -115,11 +110,11 @@
}else if (this.linkList.indexOf(newRoute.fullPath) < 0) { }else if (this.linkList.indexOf(newRoute.fullPath) < 0) {
this.linkList.push(newRoute.fullPath) this.linkList.push(newRoute.fullPath)
this.pageList.push(Object.assign({},newRoute)) this.pageList.push(Object.assign({},newRoute))
// update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842 //// update-begin-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842
// if (newRoute.meta.keepAlive) { // if (newRoute.meta.keepAlive) {
// this.routeReload() // this.routeReload()
// } // }
// update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842 //// update-end-author:sunjianlei date:20200103 for: 如果新增的页面配置了缓存路由,那么就强制刷新一遍 #842
} else if (this.linkList.indexOf(newRoute.fullPath) >= 0) { } else if (this.linkList.indexOf(newRoute.fullPath) >= 0) {
let oldIndex = this.linkList.indexOf(newRoute.fullPath) let oldIndex = this.linkList.indexOf(newRoute.fullPath)
let oldPositionRoute = this.pageList[oldIndex] let oldPositionRoute = this.pageList[oldIndex]
@ -132,8 +127,8 @@
// 【TESTA-523】修复不允许重复跳转路由异常 // 【TESTA-523】修复不允许重复跳转路由异常
if (waitRouter.fullPath !== this.$route.fullPath) { if (waitRouter.fullPath !== this.$route.fullPath) {
this.$router.push(Object.assign({}, waitRouter)) this.$router.push(Object.assign({}, waitRouter))
this.changeTitle(waitRouter.meta.title)
} }
this.changeTitle(waitRouter.meta.title)
}, },
'multipage': function(newVal) { 'multipage': function(newVal) {
if(this.reloadFlag){ if(this.reloadFlag){
@ -170,7 +165,7 @@
// update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题 // update-begin-author:sunjianlei date:20200120 for: 动态更改页面标题
changeTitle(title) { changeTitle(title) {
let projectTitle = "Jeecg-Boot 企业级快速开发平台" let projectTitle = "Jeecg-Boot 企业级低代码平台"
// 首页特殊处理 // 首页特殊处理
if (this.$route.path === indexKey) { if (this.$route.path === indexKey) {
document.title = projectTitle document.title = projectTitle
@ -185,7 +180,12 @@
}, },
tabCallBack() { tabCallBack() {
this.$nextTick(() => { this.$nextTick(() => {
//update-begin-author:taoyan date: 20201211 for:【新版】online报错 JT-100
setTimeout(()=>{
//省市区组件里面给window绑定了个resize事件 导致切换页面的时候触发了他的resize但是切换页面省市区组件还没被销毁前就触发了该事件导致控制台报错加个延迟
triggerWindowResizeEvent() triggerWindowResizeEvent()
},20)
//update-end-author:taoyan date: 20201211 for:【新版】online报错 JT-100
}) })
}, },
editPage(key, action) { editPage(key, action) {
@ -201,11 +201,27 @@
return return
} }
console.log("this.pageList ",this.pageList ); console.log("this.pageList ",this.pageList );
let removeRoute = this.pageList.filter(item => item.fullPath == key)
this.pageList = this.pageList.filter(item => item.fullPath !== key) this.pageList = this.pageList.filter(item => item.fullPath !== key)
let index = this.linkList.indexOf(key) let index = this.linkList.indexOf(key)
this.linkList = this.linkList.filter(item => item !== key) this.linkList = this.linkList.filter(item => item !== key)
index = index >= this.linkList.length ? this.linkList.length - 1 : index index = index >= this.linkList.length ? this.linkList.length - 1 : index
this.activePage = this.linkList[index] this.activePage = this.linkList[index]
//update-begin--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
//关闭页面则从缓存cache_included_routes中删除路由下次点击菜单会重新加载页面
let cacheRouterArray = Vue.ls.get(CACHE_INCLUDED_ROUTES) || []
if (removeRoute && removeRoute[0]) {
let componentName = removeRoute[0].meta.componentName
console.log("key: ", key);
console.log("componentName: ", componentName);
if(cacheRouterArray.includes(componentName)){
cacheRouterArray.splice(cacheRouterArray.findIndex(item => item === componentName), 1)
Vue.ls.set(CACHE_INCLUDED_ROUTES, cacheRouterArray)
}
}
//update-end--Author:scott Date:20201015 for路由缓存问题关闭了tab页时再打开就不刷新 #842
}, },
onContextmenu(e) { onContextmenu(e) {
const pagekey = this.getPageKey(e.target) const pagekey = this.getPageKey(e.target)

View File

@ -9,7 +9,7 @@
</a> </a>
</div> </div>
<div class="desc"> <div class="desc">
Jeecg Boot 是中国最具影响力的 企业级 快速开发平台 Jeecg Boot 是中国最具影响力的 企业级 低代码平台
</div> </div>
</div> </div>

View File

@ -1,3 +1,6 @@
/**
* 按需加载antd组件
*/
import Vue from 'vue' import Vue from 'vue'
// base library // base library
@ -50,6 +53,12 @@ import {
TreeSelect, TreeSelect,
Carousel, Carousel,
Pagination, Pagination,
FormModel,
Cascader,
Slider,
Transfer,
Rate,
Collapse,
} from 'ant-design-vue' } from 'ant-design-vue'
import Viser from 'viser-vue' import Viser from 'viser-vue'
@ -99,6 +108,12 @@ Vue.use(Tree)
Vue.use(TreeSelect) Vue.use(TreeSelect)
Vue.use(Carousel) Vue.use(Carousel)
Vue.use(Pagination) 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.$confirm = Modal.confirm
Vue.prototype.$message = message Vue.prototype.$message = message

View File

@ -1,7 +1,7 @@
<template> <template>
<a-layout-sider <a-layout-sider
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]" :class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
width="200px" width="208px"
:collapsible="collapsible" :collapsible="collapsible"
v-model="collapsed" v-model="collapsed"
:trigger="null"> :trigger="null">
@ -11,6 +11,7 @@
:menu="menus" :menu="menus"
:theme="theme" :theme="theme"
@select="onSelect" @select="onSelect"
@updateMenuTitle="onUpdateMenuTitle"
:mode="mode" :mode="mode"
:style="smenuStyle"> :style="smenuStyle">
</s-menu> </s-menu>
@ -19,7 +20,7 @@
</template> </template>
<script> <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 Logo from '../tools/Logo'
import SMenu from './index' import SMenu from './index'
import { mixin, mixinDevice } from '@/utils/mixin.js' import { mixin, mixinDevice } from '@/utils/mixin.js'
@ -68,6 +69,9 @@
methods: { methods: {
onSelect (obj) { onSelect (obj) {
this.$emit('menuSelect', obj) this.$emit('menuSelect', obj)
},
onUpdateMenuTitle (obj) {
this.$emit('updateMenuTitle', obj)
} }
} }
} }
@ -141,7 +145,6 @@
} }
/* update_end author:sunjianlei date:20190509 for: 修改侧边导航栏滚动条的样式 */ /* update_end author:sunjianlei date:20190509 for: 修改侧边导航栏滚动条的样式 */
</style> </style>
<!-- update_begin author:sunjianlei date:20190530 for: 选中首页的时候不显示背景颜色 --> <!-- update_begin author:sunjianlei date:20190530 for: 选中首页的时候不显示背景颜色 -->

View File

@ -82,18 +82,49 @@ export default {
} else { } else {
this.selectedKeys = [routes.pop().path] this.selectedKeys = [routes.pop().path]
} }
const openKeys = [] let openKeys = []
if (this.mode === 'inline') { if (this.mode === 'inline') {
routes.forEach(item => { routes.forEach(item => {
openKeys.push(item.path) 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表单菜单点击展开的一级目录不对 //update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对
if(!this.selectedKeys || this.selectedKeys[0].indexOf(":")<0){ if(!this.selectedKeys || this.selectedKeys[0].indexOf(":")<0){
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys) this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
} }
//update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对 //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 // render
renderItem (menu) { renderItem (menu) {

View File

@ -17,7 +17,7 @@
:type="collapsed ? 'menu-unfold' : 'menu-fold'" :type="collapsed ? 'menu-unfold' : 'menu-fold'"
@click="toggle"/> @click="toggle"/>
<span v-if="device === 'desktop'">欢迎进入 Jeecg-Boot 企业级快速开发平台</span> <span v-if="device === 'desktop'">欢迎进入 Jeecg-Boot 企业级低代码平台</span>
<span v-else>Jeecg-Boot</span> <span v-else>Jeecg-Boot</span>
<user-menu :theme="theme"/> <user-menu :theme="theme"/>
@ -31,7 +31,9 @@
<s-menu <s-menu
mode="horizontal" mode="horizontal"
:menu="menus" :menu="menus"
:theme="theme"></s-menu> :theme="theme"
@updateMenuTitle="handleUpdateMenuTitle"
></s-menu>
</div> </div>
<a-icon <a-icon
v-else v-else
@ -50,7 +52,6 @@
import UserMenu from '../tools/UserMenu' import UserMenu from '../tools/UserMenu'
import SMenu from '../menu/' import SMenu from '../menu/'
import Logo from '../tools/Logo' import Logo from '../tools/Logo'
import { mixin } from '@/utils/mixin.js' import { mixin } from '@/utils/mixin.js'
export default { export default {
@ -156,8 +157,15 @@
this.topMenuStyle.headerIndexLeft = { 'width': `calc(100% - ${rightWidth})` } this.topMenuStyle.headerIndexLeft = { 'width': `calc(100% - ${rightWidth})` }
} }
} }
} },
//update-begin--author:sunjianlei---date:20190508------for: 顶部导航栏过长时显示更多按钮----- //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> </script>

View File

@ -16,6 +16,7 @@
v-if="device === 'mobile'" v-if="device === 'mobile'"
:menus="menus" :menus="menus"
@menuSelect="menuSelect" @menuSelect="menuSelect"
@updateMenuTitle="handleUpdateMenuTitle"
:theme="navTheme" :theme="navTheme"
:collapsed="false" :collapsed="false"
:collapsible="true"></side-menu> :collapsible="true"></side-menu>
@ -26,6 +27,7 @@
mode="inline" mode="inline"
:menus="menus" :menus="menus"
@menuSelect="myMenuSelect" @menuSelect="myMenuSelect"
@updateMenuTitle="handleUpdateMenuTitle"
:theme="navTheme" :theme="navTheme"
:collapsed="collapsed" :collapsed="collapsed"
:collapsible="true"></side-menu> :collapsible="true"></side-menu>
@ -45,6 +47,7 @@
mode="inline" mode="inline"
:menus="menus" :menus="menus"
@menuSelect="menuSelect" @menuSelect="menuSelect"
@updateMenuTitle="handleUpdateMenuTitle"
:theme="navTheme" :theme="navTheme"
:collapsed="false" :collapsed="false"
:collapsible="true"></side-menu> :collapsible="true"></side-menu>
@ -62,6 +65,7 @@
:collapsed="collapsed" :collapsed="collapsed"
:device="device" :device="device"
@toggle="toggle" @toggle="toggle"
@updateMenuTitle="handleUpdateMenuTitle"
/> />
<!-- layout content --> <!-- layout content -->
@ -85,15 +89,14 @@
import SideMenu from '@/components/menu/SideMenu' import SideMenu from '@/components/menu/SideMenu'
import GlobalHeader from '@/components/page/GlobalHeader' import GlobalHeader from '@/components/page/GlobalHeader'
import GlobalFooter from '@/components/page/GlobalFooter' 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 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------ // update-start---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------
// import SettingDrawer from '@/components/setting/SettingDrawer' // import SettingDrawer from '@/components/setting/SettingDrawer'
// 注释这个因为在个人设置模块已经加载了SettingDrawer页面 // 注释这个因为在个人设置模块已经加载了SettingDrawer页面
// update-end ---- author:os_chengtgen -- date:20190830 -- for:issues/463 -编译主题颜色已生效,但还一直转圈,显示主题 正在编译 ------ // 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 { export default {
name: 'GlobalLayout', name: 'GlobalLayout',
components: { components: {
@ -131,6 +134,11 @@
//--update-begin----author:scott---date:20190320------for:根据后台菜单配置判断是否路由菜单字段动态选择是否生成路由为了支持参数URL菜单------ //--update-begin----author:scott---date:20190320------for:根据后台菜单配置判断是否路由菜单字段动态选择是否生成路由为了支持参数URL菜单------
//this.menus = this.mainRouters.find((item) => item.path === '/').children; //this.menus = this.mainRouters.find((item) => item.path === '/').children;
this.menus = this.permissionMenuList 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('----加载菜单逻辑----')
//console.log(this.mainRouters) //console.log(this.mainRouters)
@ -155,10 +163,6 @@
//此处触发动态路由被点击事件 //此处触发动态路由被点击事件
this.findMenuBykey(this.menus,value.key) this.findMenuBykey(this.menus,value.key)
this.$emit("dynamicRouterShow",value.key,this.activeMenu.meta.title) 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){ findMenuBykey(menus,key){
for(let i of menus){ for(let i of menus){
@ -168,8 +172,17 @@
this.findMenuBykey(i.children,key) this.findMenuBykey(i.children,key)
} }
} }
} },
//update-end-author:taoyan date:20190430 for:动态路由title显示配置的菜单title而不是其对应路由的title //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: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题
} }
} }

View File

@ -6,7 +6,7 @@
:closable="false" :closable="false"
@close="onClose" @close="onClose"
:visible="visible" :visible="visible"
:style="{}" style="height: 100%;overflow: auto;"
> >
<div class="setting-drawer-index-content"> <div class="setting-drawer-index-content">
@ -178,19 +178,12 @@
mixins: [mixin, mixinDevice], mixins: [mixin, mixinDevice],
data() { data() {
return { return {
visible: true, visible: false,
colorList, colorList,
dataFixSiderbar: false dataFixSiderbar: false
} }
},
watch: {
}, },
mounted () { mounted () {
const vm = this
setTimeout(() => {
vm.visible = false
}, 16)
// 当主题色不是默认色时,才进行主题编译 // 当主题色不是默认色时,才进行主题编译
if (this.primaryColor !== config.primaryColor) { if (this.primaryColor !== config.primaryColor) {
updateTheme(this.primaryColor) updateTheme(this.primaryColor)

View File

@ -133,6 +133,15 @@
this.searchMenus(lists,this.permissionMenuList) this.searchMenus(lists,this.permissionMenuList)
this.searchMenuOptions=[...lists] this.searchMenuOptions=[...lists]
}, },
mounted() {
//如果是单点登录模式
if (process.env.VUE_APP_SSO == 'true') {
let depart = this.userInfo().orgCode
if (!depart) {
this.updateCurrentDepart()
}
}
},
computed: { computed: {
...mapState({ ...mapState({
// 后台菜单 // 后台菜单
@ -176,8 +185,8 @@
return that.Logout({}).then(() => { return that.Logout({}).then(() => {
// update-begin author:wangshuai date:20200601 for: 退出登录跳转登录页面 // update-begin author:wangshuai date:20200601 for: 退出登录跳转登录页面
that.$router.push({ path: '/user/login' }); that.$router.push({ path: '/user/login' });
window.location.reload()
// update-end author:wangshuai date:20200601 for: 退出登录跳转登录页面 // update-end author:wangshuai date:20200601 for: 退出登录跳转登录页面
//window.location.reload()
}).catch(err => { }).catch(err => {
that.$message.error({ that.$message.error({
title: '错误', title: '错误',
@ -216,11 +225,17 @@
// update_begin author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题 // update_begin author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题
searchMethods(value) { searchMethods(value) {
let route = this.searchMenuOptions.filter(item => item.id === value)[0] 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') window.open(route.meta.url, '_blank')
} else {
if(route.component.includes('layouts/IframePageView')){
this.$router.push(route)
}else{ }else{
this.$router.push({ path: route.path }) this.$router.push({ path: route.path })
} }
}
//update-end-author:taoyan date:20210528 for: 【菜单问题】配置一个iframe地址的菜单内部打开在搜索菜单上打开却新开了一个窗口
this.searchMenuVisible = false this.searchMenuVisible = false
}, },
// update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题 // update_end author:sunjianlei date:20191230 for: 解决外部链接打开失败的问题

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