JeecgBoot低代码平台 3.0版本发布—新里程牌开始,迎接VUE3版本到来!!

pull/3142/head
zhangdaiscott 2021-10-27 10:28:14 +08:00
parent 9760185bf6
commit 0acea1abff
124 changed files with 5049 additions and 241273 deletions

View File

@ -1,13 +1,13 @@
Jeecg-Boot 低代码开发平台 Jeecg-Boot 低代码开发平台
=============== ===============
当前最新版本: 2.4.6发布日期20210813 当前最新版本: 3.0发布日期2021-11-01
## 后端技术架构 ## 后端技术架构
- 基础框架Spring Boot 2.3.5.RELEASE - 基础框架Spring Boot 2.3.5.RELEASE
- 持久层框架Mybatis-plus 3.4.3.1 - 持久层框架Mybatis-plus 3.4.1
- 安全框架Apache Shiro 1.7.0Jwt 3.11.0 - 安全框架Apache Shiro 1.7.0Jwt 3.11.0
@ -29,7 +29,7 @@ Jeecg-Boot 低代码开发平台
- 依赖管理Maven - 依赖管理Maven
- 数据库MySQL5.7+ & Oracle 11g & SqlServer & postgresql - 数据库MySQL5.7+ & Oracle 11g & SqlServer & postgresql & 国产等更多数据库
- 缓存Redis - 缓存Redis
@ -43,7 +43,7 @@ Jeecg-Boot 低代码开发平台
- 常见问题: [http://jeecg.com/doc/qa](http://jeecg.com/doc/qa) - 常见问题: [http://jeecg.com/doc/qa](http://jeecg.com/doc/qa)
- QQ交流群 ④774126647、③816531124、①284271917、②769925425 - QQ交流群 ⑤860162132、④774126647(满)、③816531124(满)、②769925425(满)、①284271917(满)
## 专项文档 ## 专项文档

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,96 +0,0 @@
--
ALTER TABLE `sys_third_account`
ADD UNIQUE INDEX `uniq_sys_third_account_third_type_third_user_id` (`third_type`, `third_user_id`) USING BTREE ;
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `url`, `component`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_route`, `is_leaf`, `keep_alive`, `hidden`, `description`, `status`, `del_flag`, `rule_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `internal_or_external`) VALUES ('1404684556047024130', '08e6b9dc3c04489c8e1ff2ce6f105aa4', '线', '/isystem/online', 'system/SysUserOnlineList', NULL, NULL, 1, NULL, '1', NULL, 0, NULL, 1, 1, 0, 0, NULL, '1', 0, 0, 'admin', '2021-06-15 14:17:51', NULL, NULL, 0);
DELETE FROM sys_depart WHERE id = '743ba9dbdc114af8953a11022ef3096a';
alter table sys_quartz_job engine = InnoDB;
UPDATE `sys_dict_item` SET `item_value` = '6' WHERE `item_text` = 'MYSQL5.7';
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1414837074500976641', '1209733563293962241', 'Postgresql', '6', '', '5', '1', 'admin', '2021-07-13 14:40:20', 'admin', '2021-07-15 13:44:15');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1415547541091504129', '1209733563293962241', 'MarialDB', '5', '', '6', '1', 'admin', '2021-07-15 13:43:28', 'admin', '2021-07-15 13:44:23');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050323111399425', '1209733563293962241', 'Derby', '13', '', '13', '1', 'admin', '2021-07-22 11:28:38', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050209823248385', '1209733563293962241', 'Hsqldb', '12', '', '12', '1', 'admin', '2021-07-22 11:28:11', 'admin', '2021-07-22 11:28:27');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050149475602434', '1209733563293962241', 'DB2', '11', '', '11', '1', 'admin', '2021-07-22 11:27:56', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050110669901826', '1209733563293962241', 'SQLite', '10', '', '10', '1', 'admin', '2021-07-22 11:27:47', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050075555188737', '1209733563293962241', '', '9', '', '9', '1', 'admin', '2021-07-22 11:27:39', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050017053036545', '1209733563293962241', '', '8', '', '8', '1', 'admin', '2021-07-22 11:27:25', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418049969003089922', '1209733563293962241', '', '7', '', '7', '1', 'admin', '2021-07-22 11:27:13', 'admin', '2021-07-22 11:27:30');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418117316707590146', '1209733563293962241', 'H2', '14', '', '14', '1', 'admin', '2021-07-22 15:54:50', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418491604048449537', '1209733563293962241', '', '15', '', 15, 1, 'admin', '2021-07-23 16:42:07', NULL, NULL);
ALTER TABLE demo ADD COLUMN tenant_id int(10) NULL DEFAULT 0;
-- Online
ALTER TABLE `onl_cgform_head`
ADD COLUMN `ext_config_json` varchar(1000) NULL COMMENT 'JSON' AFTER `physic_id`;
ALTER TABLE `onl_cgreport_head`
ADD COLUMN `low_app_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ID' AFTER `content`;
--
UPDATE `jimu_report` SET `json_str` = '{\"loopBlockList\":[],\"area\":{\"sri\":16,\"sci\":5,\"eri\":16,\"eci\":5,\"width\":147,\"height\":25},\"excel_config_id\":\"1347373863746539520\",\"printConfig\":{\"paper\":\"A4\",\"width\":210,\"height\":297,\"definition\":1,\"isBackend\":false,\"marginX\":10,\"marginY\":10,\"layout\":\"portrait\"},\"rows\":{\"0\":{\"cells\":{\"0\":{\"text\":\"\"},\"1\":{\"text\":\"\"}}},\"1\":{\"cells\":{\"0\":{\"text\":\"\"}}},\"3\":{\"cells\":{\"2\":{\"text\":\"\",\"rendered\":\"\"}}},\"5\":{\"cells\":{},\"height\":29},\"6\":{\"cells\":{\"2\":{\"text\":\"\",\"style\":2}},\"height\":34},\"7\":{\"cells\":{\"2\":{\"merge\":[0,4],\"text\":\"实习证明\",\"style\":2}},\"height\":41},\"8\":{\"cells\":{\"1\":{\"text\":\"\",\"style\":3},\"2\":{\"text\":\"\"}}},\"9\":{\"cells\":{\"1\":{\"text\":\"\",\"style\":3},\"2\":{\"text\":\"\",\"style\":3},\"3\":{\"text\":\"\"}},\"isDrag\":true,\"height\":33},\"10\":{\"cells\":{\"2\":{\"text\":\"${tt.name}\",\"style\":11},\"3\":{\"text\":\"同学在我公司与 2020年4月1日 至 2020年5月1日 实习。\",\"style\":19,\"merge\":[0,3],\"height\":34}},\"height\":34},\"11\":{\"cells\":{},\"height\":28},\"12\":{\"cells\":{\"1\":{\"text\":\"\",\"style\":6},\"2\":{\"style\":13,\"text\":\"${tt.pingjia}\",\"merge\":[3,4],\"height\":129}},\"height\":36},\"13\":{\"cells\":{},\"height\":29},\"14\":{\"cells\":{},\"height\":33},\"15\":{\"cells\":{},\"height\":31},\"16\":{\"cells\":{}},\"17\":{\"cells\":{\"1\":{\"text\":\"\"},\"2\":{\"text\":\"特此证明!\",\"style\":12}}},\"20\":{\"cells\":{\"2\":{\"text\":\"\"},\"3\":{\"text\":\"\",\"style\":3},\"4\":{\"text\":\"\"}}},\"21\":{\"cells\":{\"4\":{\"text\":\"\"}}},\"22\":{\"cells\":{\"3\":{\"text\":\"\",\"style\":3},\"4\":{\"text\":\"证明人:\",\"style\":11},\"5\":{\"text\":\"${tt.lingdao}\",\"style\":12}}},\"23\":{\"cells\":{\"4\":{\"text\":\"\"},\"5\":{\"text\":\"${tt.shijian}\",\"style\":15}}},\"len\":100},\"dbexps\":[],\"dicts\":[],\"freeze\":\"A1\",\"dataRectWidth\":576,\"displayConfig\":{},\"background\":{\"path\":\"https://static.jeecg.com/designreport/images/11_1611283832037.png\",\"repeat\":\"no-repeat\",\"width\":\"\",\"height\":\"\"},\"name\":\"sheet1\",\"autofilter\":{},\"styles\":[{\"align\":\"center\"},{\"align\":\"center\",\"font\":{\"size\":14}},{\"align\":\"center\",\"font\":{\"size\":16}},{\"align\":\"right\"},{\"align\":\"left\"},{\"align\":\"left\",\"valign\":\"top\"},{\"align\":\"left\",\"valign\":\"top\",\"textwrap\":true},{\"font\":{\"size\":16}},{\"align\":\"left\",\"valign\":\"top\",\"textwrap\":false},{\"textwrap\":false},{\"textwrap\":true},{\"align\":\"right\",\"font\":{\"size\":12}},{\"font\":{\"size\":12}},{\"align\":\"left\",\"valign\":\"top\",\"textwrap\":true,\"font\":{\"size\":12}},{\"textwrap\":true,\"font\":{\"size\":12}},{\"align\":\"left\",\"font\":{\"size\":12}},{\"font\":{\"size\":12},\"border\":{\"bottom\":[\"thin\",\"#000\"],\"top\":[\"thin\",\"#000\"],\"left\":[\"thin\",\"#000\"],\"right\":[\"thin\",\"#000\"]}},{\"font\":{\"size\":14}},{\"font\":{\"size\":10}},{\"textwrap\":false,\"font\":{\"size\":12}}],\"validations\":[],\"cols\":{\"0\":{\"width\":69},\"1\":{\"width\":41},\"4\":{\"width\":119},\"5\":{\"width\":147},\"6\":{\"width\":31},\"len\":50},\"merges\":[\"C8:G8\",\"D11:G11\",\"C13:G16\"]}' WHERE `id` = '1347373863746539520';
update jimu_report_data_source set connect_times = 0;
ALTER TABLE `jimu_report_data_source`
MODIFY COLUMN `connect_times` int(1) UNSIGNED NULL DEFAULT 0 COMMENT '' AFTER `update_time`;
ALTER TABLE `jimu_report_db_param`
MODIFY COLUMN `param_value` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '' AFTER `param_txt`;
DELETE FROM jimu_report_map
WHERE
id IN (SELECT id FROM (SELECT id FROM jimu_report_map WHERE NAME IN ( SELECT NAME FROM jimu_report_map GROUP BY NAME HAVING count(NAME) > 1)) T)
AND id NOT IN (SELECT id FROM ( SELECT min(id) id FROM jimu_report_map GROUP BY NAME HAVING count(NAME) > 1) M);
ALTER TABLE `jimu_report_map`
ADD UNIQUE INDEX `uniq_jmreport_map_name`(`name`);
update jimu_report set VIEW_COUNT = 0 WHERE VIEW_COUNT is null or VIEW_COUNT = '';
ALTER TABLE `jimu_report`
MODIFY COLUMN `view_count` bigint(15) NULL DEFAULT 0 COMMENT '' AFTER `template`;
ALTER TABLE `jimu_report_db`
ADD INDEX `idx_jimu_report_id`(`jimu_report_id`);
ALTER TABLE `jimu_report_db`
ADD INDEX `idx_db_source_id`(`db_source`);
ALTER TABLE `jimu_report_db_field`
ADD INDEX `idx_dbfield_order_num`(`order_num`);
ALTER TABLE `jimu_report`
ADD INDEX `uniq_jmreport_createby`(`create_by`);
ALTER TABLE `jimu_report`
ADD INDEX `uniq_jmreport_delflag`(`del_flag`);
ALTER TABLE `jimu_report_link`
ADD INDEX `uniq_link_reportid`(`report_id`);
ALTER TABLE `jimu_report`
MODIFY COLUMN `json_str` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'json' AFTER `type`;
ALTER TABLE `jimu_report_link`
ADD COLUMN `expression` varchar(255) NULL COMMENT '' AFTER `link_chart_id`;
--
ALTER TABLE `jimu_report_db_param`
ADD COLUMN `search_flag` int(1) NULL COMMENT '01 0' AFTER `update_time`;
update jimu_report_db_param set search_flag = 0;
create table jimu_dict like sys_dict;
insert into jimu_dict select * from sys_dict;
create table jimu_dict_item like sys_dict_item;
insert into jimu_dict_item select * from sys_dict_item;
ALTER TABLE `jimu_report_db_param`
ADD COLUMN `widget_type` varchar(50) NULL COMMENT '' AFTER `search_flag`,
ADD COLUMN `search_mode` int(1) NULL COMMENT '12' AFTER `widget_type`,
ADD COLUMN `dict_code` varchar(255) NULL COMMENT '' AFTER `search_mode`;

View File

@ -0,0 +1,63 @@
-- 字段长度不规范导致转库错误Specified key was too long; max key length is 767 bytes
ALTER TABLE `rep_demo_dxtj`
MODIFY COLUMN `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键' FIRST;
ALTER TABLE `sys_third_account`
MODIFY COLUMN `third_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录来源' AFTER `third_user_id`;
-- 数据源字典sql整理
DELETE FROM `sys_dict_item` WHERE dict_id ='1209733563293962241';
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1209733775114702850', '1209733563293962241', 'MySQL5.5', '1', '', 1, 1, 'admin', '2019-12-25 15:13:02', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1334440962954936321', '1209733563293962241', 'MYSQL5.7+', '4', '', 2, 1, 'admin', '2020-12-03 18:16:02', 'admin', '2021-07-15 13:44:29');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1209733839933476865', '1209733563293962241', 'Oracle', '2', '', 3, 1, 'admin', '2019-12-25 15:13:18', 'admin', '2021-07-15 13:44:08');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1209733903020003330', '1209733563293962241', 'SQLServer', '3', '', 4, 1, 'admin', '2019-12-25 15:13:33', 'admin', '2021-07-15 13:44:11');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1414837074500976641', '1209733563293962241', 'postgresql', '6', '', 5, 1, 'admin', '2021-07-13 14:40:20', 'admin', '2021-07-15 13:44:15');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1415547541091504129', '1209733563293962241', 'marialDB', '5', '', 6, 1, 'admin', '2021-07-15 13:43:28', 'admin', '2021-07-15 13:44:23');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418049969003089922', '1209733563293962241', '达梦', '7', '', 7, 1, 'admin', '2021-07-22 11:27:13', 'admin', '2021-07-22 11:27:30');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050017053036545', '1209733563293962241', '人大金仓', '8', '', 8, 1, 'admin', '2021-07-22 11:27:25', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050075555188737', '1209733563293962241', '神通', '9', '', 9, 1, 'admin', '2021-07-22 11:27:39', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050110669901826', '1209733563293962241', 'SQLite', '10', '', 10, 1, 'admin', '2021-07-22 11:27:47', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050149475602434', '1209733563293962241', 'DB2', '11', '', 11, 1, 'admin', '2021-07-22 11:27:56', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050209823248385', '1209733563293962241', 'Hsqldb', '12', '', 12, 1, 'admin', '2021-07-22 11:28:11', 'admin', '2021-07-22 11:28:27');
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418050323111399425', '1209733563293962241', 'Derby', '13', '', 13, 1, 'admin', '2021-07-22 11:28:38', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418117316707590146', '1209733563293962241', 'H2', '14', '', 14, 1, 'admin', '2021-07-22 15:54:50', NULL, NULL);
INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `description`, `sort_order`, `status`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES ('1418491604048449537', '1209733563293962241', '其他数据库', '15', '', 15, 1, 'admin', '2021-07-23 16:42:07', NULL, NULL);
-- 新增 hideTab 字段
ALTER TABLE `sys_permission`
ADD COLUMN `hide_tab` int(2) NULL COMMENT '是否隐藏tab: 0否,1是' AFTER `hidden`;
-- 【online表单】新增 low_app_id 字段
ALTER TABLE `onl_cgform_head`
ADD COLUMN `low_app_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '关联的应用ID' AFTER `des_form_code`;
-- online老数据,存在字符串类型key值不一致的情况,String改为string
UPDATE onl_cgform_field SET db_type = 'string' where binary db_type = 'String';
-- 积木报表升级
ALTER TABLE `jimu_report`
MODIFY COLUMN `view_count` bigint(15) NULL DEFAULT 0 COMMENT '浏览次数' AFTER `template`;
ALTER TABLE `jimu_report`
MODIFY COLUMN `json_str` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT 'json字符串' AFTER `type`;
ALTER TABLE `jimu_report_db_field`
ADD COLUMN `search_format` varchar(50) NULL COMMENT '查询时间格式化表达式' AFTER `search_value`;
ALTER TABLE `jimu_report_db_param`
ADD COLUMN `search_format` varchar(50) NULL COMMENT '查询时间格式化表达式' AFTER `dict_code`;
UPDATE jimu_report SET json_str=replace(json_str,'"subtotal":"totalField"','"funcname":"SUM"');
ALTER TABLE `jimu_report`
ADD COLUMN `css_str` text NULL COMMENT 'css增强' AFTER `view_count`,
ADD COLUMN `js_str` text NULL COMMENT 'js增强' AFTER `css_str`;
ALTER TABLE `jimu_report_link`
CHANGE COLUMN `expression` `requirement` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '条件' AFTER `link_chart_id`;
ALTER TABLE `jimu_report_db_field`
ADD COLUMN `ext_json` text NULL COMMENT '参数配置' AFTER `search_format`;
ALTER TABLE `jimu_report_db_param`
ADD COLUMN `ext_json` text NULL COMMENT '参数配置' AFTER `search_format`;
ALTER TABLE `jimu_report_db`
MODIFY COLUMN `is_list` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '是否是列表0否1是 默认0' AFTER `api_method`;

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>jeecg-boot-base-api</artifactId> <artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -8,10 +8,10 @@ import java.util.SortedMap;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.PathMatcherUtil; import org.jeecg.common.util.PathMatcherUtil;
import org.jeecg.common.config.mqtoken.UserTokenContext;
import org.jeecg.config.sign.interceptor.SignAuthConfiguration; import org.jeecg.config.sign.interceptor.SignAuthConfiguration;
import org.jeecg.config.sign.util.HttpUtils; import org.jeecg.config.sign.util.HttpUtils;
import org.jeecg.config.sign.util.SignUtil; import org.jeecg.config.sign.util.SignUtil;

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>jeecg-boot-base-api</artifactId> <artifactId>jeecg-boot-base-api</artifactId>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>jeecg-boot-base</artifactId> <artifactId>jeecg-boot-base</artifactId>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId> <artifactId>jeecg-boot-base</artifactId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -114,7 +114,7 @@
<dependency> <dependency>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<artifactId>hibernate-re</artifactId> <artifactId>hibernate-re</artifactId>
<version>2.4.6-beta1</version> <version>3.0.0-beta</version>
</dependency> </dependency>
<!-- 数据库驱动 --> <!-- 数据库驱动 -->

View File

@ -1,24 +0,0 @@
package org.jeecg.common.api;
import org.jeecg.common.api.vo.OaWpsModel;
/**
* @Description: WPS
* @Author: wangshuai
* @Date:20200709
* @Version:V1.0
*/
public interface IWpsBaseAPI {
/*根据模板id获取模板信息*/
OaWpsModel getById(String id);
/*根据文件路径下载文件*/
void downloadOosFiles(String objectName, String basePath,String fileName);
/*WPS 设置数据存储,用于逻辑判断*/
void context(String type,String text);
/*删除WPS模板相关信息*/
void deleteById(String id);
}

View File

@ -1,47 +0,0 @@
package org.jeecg.common.api.desform;
import org.jeecg.common.system.vo.DictModel;
import java.util.List;
import java.util.Map;
/**
* SystemAPI
*
* @author sunjianlei
*/
public interface ISysTranslateAPI {
/**
*
*/
List<String> categoryLoadDictItem(String ids);
/**
* codetext
*
* @param dictCode tableName,text,code
* @param keys key
* @return
*/
List<String> dictLoadDictItem(String dictCode, String keys);
/**
*
*
* @param dictCode tableName,text,code
* @param dictCode key
* @return
*/
List<DictModel> dictGetDictItems(String dictCode);
/**
* JSearchSelectTag
*
*
* @param dictCode codetable,text,code
* @return
*/
List<DictModel> dictLoadDict(String dictCode, String keyword, Integer pageSize);
}

View File

@ -1,107 +0,0 @@
package org.jeecg.common.api.vo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* @Description:
* @Author: jeecg-boot
* @Date: 2020-06-09
* @Version: V1.0
*/
@Data
@TableName("oa_wps_file")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value = "oa_wps_file对象", description = "文档")
public class OaWpsModel implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
@ApiModelProperty(value = "id")
private String id;
/**
* name
*/
@Excel(name = "name", width = 15)
@ApiModelProperty(value = "name")
private String name;
/**
* version
*/
@Excel(name = "version", width = 15)
@ApiModelProperty(value = "version")
private Integer version;
/**
* size
*/
@Excel(name = "size", width = 15)
@ApiModelProperty(value = "size")
private Integer size;
/**
* downloadUrl
*/
@Excel(name = "downloadUrl", width = 15)
@ApiModelProperty(value = "downloadUrl")
private String downloadUrl;
/**
* deleted
*/
@Excel(name = "deleted", width = 15)
@ApiModelProperty(value = "deleted")
private String deleted;
/**
* canDelete
*/
@Excel(name = "canDelete", width = 15)
@ApiModelProperty(value = "canDelete")
private String canDelete;
/**
*
*/
@ApiModelProperty(value = "创建人")
private String createBy;
/**
*
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "创建时间")
private Date createTime;
/**
*
*/
@ApiModelProperty(value = "更新人")
private String updateBy;
/**
*
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@ApiModelProperty(value = "更新时间")
private Date updateTime;
/**
*
*/
@ApiModelProperty(value = "组织机构编码")
private String sysOrgCode;
@TableField(exist = false)
private String userId;
}

View File

@ -30,7 +30,7 @@ public class Result<T> implements Serializable {
* *
*/ */
@ApiModelProperty(value = "返回处理消息") @ApiModelProperty(value = "返回处理消息")
private String message = "操作成功!"; private String message = "";
/** /**
* *
@ -51,7 +51,16 @@ public class Result<T> implements Serializable {
private long timestamp = System.currentTimeMillis(); private long timestamp = System.currentTimeMillis();
public Result() { public Result() {
}
/**
* VUE3token
* @param code
* @param message
*/
public Result(Integer code,String message) {
this.code = code;
this.message = message;
} }
public Result<T> success(String message) { public Result<T> success(String message) {
@ -66,7 +75,6 @@ public class Result<T> implements Serializable {
Result<Object> r = new Result<Object>(); Result<Object> r = new Result<Object>();
r.setSuccess(true); r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200); r.setCode(CommonConstant.SC_OK_200);
r.setMessage("成功");
return r; return r;
} }
@ -92,7 +100,6 @@ public class Result<T> implements Serializable {
Result<T> r = new Result<T>(); Result<T> r = new Result<T>();
r.setSuccess(true); r.setSuccess(true);
r.setCode(CommonConstant.SC_OK_200); r.setCode(CommonConstant.SC_OK_200);
r.setMessage("成功");
return r; return r;
} }

View File

@ -25,6 +25,7 @@ import org.springframework.util.StringUtils;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -261,7 +262,10 @@ public class DictAspect {
for (DictModel dict : texts) { for (DictModel dict : texts) {
String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue()); String redisKey = String.format("sys:cache:dictTable::SimpleKey [%s,%s]", dictCode, dict.getValue());
try { try {
redisTemplate.opsForValue().set(redisKey, dict.getText()); // update-begin-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
// 保留5分钟
redisTemplate.opsForValue().set(redisKey, dict.getText(), 300, TimeUnit.SECONDS);
// update-end-author:taoyan date:20211012 for: 字典表翻译注解缓存未更新 issues/3061
} catch (Exception e) { } catch (Exception e) {
log.warn(e.getMessage(), e); log.warn(e.getMessage(), e);
} }

View File

@ -292,6 +292,7 @@ public interface CommonConstant {
public final static String X_ACCESS_TOKEN = "X-Access-Token"; public final static String X_ACCESS_TOKEN = "X-Access-Token";
public final static String X_SIGN = "X-Sign"; public final static String X_SIGN = "X-Sign";
public final static String X_TIMESTAMP = "X-TIMESTAMP"; public final static String X_TIMESTAMP = "X-TIMESTAMP";
public final static String TOKEN_IS_INVALID_MSG = "Token失效请重新登录!";
/** /**
* *

View File

@ -10,6 +10,8 @@ public interface DataBaseConstant {
public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL"; public static final String DB_TYPE_POSTGRESQL = "POSTGRESQL";
public static final String DB_TYPE_SQLSERVER = "SQLSERVER"; public static final String DB_TYPE_SQLSERVER = "SQLSERVER";
public static final String DB_TYPE_MARIADB = "MARIADB"; public static final String DB_TYPE_MARIADB = "MARIADB";
public static final String DB_TYPE_DB2 = "DB2";
public static final String DB_TYPE_HSQL = "HSQL";
// // 数据库类型,对应 database_type 字典 // // 数据库类型,对应 database_type 字典
// public static final String DB_TYPE_MYSQL_NUM = "1"; // public static final String DB_TYPE_MYSQL_NUM = "1";

View File

@ -0,0 +1,19 @@
package org.jeecg.common.exception;
public class JeecgBoot401Exception extends RuntimeException {
private static final long serialVersionUID = 1L;
public JeecgBoot401Exception(String message){
super(message);
}
public JeecgBoot401Exception(Throwable cause)
{
super(cause);
}
public JeecgBoot401Exception(String message, Throwable cause)
{
super(message,cause);
}
}

View File

@ -7,8 +7,10 @@ import org.jeecg.common.api.vo.Result;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.connection.PoolException; import org.springframework.data.redis.connection.PoolException;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.NoHandlerFoundException;
@ -29,11 +31,21 @@ public class JeecgBootExceptionHandler {
* *
*/ */
@ExceptionHandler(JeecgBootException.class) @ExceptionHandler(JeecgBootException.class)
public Result<?> handleRRException(JeecgBootException e){ public Result<?> handleJeecgBootException(JeecgBootException e){
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return Result.error(e.getMessage()); return Result.error(e.getMessage());
} }
/**
*
*/
@ExceptionHandler(JeecgBoot401Exception.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public Result<?> handleJeecgBoot401Exception(JeecgBoot401Exception e){
log.error(e.getMessage(), e);
return new Result(401,e.getMessage());
}
@ExceptionHandler(NoHandlerFoundException.class) @ExceptionHandler(NoHandlerFoundException.class)
public Result<?> handlerNoFoundException(Exception e) { public Result<?> handlerNoFoundException(Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);

View File

@ -37,8 +37,9 @@ import java.util.stream.Collectors;
*/ */
@Slf4j @Slf4j
public class JeecgController<T, S extends IService<T>> { public class JeecgController<T, S extends IService<T>> {
//issues/2933 JeecgController注入service时改用protected修饰能避免重复引用service
@Autowired @Autowired
S service; protected S service;
@Value("${jeecg.path.upload}") @Value("${jeecg.path.upload}")
private String upLoadPath; private String upLoadPath;

View File

@ -99,7 +99,7 @@ public class QueryGenerator {
* <br>:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>(); * <br>:QueryWrapper<JeecgDemo> queryWrapper = new QueryWrapper<JeecgDemo>();
* <br>3.使 {@link #initQueryWrapper} * <br>3.使 {@link #initQueryWrapper}
*/ */
public static void installMplus(QueryWrapper<?> queryWrapper,Object searchObj,Map<String, String[]> parameterMap) { private static void installMplus(QueryWrapper<?> queryWrapper,Object searchObj,Map<String, String[]> parameterMap) {
/* /*
* : orgCode #{sys_org_code} * : orgCode #{sys_org_code}
@ -216,7 +216,7 @@ public class QueryGenerator {
} }
//多字段排序 TODO 需要修改前端 //多字段排序 TODO 需要修改前端
public static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) { private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap) {
String column=null,order=null; String column=null,order=null;
if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) { if(parameterMap!=null&& parameterMap.containsKey(ORDER_COLUMN)) {
column = parameterMap.get(ORDER_COLUMN)[0]; column = parameterMap.get(ORDER_COLUMN)[0];
@ -258,7 +258,7 @@ public class QueryGenerator {
* @param parameterMap * @param parameterMap
* @param fieldColumnMap map * @param fieldColumnMap map
*/ */
public static void doSuperQuery(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap, Map<String,String> fieldColumnMap) { private static void doSuperQuery(QueryWrapper<?> queryWrapper,Map<String, String[]> parameterMap, Map<String,String> fieldColumnMap) {
if(parameterMap!=null&& parameterMap.containsKey(SUPER_QUERY_PARAMS)){ if(parameterMap!=null&& parameterMap.containsKey(SUPER_QUERY_PARAMS)){
String superQueryParams = parameterMap.get(SUPER_QUERY_PARAMS)[0]; String superQueryParams = parameterMap.get(SUPER_QUERY_PARAMS)[0];
String superQueryMatchType = parameterMap.get(SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue(); String superQueryMatchType = parameterMap.get(SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue();
@ -347,7 +347,7 @@ public class QueryGenerator {
* @param value * @param value
* @return * @return
*/ */
private static QueryRuleEnum convert2Rule(Object value) { public static QueryRuleEnum convert2Rule(Object value) {
// 避免空数据 // 避免空数据
// update-begin-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常 // update-begin-author:taoyan date:20210629 for: 查询条件输入空格导致return null后续判断导致抛出null异常
if (value == null) { if (value == null) {
@ -595,7 +595,7 @@ public class QueryGenerator {
/** /**
* * TODO
* @return * @return
*/ */
public static Map<String, SysPermissionDataRuleModel> getRuleMap() { public static Map<String, SysPermissionDataRuleModel> getRuleMap() {
@ -616,30 +616,6 @@ public class QueryGenerator {
return ruleMap; return ruleMap;
} }
/**
*
* @return
*/
public static Map<String, SysPermissionDataRuleModel> getRuleMap(List<SysPermissionDataRuleModel> list) {
Map<String, SysPermissionDataRuleModel> ruleMap = new HashMap<String, SysPermissionDataRuleModel>();
if(list==null){
list =JeecgDataAutorUtils.loadDataSearchConditon();
}
if(list != null&&list.size()>0){
if(list.get(0)==null){
return ruleMap;
}
for (SysPermissionDataRuleModel rule : list) {
String column = rule.getRuleColumn();
if(QueryRuleEnum.SQL_RULES.getValue().equals(rule.getRuleConditions())) {
column = SQL_RULES_COLUMN+rule.getId();
}
ruleMap.put(column, rule);
}
}
return ruleMap;
}
private static void addRuleToQueryWrapper(SysPermissionDataRuleModel dataRule, String name, Class propertyType, QueryWrapper<?> queryWrapper) { private static void addRuleToQueryWrapper(SysPermissionDataRuleModel dataRule, String name, Class propertyType, QueryWrapper<?> queryWrapper) {
QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions()); QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
if(rule.equals(QueryRuleEnum.IN) && ! propertyType.equals(String.class)) { if(rule.equals(QueryRuleEnum.IN) && ! propertyType.equals(String.class)) {
@ -761,7 +737,7 @@ public class QueryGenerator {
* @param dataBaseType * @param dataBaseType
* @return * @return
*/ */
public static String getSingleSqlByRule(QueryRuleEnum rule,String field,Object value,boolean isString, String dataBaseType) { private static String getSingleSqlByRule(QueryRuleEnum rule,String field,Object value,boolean isString, String dataBaseType) {
String res = ""; String res = "";
switch (rule) { switch (rule) {
case GT: case GT:
@ -813,7 +789,7 @@ public class QueryGenerator {
* @param isString * @param isString
* @return * @return
*/ */
public static String getSingleSqlByRule(QueryRuleEnum rule,String field,Object value,boolean isString) { private static String getSingleSqlByRule(QueryRuleEnum rule,String field,Object value,boolean isString) {
return getSingleSqlByRule(rule, field, value, isString, null); return getSingleSqlByRule(rule, field, value, isString, null);
} }

View File

@ -5,13 +5,19 @@ import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date; import java.util.Date;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant; import org.jeecg.common.constant.DataBaseConstant;
import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.exception.JeecgBootException;
@ -31,6 +37,28 @@ public class JwtUtil {
// Token过期时间30分钟用户登录过期时间是此时间的两倍以token在reids缓存时间为准 // Token过期时间30分钟用户登录过期时间是此时间的两倍以token在reids缓存时间为准
public static final long EXPIRE_TIME = 30 * 60 * 1000; public static final long EXPIRE_TIME = 30 * 60 * 1000;
/**
*
* @param response
* @param code
* @param errorMsg
*/
public static void responseError(ServletResponse response, Integer code, String errorMsg) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
Result jsonResult = new Result(code, errorMsg);
OutputStream os = null;
try {
os = httpServletResponse.getOutputStream();
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setStatus(401);
os.write(new ObjectMapper().writeValueAsString(jsonResult).getBytes("UTF-8"));
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/** /**
* token * token
* *

View File

@ -1,26 +1,30 @@
package org.jeecg.common.util; package org.jeecg.common.util;
import java.io.*; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import java.sql.Connection; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import java.sql.DatabaseMetaData; import com.baomidou.mybatisplus.annotation.DbType;
import java.sql.SQLException; import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import java.util.regex.Matcher; import lombok.extern.slf4j.Slf4j;
import java.util.regex.Pattern;
import javax.sql.DataSource;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.DataBaseConstant; import org.jeecg.common.constant.DataBaseConstant;
import org.jeecg.common.util.filter.FileTypeFilter; import org.jeecg.common.util.filter.FileTypeFilter;
import org.jeecg.common.util.oss.OssBootUtil; import org.jeecg.common.util.oss.OssBootUtil;
import org.jeecgframework.poi.util.PoiPublicUtil; import org.jeecgframework.poi.util.PoiPublicUtil;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.annotation.DbType; import javax.sql.DataSource;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils; import java.io.ByteArrayInputStream;
import java.io.File;
import lombok.extern.slf4j.Slf4j; import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j @Slf4j
public class CommonUtils { public class CommonUtils {
@ -207,6 +211,42 @@ public class CommonUtils {
} }
} }
/**
* keyDataSourceProperty
* @param sourceKey
* @return
*/
public static DataSourceProperty getDataSourceProperty(String sourceKey){
DynamicDataSourceProperties prop = SpringContextUtils.getApplicationContext().getBean(DynamicDataSourceProperties.class);
Map<String, DataSourceProperty> map = prop.getDatasource();
DataSourceProperty db = (DataSourceProperty)map.get(sourceKey);
return db;
}
/**
* sourceKey
* @param sourceKey
* @return
* @throws SQLException
*/
public static Connection getDataSourceConnect(String sourceKey) throws SQLException {
if (oConvertUtils.isEmpty(sourceKey)) {
sourceKey = "master";
}
DynamicDataSourceProperties prop = SpringContextUtils.getApplicationContext().getBean(DynamicDataSourceProperties.class);
Map<String, DataSourceProperty> map = prop.getDatasource();
DataSourceProperty db = (DataSourceProperty)map.get(sourceKey);
if(db==null){
return null;
}
DriverManagerDataSource ds = new DriverManagerDataSource ();
ds.setDriverClassName(db.getDriverClassName());
ds.setUrl(db.getUrl());
ds.setUsername(db.getUsername());
ds.setPassword(db.getPassword());
return ds.getConnection();
}
/** /**
* *
* @param dataSource * @param dataSource

View File

@ -38,7 +38,7 @@ public class ImportExcelUtil {
} }
} }
public static List<String> importDateSave(List<Object> list, Class serviceClass,List<String> errorMessage,String errorFlag) { public static List<String> importDateSave(List<?> list, Class serviceClass, List<String> errorMessage, String errorFlag) {
IService bean =(IService) SpringContextUtils.getBean(serviceClass); IService bean =(IService) SpringContextUtils.getBean(serviceClass);
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
try { try {

View File

@ -1,6 +1,7 @@
package org.jeecg.common.util; package org.jeecg.common.util;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jeecg.common.constant.ServiceNameConstants; import org.jeecg.common.constant.ServiceNameConstants;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@ -38,6 +39,12 @@ public class SpringContextUtils implements ApplicationContextAware {
public static HttpServletRequest getHttpServletRequest() { public static HttpServletRequest getHttpServletRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
} }
/**
* HttpServletResponse
*/
public static HttpServletResponse getHttpServletResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
/** /**
* basePath * basePath

View File

@ -2,9 +2,9 @@ package org.jeecg.common.util;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBoot401Exception;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
@ -40,27 +40,57 @@ public class TokenUtils {
String token = getTokenByRequest(request); String token = getTokenByRequest(request);
if (StringUtils.isBlank(token)) { if (StringUtils.isBlank(token)) {
throw new AuthenticationException("Token不能为空!"); throw new JeecgBoot401Exception("Token不能为空!");
} }
// 解密获得username用于和数据库进行对比 // 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token); String username = JwtUtil.getUsername(token);
if (username == null) { if (username == null) {
throw new AuthenticationException("Token非法无效!"); throw new JeecgBoot401Exception("Token非法无效!");
} }
// 查询用户信息 // 查询用户信息
LoginUser user = commonAPI.getUserByName(username); LoginUser user = commonAPI.getUserByName(username);
if (user == null) { if (user == null) {
throw new AuthenticationException("用户不存在!"); throw new JeecgBoot401Exception("用户不存在!");
} }
// 判断用户状态 // 判断用户状态
if (user.getStatus() != 1) { if (user.getStatus() != 1) {
throw new AuthenticationException("账号已锁定,请联系管理员!"); throw new JeecgBoot401Exception("账号已锁定,请联系管理员!");
} }
// 校验token是否超时失效 & 或者账号密码是否错误 // 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) { if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
throw new AuthenticationException("Token失效请重新登录"); throw new JeecgBoot401Exception("Token失效请重新登录");
}
return true;
}
/**
* Token
*/
public static boolean verifyToken(String token, CommonAPI commonAPI, RedisUtil redisUtil) {
if (StringUtils.isBlank(token)) {
throw new JeecgBoot401Exception("token不能为空!");
}
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new JeecgBoot401Exception("token非法无效!");
}
// 查询用户信息
LoginUser user = commonAPI.getUserByName(username);
if (user == null) {
throw new JeecgBoot401Exception("用户不存在!");
}
// 判断用户状态
if (user.getStatus() != 1) {
throw new JeecgBoot401Exception("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
throw new JeecgBoot401Exception(CommonConstant.TOKEN_IS_INVALID_MSG);
} }
return true; return true;
} }
@ -95,34 +125,4 @@ public class TokenUtils {
return false; return false;
} }
/**
* Token
*/
public static boolean verifyToken(String token, CommonAPI commonAPI, RedisUtil redisUtil) {
if (StringUtils.isBlank(token)) {
throw new AuthenticationException("token不能为空!");
}
// 解密获得username用于和数据库进行对比
String username = JwtUtil.getUsername(token);
if (username == null) {
throw new AuthenticationException("token非法无效!");
}
// 查询用户信息
LoginUser user = commonAPI.getUserByName(username);
if (user == null) {
throw new AuthenticationException("用户不存在!");
}
// 判断用户状态
if (user.getStatus() != 1) {
throw new AuthenticationException("账号已被锁定,请联系管理员!");
}
// 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, user.getPassword(), redisUtil)) {
throw new AuthenticationException("Token失效请重新登录!");
}
return true;
}
} }

View File

@ -1,6 +1,10 @@
package org.jeecg.common.util.dynamic.db; package org.jeecg.common.util.dynamic.db;
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.DbType;
import org.jeecg.common.constant.DataBaseConstant;
import java.util.HashMap;
import java.util.Map;
/** /**
* *
@ -8,6 +12,34 @@ import com.baomidou.mybatisplus.annotation.DbType;
*/ */
public class DbTypeUtils { public class DbTypeUtils {
public static Map<String, String> dialectMap = new HashMap<String, String>();
static{
dialectMap.put("mysql", "org.hibernate.dialect.MySQL5InnoDBDialect");
dialectMap.put("mariadb", "org.hibernate.dialect.MariaDBDialect");// 1 --
dialectMap.put("oracle", "org.hibernate.dialect.OracleDialect");//1
dialectMap.put("oracle12c", "org.hibernate.dialect.OracleDialect"); // TODO 没找到不确定
dialectMap.put("db2", "org.hibernate.dialect.DB2390Dialect"); // 1xx
dialectMap.put("h2", "org.hibernate.dialect.HSQLDialect");// H2数据库
dialectMap.put("hsql", "org.hibernate.dialect.HSQLDialect");// HSQL数据库 1
dialectMap.put("sqlite", "org.jeecg.modules.online.config.dialect.SQLiteDialect"); //SQLite数据库 应用平台mobile
dialectMap.put("postgresql", "org.hibernate.dialect.PostgreSQLDialect"); //1 --
dialectMap.put("sqlserver2005", "org.hibernate.dialect.SQLServer2005Dialect");
dialectMap.put("sqlserver", "org.hibernate.dialect.SQLServerDialect"); //1
dialectMap.put("dm", "org.hibernate.dialect.OracleDialect");//达梦数据库 [国产] 1--
dialectMap.put("xugu", "org.hibernate.dialect.HSQLDialect"); //虚谷数据库
dialectMap.put("kingbasees", "org.hibernate.dialect.PostgreSQLDialect"); //人大金仓 [国产] 1
dialectMap.put("phoenix", "org.hibernate.dialect.HSQLDialect"); // Phoenix HBase数据库
dialectMap.put("zenith", "org.hibernate.dialect.PostgreSQLDialect"); // Gauss 数据库
dialectMap.put("clickhouse", "org.hibernate.dialect.MySQLDialect"); //阿里云PolarDB
dialectMap.put("gbase", "org.hibernate.dialect.PostgreSQLDialect"); // 南大通用数据库 TODO 没找到不确定
dialectMap.put("oscar", "org.hibernate.dialect.PostgreSQLDialect"); //神通数据库 [国产] TODO 没找到不确定
dialectMap.put("sybase", "org.hibernate.dialect.SybaseDialect"); //Sybase ASE 数据库
dialectMap.put("oceanbase", "org.hibernate.dialect.PostgreSQLDialect"); //OceanBase 数据库 TODO 没找到不确定
dialectMap.put("Firebird", "org.hibernate.dialect.FirebirdDialect");
dialectMap.put("highgo", "org.hibernate.dialect.HSQLDialect"); //瀚高数据库
dialectMap.put("other", "org.hibernate.dialect.PostgreSQLDialect");
}
public static boolean dbTypeIsMySQL(DbType dbType) { public static boolean dbTypeIsMySQL(DbType dbType) {
return dbTypeIf(dbType, DbType.MYSQL, DbType.MARIADB, DbType.CLICK_HOUSE, DbType.SQLITE); return dbTypeIf(dbType, DbType.MYSQL, DbType.MARIADB, DbType.CLICK_HOUSE, DbType.SQLITE);
} }
@ -24,6 +56,37 @@ public class DbTypeUtils {
return dbTypeIf(dbType, DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.GAUSS); return dbTypeIf(dbType, DbType.POSTGRE_SQL, DbType.KINGBASE_ES, DbType.GAUSS);
} }
/**
*
* @param dbType
* @return
*/
public static String getDbTypeString(DbType dbType){
if(DbType.DB2.equals(dbType)){
return DataBaseConstant.DB_TYPE_DB2;
}else if(DbType.HSQL.equals(dbType)){
return DataBaseConstant.DB_TYPE_HSQL;
}else if(dbTypeIsOracle(dbType)){
return DataBaseConstant.DB_TYPE_ORACLE;
}else if(dbTypeIsSQLServer(dbType)){
return DataBaseConstant.DB_TYPE_SQLSERVER;
}else if(dbTypeIsPostgre(dbType)){
return DataBaseConstant.DB_TYPE_POSTGRESQL;
}
return DataBaseConstant.DB_TYPE_MYSQL;
}
/**
*
* @param dbType
* @return
*/
public static String getDbDialect(DbType dbType){
return dialectMap.get(dbType.getDb());
}
/** /**
* *
*/ */

View File

@ -111,6 +111,16 @@ public class DynamicDBUtil {
return new JdbcTemplate(dataSource); return new JdbcTemplate(dataSource);
} }
/**
* NamedParameterJdbcTemplate
* @param dbKey
* @return
*/
private static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(String dbKey) {
DruidDataSource dataSource = getDbSourceByDbKey(dbKey);
return new NamedParameterJdbcTemplate(dataSource);
}
/** /**
* Executes the SQL statement in this <code>PreparedStatement</code> object, * Executes the SQL statement in this <code>PreparedStatement</code> object,
* which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
@ -221,6 +231,31 @@ public class DynamicDBUtil {
return list; return list;
} }
/**
*
* @param dbKey
* @param sql
* @param param
* @return
*/
public static Map<String, Object> queryCount(String dbKey, String sql, Map<String, Object> param){
NamedParameterJdbcTemplate npJdbcTemplate = getNamedParameterJdbcTemplate(dbKey);
return npJdbcTemplate.queryForMap(sql, param);
}
/**
*
* @param dbKey
* @param sql
* @param param
* @return
*/
public static List<Map<String, Object>> findListByNamedParam(final String dbKey, String sql, Map<String, Object> param) {
NamedParameterJdbcTemplate npJdbcTemplate = getNamedParameterJdbcTemplate(dbKey);
List<Map<String, Object>> list = npJdbcTemplate.queryForList(sql, param);
return list;
}
/** /**
* miniDao * miniDao
* *

View File

@ -0,0 +1,25 @@
package org.jeecg.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
*
*/
@Component("jeeccgBaseConfig")
@ConfigurationProperties(prefix = "jeecg")
public class JeeccgBaseConfig {
/**
*
*/
private Boolean safeMode = false;
public Boolean getSafeMode() {
return safeMode;
}
public void setSafeMode(Boolean safeMode) {
this.safeMode = safeMode;
}
}

View File

@ -35,6 +35,11 @@ public class MybatisPlusSaasConfig {
static { static {
tenantTable.add("demo"); tenantTable.add("demo");
// //角色、菜单、部门
// tenantTable.add("sys_role");
// tenantTable.add("sys_permission");
// tenantTable.add("sys_depart");
} }

View File

@ -118,8 +118,12 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/jmreport/**", "anon"); filterChainDefinitionMap.put("/jmreport/**", "anon");
filterChainDefinitionMap.put("/**/*.js.map", "anon"); filterChainDefinitionMap.put("/**/*.js.map", "anon");
filterChainDefinitionMap.put("/**/*.css.map", "anon"); filterChainDefinitionMap.put("/**/*.css.map", "anon");
//大屏模板例子
filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //测试示例
filterChainDefinitionMap.put("/test/bigScreen/**", "anon"); //大屏模板例子
//filterChainDefinitionMap.put("/test/jeecgDemo/rabbitMqClientTest/**", "anon"); //MQ测试
//filterChainDefinitionMap.put("/test/jeecgDemo/html", "anon"); //模板页面
//filterChainDefinitionMap.put("/test/jeecgDemo/redis/**", "anon"); //redis测试
//websocket排除 //websocket排除
filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告 filterChainDefinitionMap.put("/websocket/**", "anon");//系统通知和公告

View File

@ -1,6 +1,5 @@
package org.jeecg.config.shiro; package org.jeecg.config.shiro;
import cn.hutool.crypto.SecureUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationInfo;
@ -11,7 +10,6 @@ import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.PrincipalCollection;
import org.jeecg.common.api.CommonAPI; import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
@ -97,7 +95,14 @@ public class ShiroRealm extends AuthorizingRealm {
throw new AuthenticationException("token为空!"); throw new AuthenticationException("token为空!");
} }
// 校验token有效性 // 校验token有效性
LoginUser loginUser = this.checkUserTokenIsEffect(token); LoginUser loginUser = null;
try {
loginUser = this.checkUserTokenIsEffect(token);
} catch (AuthenticationException e) {
JwtUtil.responseError(SpringContextUtils.getHttpServletResponse(),401,e.getMessage());
e.printStackTrace();
return null;
}
return new SimpleAuthenticationInfo(loginUser, token, getName()); return new SimpleAuthenticationInfo(loginUser, token, getName());
} }
@ -125,7 +130,7 @@ public class ShiroRealm extends AuthorizingRealm {
} }
// 校验token是否超时失效 & 或者账号密码是否错误 // 校验token是否超时失效 & 或者账号密码是否错误
if (!jwtTokenRefresh(token, username, loginUser.getPassword())) { if (!jwtTokenRefresh(token, username, loginUser.getPassword())) {
throw new AuthenticationException("Token失效请重新登录!"); throw new AuthenticationException(CommonConstant.TOKEN_IS_INVALID_MSG);
} }
//update-begin-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致 //update-begin-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致
String userTenantIds = loginUser.getRelTenantIds(); String userTenantIds = loginUser.getRelTenantIds();

View File

@ -1,9 +1,9 @@
package org.jeecg.config.shiro.filters; package org.jeecg.config.shiro.filters;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.TenantContext; import org.jeecg.config.mybatis.TenantContext;
import org.jeecg.config.shiro.JwtToken; import org.jeecg.config.shiro.JwtToken;
@ -48,7 +48,9 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
executeLogin(request, response); executeLogin(request, response);
return true; return true;
} catch (Exception e) { } catch (Exception e) {
throw new AuthenticationException("Token失效请重新登录", e); JwtUtil.responseError(response,401,CommonConstant.TOKEN_IS_INVALID_MSG);
return false;
//throw new AuthenticationException("Token失效请重新登录", e);
} }
} }

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-base</artifactId> <artifactId>jeecg-boot-base</artifactId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<description>公共模块</description> <description>公共模块</description>

View File

@ -1,8 +1,9 @@
package org.jeecg.common.config.mqtoken; package org.jeecg.common.config.mqtoken;
import java.io.IOException;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/** /**
* tokenfeign使 * tokenfeign使

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>jeecg-boot-parent</artifactId> <artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>jeecg-boot-parent</artifactId> <artifactId>jeecg-boot-parent</artifactId>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,5 +1,14 @@
package org.jeecg.modules.demo.mock; package org.jeecg.modules.demo.mock;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.jeecg.common.api.vo.Result;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -8,20 +17,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.io.IOUtils;
import org.jeecg.common.api.vo.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@RestController @RestController
@RequestMapping("/mock/api") @RequestMapping("/mock/api")
@Slf4j @Slf4j
@ -42,8 +37,9 @@ public class MockController {
} }
@GetMapping(value = "/asynTreeList") @GetMapping(value = "/asynTreeList")
public String asynTreeList(String id) { public Result asynTreeList(String id) {
return readJson(JSON_PATH + "/asyn_tree_list_" + id + ".json"); String json = readJson(JSON_PATH + "/asyn_tree_list_" + id + ".json");
return Result.OK(JSON.parseArray(json));
} }
@GetMapping(value = "/user") @GetMapping(value = "/user")

View File

@ -1,29 +1,23 @@
{ [
"status": 200, {
"success": true, "id": 1,
"message": "ok", "name": "首页",
"result": [ "component": "dashboard/Analysis",
{ "orderNum": 1,
"id": 1, "hasChildren": false
"name": "首页", },
"component": "dashboard/Analysis", {
"orderNum": 1, "id": 2,
"hasChildren": false "name": "常见案例",
}, "component": "layouts/RouteView",
{ "orderNum": 2,
"id": 2, "hasChildren": true
"name": "常见案例", },
"component": "layouts/RouteView", {
"orderNum": 2, "id": 3,
"hasChildren": true "name": "系统监控",
}, "component": "layouts/RouteView",
{ "orderNum": 3,
"id": 3, "hasChildren": true
"name": "系统监控", }
"component": "layouts/RouteView", ]
"orderNum": 3,
"hasChildren": true
}
],
"timestamp": 1554950583837
}

View File

@ -1,29 +1,23 @@
{ [
"status": 200, {
"success": true, "id": 11,
"message": "ok", "name": "首页",
"result": [ "component": "dashboard/Analysis",
{ "orderNum": 1,
"id": 11, "hasChildren": false
"name": "首页", },
"component": "dashboard/Analysis", {
"orderNum": 1, "id": 12,
"hasChildren": false "name": "系统管理",
}, "component": "layouts/RouteView",
{ "orderNum": 2,
"id": 12, "hasChildren": true
"name": "系统管理", },
"component": "layouts/RouteView", {
"orderNum": 2, "id": 13,
"hasChildren": true "name": "常见案例",
}, "component": "layouts/RouteView",
{ "orderNum": 3,
"id": 13, "hasChildren": true
"name": "常见案例", }
"component": "layouts/RouteView", ]
"orderNum": 3,
"hasChildren": true
}
],
"timestamp": 1554950583837
}

View File

@ -1,29 +1,23 @@
{ [
"status": 200, {
"success": true, "id": 21,
"message": "ok", "name": "弹框选择Demo",
"result": [ "component": "jeecg/SelectDemo",
{ "orderNum": 1,
"id": 21, "hasChildren": false
"name": "弹框选择Demo", },
"component": "jeecg/SelectDemo", {
"orderNum": 1, "id": 22,
"hasChildren": false "name": "单表模型示例",
}, "component": "jeecg/JeecgDemoList",
{ "orderNum": 2,
"id": 22, "hasChildren": false
"name": "单表模型示例", },
"component": "jeecg/JeecgDemoList", {
"orderNum": 2, "id": 23,
"hasChildren": false "name": "一对多Tab示例",
}, "component": "jeecg/tablist/JeecgOrderDMainList",
{ "orderNum": 3,
"id": 23, "hasChildren": false
"name": "一对多Tab示例", }
"component": "jeecg/tablist/JeecgOrderDMainList", ]
"orderNum": 3,
"hasChildren": false
}
],
"timestamp": 1554950583837
}

View File

@ -1,29 +1,23 @@
{ [
"status": 200, {
"success": true, "id": 31,
"message": "ok", "name": "性能监控",
"result": [ "component": "layouts/RouteView",
{ "orderNum": 1,
"id": 31, "hasChildren": true
"name": "性能监控", },
"component": "layouts/RouteView", {
"orderNum": 1, "id": 32,
"hasChildren": true "name": "在线文档",
}, "component": "layouts/IframePageView",
{ "orderNum": 2,
"id": 32, "hasChildren": false
"name": "在线文档", },
"component": "layouts/IframePageView", {
"orderNum": 2, "id": 33,
"hasChildren": false "name": "工作台",
}, "component": "dashboard/Workplace",
{ "orderNum": 3,
"id": 33, "hasChildren": false
"name": "工作台", }
"component": "dashboard/Workplace", ]
"orderNum": 3,
"hasChildren": false
}
],
"timestamp": 1554950583837
}

View File

@ -1,29 +1,23 @@
{ [
"status": 200, {
"success": true, "id": 311,
"message": "ok", "name": "Redis监控",
"result": [ "component": "modules/monitor/RedisInfo",
{ "orderNum": 1,
"id": 311, "hasChildren": false
"name": "Redis监控", },
"component": "modules/monitor/RedisInfo", {
"orderNum": 1, "id": 312,
"hasChildren": false "name": "JVM信息",
}, "component": "modules/monitor/JvmInfo",
{ "orderNum": 2,
"id": 312, "hasChildren": false
"name": "JVM信息", },
"component": "modules/monitor/JvmInfo", {
"orderNum": 2, "id": 313,
"hasChildren": false "name": "Tomcat信息",
}, "component": "modules/monitor/TomcatInfo",
{ "orderNum": 3,
"id": 313, "hasChildren": false
"name": "Tomcat信息", }
"component": "modules/monitor/TomcatInfo", ]
"orderNum": 3,
"hasChildren": false
}
],
"timestamp": 1554950583837
}

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.demo.test.controller; package org.jeecg.modules.demo.test.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
@ -282,4 +283,38 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
return Result.OK(pageList); return Result.OK(pageList);
} }
/*----------------------------------------外部获取权限示例------------------------------------*/ /*----------------------------------------外部获取权限示例------------------------------------*/
/**
* online api
* @param params
* @return
*/
@PostMapping("/enhanceJavaListHttp")
public Result enhanceJavaListHttp(@RequestBody JSONObject params) {
log.info(" =========================================================== ");
log.info("params: " + params.toJSONString());
log.info("params.tableName: " + params.getString("tableName"));
log.info("params.json: " + params.getJSONObject("json").toJSONString());
JSONArray dataList = params.getJSONArray("dataList");
log.info("params.dataList: " + dataList.toJSONString());
log.info(" =========================================================== ");
return Result.OK(dataList);
}
/**
* online api
* @param params
* @return
*/
@PostMapping("/enhanceJavaFormHttp")
public Result enhanceJavaFormHttp(@RequestBody JSONObject params) {
log.info(" =========================================================== ");
log.info("params: " + params.toJSONString());
log.info("params.tableName: " + params.getString("tableName"));
log.info("params.json: " + params.getJSONObject("json").toJSONString());
log.info(" =========================================================== ");
return Result.OK("1");
}
} }

View File

@ -28,10 +28,6 @@ import lombok.experimental.Accessors;
@TableName("demo") @TableName("demo")
public class JeecgDemo extends JeecgEntity implements Serializable { public class JeecgDemo extends JeecgEntity implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/** 部门编码 */
@Excel(name="部门编码",width=25)
@ApiModelProperty(value = "部门编码")
private java.lang.String sysOrgCode;
/** 姓名 */ /** 姓名 */
@Excel(name="姓名",width=25) @Excel(name="姓名",width=25)
@ApiModelProperty(value = "姓名") @ApiModelProperty(value = "姓名")
@ -75,7 +71,10 @@ public class JeecgDemo extends JeecgEntity implements Serializable {
/** 个人简介 */ /** 个人简介 */
@ApiModelProperty(value = "个人简介") @ApiModelProperty(value = "个人简介")
private java.lang.String content; private java.lang.String content;
@ApiModelProperty(value = "租户ID") @ApiModelProperty(value = "租户ID")
private java.lang.Integer tenantId; private java.lang.Integer tenantId;
/** 部门编码 */
@Excel(name="部门编码",width=25)
@ApiModelProperty(value = "部门编码")
private java.lang.String sysOrgCode;
} }

View File

@ -10,6 +10,6 @@ WORKDIR /jeecg-boot
EXPOSE 8080 EXPOSE 8080
ADD ./target/jeecg-boot-module-system-2.4.6.jar ./ ADD ./target/jeecg-boot-module-system-3.0.jar ./
CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-2.4.6.jar CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.0.jar

View File

@ -4,7 +4,7 @@
<parent> <parent>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-parent</artifactId> <artifactId>jeecg-boot-parent</artifactId>
<version>2.4.6</version> <version>3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -54,7 +54,7 @@
<dependency> <dependency>
<groupId>org.jeecgframework.jimureport</groupId> <groupId>org.jeecgframework.jimureport</groupId>
<artifactId>jimureport-spring-boot-starter</artifactId> <artifactId>jimureport-spring-boot-starter</artifactId>
<version>1.3.78</version> <version>1.4.0</version>
</dependency> </dependency>
@ -62,7 +62,7 @@
<dependency> <dependency>
<groupId>org.jeecgframework.boot</groupId> <groupId>org.jeecgframework.boot</groupId>
<artifactId>jeecg-boot-module-demo</artifactId> <artifactId>jeecg-boot-module-demo</artifactId>
<version>2.4.6</version> <version>3.0</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,17 +1,12 @@
package org.jeecg; package org.jeecg;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.Context;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
//import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import java.net.InetAddress; import java.net.InetAddress;

View File

@ -80,8 +80,12 @@ public class WebSocket {
Session session = sessionPool.get(userId); Session session = sessionPool.get(userId);
if (session != null && session.isOpen()) { if (session != null && session.isOpen()) {
try { try {
log.info("【websocket消息】 单点消息:" + message); //update-begin-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
session.getAsyncRemote().sendText(message); synchronized (session){
log.info("【websocket消息】 单点消息:" + message);
session.getBasicRemote().sendText(message);
}
//update-end-author:taoyan date:20211012 for: websocket报错 https://gitee.com/jeecg/jeecg-boot/issues/I4C0MU
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -2,10 +2,6 @@ package org.jeecg.modules.oss.controller;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.authz.annotation.RequiresRoles;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryGenerator;
@ -13,14 +9,18 @@ import org.jeecg.modules.oss.entity.OSSFile;
import org.jeecg.modules.oss.service.IOSSFileService; import org.jeecg.modules.oss.service.IOSSFileService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
/**
* DEMO
*/
@Slf4j @Slf4j
@Controller @Controller
@RequestMapping("/sys/oss/file") @RequestMapping("/sys/oss/file")

View File

@ -89,7 +89,7 @@ public class QuartzJobController {
* @return * @return
*/ */
//@RequiresRoles("admin") //@RequiresRoles("admin")
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<?> eidt(@RequestBody QuartzJob quartzJob) { public Result<?> eidt(@RequestBody QuartzJob quartzJob) {
try { try {
quartzJobService.editAndScheduleJob(quartzJob); quartzJobService.editAndScheduleJob(quartzJob);
@ -228,8 +228,13 @@ public class QuartzJobController {
params.setHeadRows(1); params.setHeadRows(1);
params.setNeedSave(true); params.setNeedSave(true);
try { try {
List<Object> listQuartzJobs = ExcelImportUtil.importExcel(file.getInputStream(), QuartzJob.class, params); List<QuartzJob> listQuartzJobs = ExcelImportUtil.importExcel(file.getInputStream(), QuartzJob.class, params);
//add-begin-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
for(QuartzJob job: listQuartzJobs){
job.setStatus(CommonConstant.STATUS_DISABLE);
}
List<String> list = ImportExcelUtil.importDateSave(listQuartzJobs, IQuartzJobService.class, errorMessage,CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME); List<String> list = ImportExcelUtil.importDateSave(listQuartzJobs, IQuartzJobService.class, errorMessage,CommonConstant.SQL_INDEX_UNIQ_JOB_CLASS_NAME);
//add-end-author:taoyan date:20210909 for:导入定时任务,并不会被启动和调度,需要手动点击启动,才会加入调度任务中 #2986
errorLines+=list.size(); errorLines+=list.size();
successLines+=(listQuartzJobs.size()-errorLines); successLines+=(listQuartzJobs.size()-errorLines);
} catch (Exception e) { } catch (Exception e) {

View File

@ -118,6 +118,30 @@ public class LoginController {
return result; return result;
} }
/**
* vue3
*/
@GetMapping("/user/getUserInfo")
public Result<JSONObject> getUserInfo(HttpServletRequest request){
Result<JSONObject> result = new Result<JSONObject>();
String username = JwtUtil.getUserNameByToken(request);
if(oConvertUtils.isNotEmpty(username)) {
// 根据用户名查询用户信息
SysUser sysUser = sysUserService.getUserByName(username);
//用户登录信息
Result<JSONObject> resultObj=userInfo(sysUser, result);
JSONObject jsonObject=resultObj.getResult();
JSONObject obj=new JSONObject();
obj.put("userInfo",jsonObject.get("userInfo"));
obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
result.setResult(obj);
result.success("");
}
return result;
}
/** /**
* 退 * 退
* @param request * @param request

View File

@ -0,0 +1,19 @@
package org.jeecg.modules.system.controller;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.system.entity.SysUser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* vue3
*/
@RestController
@RequestMapping("/")
@Slf4j
public class MockVue3Controller {
}

View File

@ -140,7 +140,7 @@ public class SysAnnouncementController {
* @param sysAnnouncement * @param sysAnnouncement
* @return * @return
*/ */
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysAnnouncement> eidt(@RequestBody SysAnnouncement sysAnnouncement) { public Result<SysAnnouncement> eidt(@RequestBody SysAnnouncement sysAnnouncement) {
Result<SysAnnouncement> result = new Result<SysAnnouncement>(); Result<SysAnnouncement> result = new Result<SysAnnouncement>();
SysAnnouncement sysAnnouncementEntity = sysAnnouncementService.getById(sysAnnouncement.getId()); SysAnnouncement sysAnnouncementEntity = sysAnnouncementService.getById(sysAnnouncement.getId());
@ -314,7 +314,7 @@ public class SysAnnouncementController {
* @return * @return
*/ */
@RequestMapping(value = "/listByUser", method = RequestMethod.GET) @RequestMapping(value = "/listByUser", method = RequestMethod.GET)
public Result<Map<String,Object>> listByUser() { public Result<Map<String, Object>> listByUser(@RequestParam(required = false, defaultValue = "5") Integer pageSize) {
Result<Map<String,Object>> result = new Result<Map<String,Object>>(); Result<Map<String,Object>> result = new Result<Map<String,Object>>();
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal(); LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
String userId = sysUser.getId(); String userId = sysUser.getId();
@ -347,9 +347,9 @@ public class SysAnnouncementController {
} }
} }
// 2.查询用户未读的系统消息 // 2.查询用户未读的系统消息
Page<SysAnnouncement> anntMsgList = new Page<SysAnnouncement>(0,5); Page<SysAnnouncement> anntMsgList = new Page<SysAnnouncement>(0, pageSize);
anntMsgList = sysAnnouncementService.querySysCementPageByUserId(anntMsgList,userId,"1");//通知公告消息 anntMsgList = sysAnnouncementService.querySysCementPageByUserId(anntMsgList,userId,"1");//通知公告消息
Page<SysAnnouncement> sysMsgList = new Page<SysAnnouncement>(0,5); Page<SysAnnouncement> sysMsgList = new Page<SysAnnouncement>(0, pageSize);
sysMsgList = sysAnnouncementService.querySysCementPageByUserId(sysMsgList,userId,"2");//系统消息 sysMsgList = sysAnnouncementService.querySysCementPageByUserId(sysMsgList,userId,"2");//系统消息
Map<String,Object> sysMsgMap = new HashMap<String, Object>(); Map<String,Object> sysMsgMap = new HashMap<String, Object>();
sysMsgMap.put("sysMsgList", sysMsgList.getRecords()); sysMsgMap.put("sysMsgList", sysMsgList.getRecords());

View File

@ -8,8 +8,10 @@ import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.WebsocketConst;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.message.websocket.WebSocket;
import org.jeecg.modules.system.entity.SysAnnouncementSend; import org.jeecg.modules.system.entity.SysAnnouncementSend;
import org.jeecg.modules.system.model.AnnouncementSendModel; import org.jeecg.modules.system.model.AnnouncementSendModel;
import org.jeecg.modules.system.service.ISysAnnouncementSendService; import org.jeecg.modules.system.service.ISysAnnouncementSendService;
@ -45,6 +47,8 @@ import lombok.extern.slf4j.Slf4j;
public class SysAnnouncementSendController { public class SysAnnouncementSendController {
@Autowired @Autowired
private ISysAnnouncementSendService sysAnnouncementSendService; private ISysAnnouncementSendService sysAnnouncementSendService;
@Autowired
private WebSocket webSocket;
/** /**
* *
@ -235,6 +239,9 @@ public class SysAnnouncementSendController {
updateWrapper.last("where user_id ='"+userId+"'"); updateWrapper.last("where user_id ='"+userId+"'");
SysAnnouncementSend announcementSend = new SysAnnouncementSend(); SysAnnouncementSend announcementSend = new SysAnnouncementSend();
sysAnnouncementSendService.update(announcementSend, updateWrapper); sysAnnouncementSendService.update(announcementSend, updateWrapper);
JSONObject socketParams = new JSONObject();
socketParams.put(WebsocketConst.MSG_CMD, WebsocketConst.CMD_TOPIC);
webSocket.sendMessage(socketParams.toJSONString());
result.setSuccess(true); result.setSuccess(true);
result.setMessage("全部已读"); result.setMessage("全部已读");
return result; return result;

View File

@ -111,7 +111,7 @@ public class SysCategoryController {
* @param sysCategory * @param sysCategory
* @return * @return
*/ */
@PutMapping(value = "/edit") @RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
public Result<SysCategory> edit(@RequestBody SysCategory sysCategory) { public Result<SysCategory> edit(@RequestBody SysCategory sysCategory) {
Result<SysCategory> result = new Result<SysCategory>(); Result<SysCategory> result = new Result<SysCategory>();
SysCategory sysCategoryEntity = sysCategoryService.getById(sysCategory.getId()); SysCategory sysCategoryEntity = sysCategoryService.getById(sysCategory.getId());

View File

@ -128,7 +128,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
*/ */
@AutoLog(value = "多数据源管理-编辑") @AutoLog(value = "多数据源管理-编辑")
@ApiOperation(value = "多数据源管理-编辑", notes = "多数据源管理-编辑") @ApiOperation(value = "多数据源管理-编辑", notes = "多数据源管理-编辑")
@PutMapping(value = "/edit") @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<?> edit(@RequestBody SysDataSource sysDataSource) { public Result<?> edit(@RequestBody SysDataSource sysDataSource) {
try { try {
SysDataSource d = sysDataSourceService.getById(sysDataSource.getId()); SysDataSource d = sysDataSourceService.getById(sysDataSource.getId());

View File

@ -97,7 +97,7 @@ public class SysDepartController {
* @return * @return
*/ */
@RequestMapping(value = "/queryTreeList", method = RequestMethod.GET) @RequestMapping(value = "/queryTreeList", method = RequestMethod.GET)
public Result<List<SysDepartTreeModel>> queryTreeList() { public Result<List<SysDepartTreeModel>> queryTreeList(@RequestParam(name = "ids", required = false) String ids) {
Result<List<SysDepartTreeModel>> result = new Result<>(); Result<List<SysDepartTreeModel>> result = new Result<>();
try { try {
// 从内存中读取 // 从内存中读取
@ -105,8 +105,13 @@ public class SysDepartController {
// if (CollectionUtils.isEmpty(list)) { // if (CollectionUtils.isEmpty(list)) {
// list = sysDepartService.queryTreeList(); // list = sysDepartService.queryTreeList();
// } // }
List<SysDepartTreeModel> list = sysDepartService.queryTreeList(); if(oConvertUtils.isNotEmpty(ids)){
result.setResult(list); List<SysDepartTreeModel> departList = sysDepartService.queryTreeList(ids);
result.setResult(departList);
}else{
List<SysDepartTreeModel> list = sysDepartService.queryTreeList();
result.setResult(list);
}
result.setSuccess(true); result.setSuccess(true);
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(),e); log.error(e.getMessage(),e);
@ -116,14 +121,15 @@ public class SysDepartController {
/** /**
* list * list
* * @param parentId
* @param ids
* @return * @return
*/ */
@RequestMapping(value = "/queryDepartTreeSync", method = RequestMethod.GET) @RequestMapping(value = "/queryDepartTreeSync", method = RequestMethod.GET)
public Result<List<SysDepartTreeModel>> queryDepartTreeSync(@RequestParam(name = "pid", required = false) String parentId) { public Result<List<SysDepartTreeModel>> queryDepartTreeSync(@RequestParam(name = "pid", required = false) String parentId,@RequestParam(name = "ids", required = false) String ids) {
Result<List<SysDepartTreeModel>> result = new Result<>(); Result<List<SysDepartTreeModel>> result = new Result<>();
try { try {
List<SysDepartTreeModel> list = sysDepartService.queryTreeListByPid(parentId); List<SysDepartTreeModel> list = sysDepartService.queryTreeListByPid(parentId,ids);
result.setResult(list); result.setResult(list);
result.setSuccess(true); result.setSuccess(true);
} catch (Exception e) { } catch (Exception e) {

View File

@ -359,7 +359,7 @@ public class SysDictController {
* @return * @return
*/ */
//@RequiresRoles({"admin"}) //@RequiresRoles({"admin"})
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
public Result<SysDict> edit(@RequestBody SysDict sysDict) { public Result<SysDict> edit(@RequestBody SysDict sysDict) {
Result<SysDict> result = new Result<SysDict>(); Result<SysDict> result = new Result<SysDict>();
SysDict sysdict = sysDictService.getById(sysDict.getId()); SysDict sysdict = sysDictService.getById(sysDict.getId());

View File

@ -93,7 +93,7 @@ public class SysDictItemController {
* @return * @return
*/ */
//@RequiresRoles({"admin"}) //@RequiresRoles({"admin"})
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method = { RequestMethod.PUT,RequestMethod.POST })
@CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true) @CacheEvict(value={CacheConstant.SYS_DICT_CACHE, CacheConstant.SYS_ENABLE_DICT_CACHE}, allEntries=true)
public Result<SysDictItem> edit(@RequestBody SysDictItem sysDictItem) { public Result<SysDictItem> edit(@RequestBody SysDictItem sysDictItem) {
Result<SysDictItem> result = new Result<SysDictItem>(); Result<SysDictItem> result = new Result<SysDictItem>();

View File

@ -14,16 +14,13 @@ import org.jeecg.common.constant.enums.RoleIndexConfigEnum;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.MD5Util; import org.jeecg.common.util.MD5Util;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysDepartPermission; import org.jeecg.config.JeeccgBaseConfig;
import org.jeecg.modules.system.entity.SysPermission; import org.jeecg.modules.system.entity.*;
import org.jeecg.modules.system.entity.SysPermissionDataRule;
import org.jeecg.modules.system.entity.SysRolePermission;
import org.jeecg.modules.system.model.SysPermissionTree; import org.jeecg.modules.system.model.SysPermissionTree;
import org.jeecg.modules.system.model.TreeModel; import org.jeecg.modules.system.model.TreeModel;
import org.jeecg.modules.system.service.*; import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.util.PermissionDataUtil; import org.jeecg.modules.system.util.PermissionDataUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.util.*; import java.util.*;
@ -56,12 +53,9 @@ public class SysPermissionController {
@Autowired @Autowired
private ISysUserService sysUserService; private ISysUserService sysUserService;
/**
* truefalse
*/
@Value(value = "${jeecg.safeMode:false}")
private Boolean sysSafeMode;
@Autowired
private JeeccgBaseConfig jeeccgBaseConfig;
/** /**
* *
@ -238,6 +232,9 @@ public class SysPermissionController {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
JSONArray menujsonArray = new JSONArray(); JSONArray menujsonArray = new JSONArray();
this.getPermissionJsonArray(menujsonArray, metaList, null); this.getPermissionJsonArray(menujsonArray, metaList, null);
//一级菜单下的子菜单全部是隐藏路由,则一级菜单不显示
this.handleFirstLevelMenuHidden(menujsonArray);
JSONArray authjsonArray = new JSONArray(); JSONArray authjsonArray = new JSONArray();
this.getAuthJsonArray(authjsonArray, metaList); this.getAuthJsonArray(authjsonArray, metaList);
//查询所有的权限 //查询所有的权限
@ -254,9 +251,37 @@ public class SysPermissionController {
json.put("auth", authjsonArray); json.put("auth", authjsonArray);
//全部权限配置集合(按钮权限,访问权限) //全部权限配置集合(按钮权限,访问权限)
json.put("allAuth", allauthjsonArray); json.put("allAuth", allauthjsonArray);
json.put("sysSafeMode", sysSafeMode); json.put("sysSafeMode", jeeccgBaseConfig.getSafeMode());
result.setResult(json); result.setResult(json);
result.success("查询成功"); } catch (Exception e) {
result.error500("查询失败:" + e.getMessage());
log.error(e.getMessage(), e);
}
return result;
}
/**
* vue3/访
* @return
*/
@RequestMapping(value = "/getPermCode", method = RequestMethod.GET)
public Result<?> getPermCode() {
Result<List<String>> result = new Result<List<String>>();
try {
//直接获取当前用户
LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//获取当前用户的权限集合
List<SysPermission> metaList = sysPermissionService.queryByUser(loginUser.getUsername());
//按钮权限(用户拥有的权限集合)
List<String> authList = metaList.stream()
.filter((permission) -> permission.getMenuType().equals(CommonConstant.MENU_TYPE_2)
&& CommonConstant.STATUS_1.equals(permission.getStatus())
)
.collect(() -> new ArrayList<String>(),
(list, permission) -> list.add(permission.getPerms()),
(list1, list2) -> list1.addAll(list2)
);
result.setResult(authList);
} catch (Exception e) { } catch (Exception e) {
result.error500("查询失败:" + e.getMessage()); result.error500("查询失败:" + e.getMessage());
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
@ -380,7 +405,7 @@ public class SysPermissionController {
} }
/** /**
* * [,]
* *
* @return * @return
*/ */
@ -482,6 +507,31 @@ public class SysPermissionController {
} }
} }
/**
*
* @param jsonArray
*/
private void handleFirstLevelMenuHidden(JSONArray jsonArray) {
jsonArray = jsonArray.stream().map(obj -> {
JSONObject returnObj = new JSONObject();
JSONObject jsonObj = (JSONObject)obj;
if(jsonObj.containsKey("children")){
JSONArray childrens = jsonObj.getJSONArray("children");
childrens = childrens.stream().filter(arrObj -> !"true".equals(((JSONObject) arrObj).getString("hidden"))).collect(Collectors.toCollection(JSONArray::new));
if(childrens==null || childrens.size()==0){
jsonObj.put("hidden",true);
//vue3版本兼容代码
JSONObject meta = new JSONObject();
meta.put("hideMenu",true);
jsonObj.put("meta", meta);
}
}
return returnObj;
}).collect(Collectors.toCollection(JSONArray::new));
}
/** /**
* JSON * JSON
* @param jsonArray * @param jsonArray
@ -605,16 +655,18 @@ public class SysPermissionController {
json.put("name", urlToRouteName(permission.getUrl())); json.put("name", urlToRouteName(permission.getUrl()));
} }
JSONObject meta = new JSONObject();
// 是否隐藏路由,默认都是显示的 // 是否隐藏路由,默认都是显示的
if (permission.isHidden()) { if (permission.isHidden()) {
json.put("hidden", true); json.put("hidden", true);
//vue3版本兼容代码
meta.put("hideMenu",true);
} }
// 聚合路由 // 聚合路由
if (permission.isAlwaysShow()) { if (permission.isAlwaysShow()) {
json.put("alwaysShow", true); json.put("alwaysShow", true);
} }
json.put("component", permission.getComponent()); json.put("component", permission.getComponent());
JSONObject meta = new JSONObject();
// 由用户设置是否缓存页面 用布尔值 // 由用户设置是否缓存页面 用布尔值
if (permission.isKeepAlive()) { if (permission.isKeepAlive()) {
meta.put("keepAlive", true); meta.put("keepAlive", true);
@ -654,6 +706,11 @@ public class SysPermissionController {
if (isWWWHttpUrl(permission.getUrl())) { if (isWWWHttpUrl(permission.getUrl())) {
meta.put("url", permission.getUrl()); meta.put("url", permission.getUrl());
} }
// update-begin--Author:sunjianlei Date:20210918 for新增适配vue3项目的隐藏tab功能
if (permission.isHideTab()) {
meta.put("hideTab", true);
}
// update-end--Author:sunjianlei Date:20210918 for新增适配vue3项目的隐藏tab功能
json.put("meta", meta); json.put("meta", meta);
} }
@ -776,7 +833,6 @@ public class SysPermissionController {
try { try {
List<SysPermissionDataRule> permRuleList = sysPermissionDataRuleService.queryPermissionRule(sysPermissionDataRule); List<SysPermissionDataRule> permRuleList = sysPermissionDataRuleService.queryPermissionRule(sysPermissionDataRule);
result.setResult(permRuleList); result.setResult(permRuleList);
result.success("查询成功!");
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
result.error500("操作失败"); result.error500("操作失败");

View File

@ -107,7 +107,7 @@ public class SysPositionController {
*/ */
@AutoLog(value = "职务表-编辑") @AutoLog(value = "职务表-编辑")
@ApiOperation(value = "职务表-编辑", notes = "职务表-编辑") @ApiOperation(value = "职务表-编辑", notes = "职务表-编辑")
@PutMapping(value = "/edit") @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<SysPosition> edit(@RequestBody SysPosition sysPosition) { public Result<SysPosition> edit(@RequestBody SysPosition sysPosition) {
Result<SysPosition> result = new Result<SysPosition>(); Result<SysPosition> result = new Result<SysPosition>();
SysPosition sysPositionEntity = sysPositionService.getById(sysPosition.getId()); SysPosition sysPositionEntity = sysPositionService.getById(sysPosition.getId());

View File

@ -129,7 +129,7 @@ public class SysRoleController {
* @return * @return
*/ */
//@RequiresRoles({"admin"}) //@RequiresRoles({"admin"})
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit",method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysRole> edit(@RequestBody SysRole role) { public Result<SysRole> edit(@RequestBody SysRole role) {
Result<SysRole> result = new Result<SysRole>(); Result<SysRole> result = new Result<SysRole>();
SysRole sysrole = sysRoleService.getById(role.getId()); SysRole sysrole = sysRoleService.getById(role.getId());

View File

@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
/** /**
@ -43,7 +44,23 @@ public class SysTenantController {
public Result<IPage<SysTenant>> queryPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo, public Result<IPage<SysTenant>> queryPageList(SysTenant sysTenant,@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) { @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) {
Result<IPage<SysTenant>> result = new Result<IPage<SysTenant>>(); Result<IPage<SysTenant>> result = new Result<IPage<SysTenant>>();
QueryWrapper<SysTenant> queryWrapper = QueryGenerator.initQueryWrapper(sysTenant, req.getParameterMap()); //---author:zhangyafei---date:20210916-----for: 租户管理添加日期范围查询---
Date beginDate=null;
Date endDate=null;
if(oConvertUtils.isNotEmpty(sysTenant)) {
beginDate=sysTenant.getBeginDate();
endDate=sysTenant.getEndDate();
sysTenant.setBeginDate(null);
sysTenant.setEndDate(null);
}
//---author:zhangyafei---date:20210916-----for: 租户管理添加日期范围查询---
QueryWrapper<SysTenant> queryWrapper = QueryGenerator.initQueryWrapper(sysTenant, req.getParameterMap());
//---author:zhangyafei---date:20210916-----for: 租户管理添加日期范围查询---
if(oConvertUtils.isNotEmpty(sysTenant)){
queryWrapper.ge(oConvertUtils.isNotEmpty(beginDate),"begin_date",beginDate);
queryWrapper.le(oConvertUtils.isNotEmpty(endDate),"end_date",endDate);
}
//---author:zhangyafei---date:20210916-----for: 租户管理添加日期范围查询---
Page<SysTenant> page = new Page<SysTenant>(pageNo, pageSize); Page<SysTenant> page = new Page<SysTenant>(pageNo, pageSize);
IPage<SysTenant> pageList = sysTenantService.page(page, queryWrapper); IPage<SysTenant> pageList = sysTenantService.page(page, queryWrapper);
result.setSuccess(true); result.setSuccess(true);
@ -58,7 +75,7 @@ public class SysTenantController {
*/ */
@RequestMapping(value = "/add", method = RequestMethod.POST) @RequestMapping(value = "/add", method = RequestMethod.POST)
public Result<SysTenant> add(@RequestBody SysTenant sysTenant) { public Result<SysTenant> add(@RequestBody SysTenant sysTenant) {
Result<SysTenant> result = new Result<SysTenant>(); Result<SysTenant> result = new Result();
if(sysTenantService.getById(sysTenant.getId())!=null){ if(sysTenantService.getById(sysTenant.getId())!=null){
return result.error500("该编号已存在!"); return result.error500("该编号已存在!");
} }
@ -77,17 +94,16 @@ public class SysTenantController {
* @param * @param
* @return * @return
*/ */
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method ={RequestMethod.PUT, RequestMethod.POST})
public Result<SysTenant> edit(@RequestBody SysTenant tenant) { public Result<SysTenant> edit(@RequestBody SysTenant tenant) {
Result<SysTenant> result = new Result<SysTenant>(); Result<SysTenant> result = new Result();
SysTenant sysTenant = sysTenantService.getById(tenant.getId()); SysTenant sysTenant = sysTenantService.getById(tenant.getId());
if(sysTenant==null) { if(sysTenant==null) {
result.error500("未找到对应实体"); return result.error500("未找到对应实体");
}else { }
boolean ok = sysTenantService.updateById(tenant); boolean ok = sysTenantService.updateById(tenant);
if(ok) { if(ok) {
result.success("修改成功!"); result.success("修改成功!");
}
} }
return result; return result;
} }
@ -97,7 +113,7 @@ public class SysTenantController {
* @param id * @param id
* @return * @return
*/ */
@RequestMapping(value = "/delete", method = RequestMethod.DELETE) @RequestMapping(value = "/delete", method ={RequestMethod.DELETE, RequestMethod.POST})
public Result<?> delete(@RequestParam(name="id",required=true) String id) { public Result<?> delete(@RequestParam(name="id",required=true) String id) {
sysTenantService.removeTenantById(id); sysTenantService.removeTenantById(id);
return Result.ok("删除成功"); return Result.ok("删除成功");

View File

@ -107,7 +107,7 @@ public class SysUserAgentController {
* @param sysUserAgent * @param sysUserAgent
* @return * @return
*/ */
@PutMapping(value = "/edit") @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysUserAgent> edit(@RequestBody SysUserAgent sysUserAgent) { public Result<SysUserAgent> edit(@RequestBody SysUserAgent sysUserAgent) {
Result<SysUserAgent> result = new Result<SysUserAgent>(); Result<SysUserAgent> result = new Result<SysUserAgent>();
SysUserAgent sysUserAgentEntity = sysUserAgentService.getById(sysUserAgent.getId()); SysUserAgent sysUserAgentEntity = sysUserAgentService.getById(sysUserAgent.getId());

View File

@ -157,7 +157,7 @@ public class SysUserController {
//@RequiresRoles({"admin"}) //@RequiresRoles({"admin"})
//@RequiresPermissions("user:edit") //@RequiresPermissions("user:edit")
@RequestMapping(value = "/edit", method = RequestMethod.PUT) @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<SysUser> edit(@RequestBody JSONObject jsonObject) { public Result<SysUser> edit(@RequestBody JSONObject jsonObject) {
Result<SysUser> result = new Result<SysUser>(); Result<SysUser> result = new Result<SysUser>();
try { try {
@ -172,6 +172,10 @@ public class SysUserController {
user.setPassword(sysUser.getPassword()); user.setPassword(sysUser.getPassword());
String roles = jsonObject.getString("selectedroles"); String roles = jsonObject.getString("selectedroles");
String departs = jsonObject.getString("selecteddeparts"); String departs = jsonObject.getString("selecteddeparts");
if(oConvertUtils.isEmpty(departs)){
//vue3.0前端只传递了departIds
departs=user.getDepartIds();
}
// 修改用户走一个service 保证事务 // 修改用户走一个service 保证事务
sysUserService.editUser(user, roles, departs); sysUserService.editUser(user, roles, departs);
result.success("修改成功!"); result.success("修改成功!");

View File

@ -1,9 +1,6 @@
package org.jeecg.modules.system.controller; package org.jeecg.modules.system.controller;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
@ -55,45 +52,38 @@ public class SysUserOnlineController {
private BaseCommonService baseCommonService; private BaseCommonService baseCommonService;
@RequestMapping(value = "/list", method = RequestMethod.GET) @RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username,
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) { @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
Collection<String> keys = redisTemplate.keys(CommonConstant.PREFIX_USER_TOKEN + "*"); Collection<String> keys = redisTemplate.keys(CommonConstant.PREFIX_USER_TOKEN + "*");
SysUserOnlineVO online;
List<SysUserOnlineVO> onlineList = new ArrayList<SysUserOnlineVO>(); List<SysUserOnlineVO> onlineList = new ArrayList<SysUserOnlineVO>();
for (String key : keys) { for (String key : keys) {
online = new SysUserOnlineVO(); String token = (String)redisUtil.get(key);
String token = (String) redisUtil.get(key); if (StringUtils.isNotEmpty(token)) {
if (!StringUtils.isEmpty(token)){ SysUserOnlineVO online = new SysUserOnlineVO();
online.setToken(token); online.setToken(token);
//TODO 改成一次性查询
LoginUser loginUser = sysBaseAPI.getUserByName(JwtUtil.getUsername(token)); LoginUser loginUser = sysBaseAPI.getUserByName(JwtUtil.getUsername(token));
BeanUtils.copyProperties(loginUser, online); BeanUtils.copyProperties(loginUser, online);
if (StringUtils.isNotEmpty(username)) { onlineList.add(online);
if (StringUtils.equals(username, online.getUsername())) {
onlineList.add(online);
}
} else {
onlineList.add(online);
}
} }
} }
Collections.reverse(onlineList);
Page<SysUserOnlineVO> page = new Page<SysUserOnlineVO>(pageNo, pageSize); Page<SysUserOnlineVO> page = new Page<SysUserOnlineVO>(pageNo, pageSize);
int count = onlineList.size(); int count = onlineList.size();
List<SysUserOnlineVO> pages = new ArrayList<>(); List<SysUserOnlineVO> pages = new ArrayList<>();
//计算当前页第一条数据的下标 // 计算当前页第一条数据的下标
int currId = pageNo>1 ? (pageNo-1)*pageSize:0; int currId = pageNo > 1 ? (pageNo - 1) * pageSize : 0;
for (int i=0; i<pageSize && i<count - currId;i++){ for (int i = 0; i < pageSize && i < count - currId; i++) {
pages.add(onlineList.get(currId+i)); pages.add(onlineList.get(currId + i));
} }
page.setSize(pageSize); page.setSize(pageSize);
page.setCurrent(pageNo); page.setCurrent(pageNo);
page.setTotal(count); page.setTotal(count);
//计算分页总页数 // 计算分页总页数
page.setPages(count %10 == 0 ? count/10 :count/10+1); page.setPages(count % 10 == 0 ? count / 10 : count / 10 + 1);
page.setRecords(pages); page.setRecords(pages);
Collections.reverse(onlineList);
onlineList.removeAll(Collections.singleton(null));
Result<Page<SysUserOnlineVO>> result = new Result<Page<SysUserOnlineVO>>(); Result<Page<SysUserOnlineVO>> result = new Result<Page<SysUserOnlineVO>>();
result.setSuccess(true); result.setSuccess(true);
result.setResult(page); result.setResult(page);

View File

@ -130,6 +130,11 @@ public class SysPermission implements Serializable {
*/ */
private boolean hidden; private boolean hidden;
/**
* Tab: 0,10
*/
private boolean hideTab;
/** /**
* *
*/ */

View File

@ -127,7 +127,7 @@
select ${text} as "title", select ${text} as "title",
${code} as "key", ${code} as "key",
<if test="hasChildField != null and hasChildField != ''"> <if test="hasChildField != null and hasChildField != ''">
(case when ${hasChildField} = '1' then 0 else 1 end) as isLeaf, ${hasChildField} as "isLeaf",
</if> </if>
${pidField} as parentId ${pidField} as parentId
from ${table} from ${table}

View File

@ -8,7 +8,7 @@
<result column="name" property="title" jdbcType="VARCHAR"/> <result column="name" property="title" jdbcType="VARCHAR"/>
<result column="icon" property="icon" jdbcType="VARCHAR"/> <result column="icon" property="icon" jdbcType="VARCHAR"/>
<result column="parent_id" property="parentId" jdbcType="VARCHAR"/> <result column="parent_id" property="parentId" jdbcType="VARCHAR"/>
<result column="leaf_flag" property="isLeaf" jdbcType="INTEGER"/> <result column="is_leaf" property="isLeaf" jdbcType="INTEGER"/>
</resultMap> </resultMap>
<!-- 通过<resultMap>映射实体类属性名和表的字段名对应关系 --> <!-- 通过<resultMap>映射实体类属性名和表的字段名对应关系 -->
@ -26,7 +26,7 @@
,parent_id ,parent_id
,name ,name
,icon ,icon
,leaf_flag ,is_leaf
FROM sys_permission FROM sys_permission
WHERE 1=1 WHERE 1=1
<choose> <choose>

View File

@ -29,6 +29,13 @@ public interface ISysDepartService extends IService<SysDepart>{
*/ */
List<SysDepartTreeModel> queryTreeList(); List<SysDepartTreeModel> queryTreeList();
/**
* ,
* @return
*/
List<SysDepartTreeModel> queryTreeList(String ids);
/** /**
* DepartId, * DepartId,
* @return * @return
@ -112,7 +119,7 @@ public interface ISysDepartService extends IService<SysDepart>{
* *
* @return * @return
*/ */
List<SysDepartTreeModel> queryTreeListByPid(String parentId); List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids);
/** /**
* ID * ID

View File

@ -114,8 +114,12 @@ public class SysAnnouncementServiceImpl extends ServiceImpl<SysAnnouncementMappe
} }
@Override @Override
public Page<SysAnnouncement> querySysCementPageByUserId(Page<SysAnnouncement> page, String userId,String msgCategory) { public Page<SysAnnouncement> querySysCementPageByUserId(Page<SysAnnouncement> page, String userId, String msgCategory) {
return page.setRecords(sysAnnouncementMapper.querySysCementListByUserId(page, userId, msgCategory)); if (page.getSize() == -1) {
return page.setRecords(sysAnnouncementMapper.querySysCementListByUserId(null, userId, msgCategory));
} else {
return page.setRecords(sysAnnouncementMapper.querySysCementListByUserId(page, userId, msgCategory));
}
} }
} }

View File

@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
/** /**
* <p> * <p>
@ -77,8 +78,8 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
/** /**
* queryTreeList queryTreeList , * queryTreeList queryTreeList ,
*/ */
@Cacheable(value = CacheConstant.SYS_DEPARTS_CACHE)
@Override @Override
@Cacheable(value = CacheConstant.SYS_DEPARTS_CACHE)
public List<SysDepartTreeModel> queryTreeList() { public List<SysDepartTreeModel> queryTreeList() {
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>(); LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString()); query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
@ -89,6 +90,26 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
return listResult; return listResult;
} }
/**
* queryTreeList id,
*/
@Override
public List<SysDepartTreeModel> queryTreeList(String ids) {
List<SysDepartTreeModel> listResult=new ArrayList<>();
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
if(oConvertUtils.isNotEmpty(ids)){
query.in(true,SysDepart::getId,ids.split(","));
}
query.orderByAsc(SysDepart::getDepartOrder);
List<SysDepart> list= this.list(query);
for (SysDepart depart : list) {
listResult.add(new SysDepartTreeModel(depart));
}
return listResult;
}
@Cacheable(value = CacheConstant.SYS_DEPART_IDS_CACHE) @Cacheable(value = CacheConstant.SYS_DEPART_IDS_CACHE)
@Override @Override
public List<DepartIdModel> queryDepartIdTreeList() { public List<DepartIdModel> queryDepartIdTreeList() {
@ -458,11 +479,27 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
/** /**
* parentId * parentId
* @param parentId * @param parentId
* @param ids
* @return * @return
*/ */
@Override @Override
public List<SysDepartTreeModel> queryTreeListByPid(String parentId) { public List<SysDepartTreeModel> queryTreeListByPid(String parentId,String ids) {
List<SysDepart> list = this.baseMapper.queryTreeListByPid(parentId); Consumer<LambdaQueryWrapper<SysDepart>> square = i -> {
if (oConvertUtils.isNotEmpty(ids)) {
i.in(SysDepart::getId, ids.split(","));
} else {
if(oConvertUtils.isEmpty(parentId)){
i.and(q->q.isNull(true,SysDepart::getParentId).or().eq(true,SysDepart::getParentId,""));
}else{
i.eq(true,SysDepart::getParentId,parentId);
}
}
};
LambdaQueryWrapper<SysDepart> lqw=new LambdaQueryWrapper();
lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0);
lqw.func(square);
lqw.orderByDesc(SysDepart::getDepartOrder);
List<SysDepart> list = list(lqw);
List<SysDepartTreeModel> records = new ArrayList<>(); List<SysDepartTreeModel> records = new ArrayList<>();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
SysDepart depart = list.get(i); SysDepart depart = list.get(i);

View File

@ -9,6 +9,7 @@ import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.base.BaseMap; import org.jeecg.common.base.BaseMap;
import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.GlobalConstants; import org.jeecg.common.constant.GlobalConstants;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.entity.SysGatewayRoute; import org.jeecg.modules.system.entity.SysGatewayRoute;
import org.jeecg.modules.system.mapper.SysGatewayRouteMapper; import org.jeecg.modules.system.mapper.SysGatewayRouteMapper;
import org.jeecg.modules.system.service.ISysGatewayRouteService; import org.jeecg.modules.system.service.ISysGatewayRouteService;
@ -17,7 +18,9 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @Description: gateway * @Description: gateway
@ -42,7 +45,7 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
@Override @Override
public void deleteById(String id) { public void deleteById(String id) {
this.removeById(id); this.removeById(id);
this.resreshRouter(); this.resreshRouter(id);
} }
@Override @Override
@ -52,7 +55,14 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
try { try {
json = json.getJSONObject("router"); json = json.getJSONObject("router");
String id = json.getString("id"); String id = json.getString("id");
SysGatewayRoute route = getById(id); //update-begin-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
SysGatewayRoute route;
if(oConvertUtils.isEmpty(id)){
route = new SysGatewayRoute();
}else{
route = getById(id);
}
//update-end-author:taoyan date:20211025 for: oracle路由网关新增小bug /issues/I4EV2J
if (ObjectUtil.isEmpty(route)) { if (ObjectUtil.isEmpty(route)) {
route = new SysGatewayRoute(); route = new SysGatewayRoute();
} }
@ -71,10 +81,10 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
route.setStatus(json.getInteger("status")); route.setStatus(json.getInteger("status"));
} }
this.saveOrUpdate(route); this.saveOrUpdate(route);
resreshRouter(); resreshRouter(null);
} catch (Exception e) { } catch (Exception e) {
log.error("路由配置解析失败", e); log.error("路由配置解析失败", e);
resreshRouter(); resreshRouter(null);
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -82,11 +92,12 @@ public class SysGatewayRouteServiceImpl extends ServiceImpl<SysGatewayRouteMappe
/** /**
* redis * redis
*/ */
private void resreshRouter() { private void resreshRouter(String id) {
//更新redis路由缓存 //更新redis路由缓存
addRoute2Redis(CacheConstant.GATEWAY_ROUTES); addRoute2Redis(CacheConstant.GATEWAY_ROUTES);
BaseMap params = new BaseMap(); BaseMap params = new BaseMap();
params.put(GlobalConstants.HANDLER_NAME, "loderRouderHandler"); params.put(GlobalConstants.HANDLER_NAME, "loderRouderHandler");
params.put("routerId", id);
//刷新网关 //刷新网关
redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params); redisTemplate.convertAndSend(GlobalConstants.REDIS_TOPIC_NAME, params);
} }

View File

@ -1,52 +0,0 @@
package org.jeecg.modules.system.service.impl.desform;
import org.jeecg.common.api.desform.ISysTranslateAPI;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.modules.system.service.ISysCategoryService;
import org.jeecg.modules.system.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* APIsystem
*
* @author sunjianlei
*/
@Component
public class SysTranslateAPIImpl implements ISysTranslateAPI {
@Autowired
ISysCategoryService sysCategoryService;
@Autowired
ISysDictService sysDictService;
@Override
public List<String> categoryLoadDictItem(String ids) {
return sysCategoryService.loadDictItem(ids, false);
}
@Override
public List<String> dictLoadDictItem(String dictCode, String keys) {
String[] params = dictCode.split(",");
return sysDictService.queryTableDictByKeys(params[0], params[1], params[2], keys, false);
}
@Override
public List<DictModel> dictGetDictItems(String dictCode) {
List<DictModel> ls = sysDictService.getDictItems(dictCode);
if (ls == null) {
ls = new ArrayList<>();
}
return ls;
}
@Override
public List<DictModel> dictLoadDict(String dictCode, String keyword, Integer pageSize) {
return sysDictService.loadDict(dictCode, keyword, pageSize);
}
}

View File

@ -1,25 +0,0 @@
//package org.jeecg.modules.system.util;
//
//import lombok.extern.slf4j.Slf4j;
//
///**
// * 多租户 tenant_id存储器
// */
//@Slf4j
//public class TenantContext {
//
// private static ThreadLocal<String> currentTenant = new ThreadLocal<>();
//
// public static void setTenant(String tenant) {
// log.debug(" setting tenant to " + tenant);
// currentTenant.set(tenant);
// }
//
// public static String getTenant() {
// return currentTenant.get();
// }
//
// public static void clear(){
// currentTenant.remove();
// }
//}

View File

@ -1,60 +0,0 @@
package org.jeecg.modules.system.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.jeecg.common.aspect.annotation.Dict;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
*
* @Author: chenli
* @Date: 2020-06-07
* @Version: V1.0
*/
@Data
public class SysOnlineVO {
/**
* id
*/
private String id;
/**
*
*/
private String token;
/**
*
*/
private String username;
/**
*
*/
private String realname;
/**
*
*/
private String avatar;
/**
*
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
/**
* 1 2
*/
@Dict(dicCode = "sex")
private Integer sex;
/**
*
*/
private String phone;
}

View File

@ -131,7 +131,7 @@ spring:
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000 connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
datasource: datasource:
master: master:
url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai url: jdbc:mysql://127.0.0.1:3306/jeecg-boot-os-re?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: root username: root
password: root password: root
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
@ -176,6 +176,8 @@ minidao :
#DB类型mysql | postgresql | oracle | sqlserver| other #DB类型mysql | postgresql | oracle | sqlserver| other
db-type: mysql db-type: mysql
jeecg : jeecg :
# 是否启用安全模式
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改) # 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 本地local\Miniominio\阿里云alioss # 本地local\Miniominio\阿里云alioss

View File

@ -174,6 +174,8 @@ mybatis-plus:
minidao : minidao :
base-package: org.jeecg.modules.jmreport.* base-package: org.jeecg.modules.jmreport.*
jeecg : jeecg :
# 是否启用安全模式
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改) # 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 本地local\Miniominio\阿里云alioss # 本地local\Miniominio\阿里云alioss

View File

@ -174,6 +174,8 @@ mybatis-plus:
minidao : minidao :
base-package: org.jeecg.modules.jmreport.* base-package: org.jeecg.modules.jmreport.*
jeecg : jeecg :
# 是否启用安全模式
safeMode: false
# 签名密钥串(前后端要一致,正式发布请自行修改) # 签名密钥串(前后端要一致,正式发布请自行修改)
signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a signatureSecret: dd05f1c54d63749eda95f9fa6d49v442a
# 本地local\Miniominio\阿里云alioss # 本地local\Miniominio\阿里云alioss

View File

@ -9,6 +9,6 @@ ${AnsiColor.BRIGHT_BLUE}
${AnsiColor.BRIGHT_GREEN} ${AnsiColor.BRIGHT_GREEN}
Jeecg Boot Version: 2.4.6 Jeecg Boot Version: 3.0
Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version} Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
${AnsiColor.BLACK} ${AnsiColor.BLACK}

View File

@ -0,0 +1,244 @@
<template>
<div>
<#assign list_need_category=false>
<#assign list_need_pca=false>
<#assign bpm_flag=false>
<#-- 开始循环 -->
<#list columns as po>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
<#assign list_need_category=true>
</#if>
<#if po.classType=='pca'>
<#assign list_need_pca=true>
</#if>
</#list>
<#-- 结束循环 -->
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<ExcelButton :config="excelConfig"></ExcelButton>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
</div>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import ExcelButton from '/@/components/jeecg/ExcelButton.vue'
import {useModal} from '/@/components/Modal';
import ${entityName}Modal from './components/${entityName}Modal.vue'
import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
<#if list_need_category>
import { loadCategoryData } from '/@/api/common/api'
import { getAuthCache, setAuthCache } from '/@/utils/auth';
import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
</#if>
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerModal, {openModal}] = useModal();
//注册table数据
const [registerTable, {reload}] = useTable({
title: '${tableVo.ftlDescription}',
api: list,
rowKey: 'id',
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToTime: [
<#list columns as po>
<#if po.isQuery=='Y'>
<#if po.queryMode!='single'>
<#if po.classType=='date'>
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
<#elseif po.classType=='datetime'>
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
</#if>
</#if>
</#if>
</#list>
],
},
striped: true,
useSearchForm: true,
showTableSetting: true,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
tableSetting: {fullScreen: true},
actionColumn: {
width: 120,
title: '操作',
dataIndex: 'action',
slots: {customRender: 'action'},
fixed: 'right',
},
})
/**
* excel导入导出配置
*/
const excelConfig = {
export: {
name:'${tableVo.ftlDescription}',
url: getExportUrl,
},
import: {
url: getImportUrl,
success: reload,
}
}
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 30,
selectedRowKeys: checkedKeys,
onChange: onSelectChange
}
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, reload);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: checkedKeys.value}, reload);
}
/**
* 成功回调
*/
function handleSuccess() {
reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
<#if list_need_category>
/**
* 初始化字典配置
*/
function initDictConfig(){
<#list columns as po>
<#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
<#if po.classType=='cat_tree' && list_need_category==true>
loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
if (res) {
let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
if(!allDictDate['${po.dictField?default("")}']){
Object.assign(allDictDate,{'${po.dictField?default("")}':res})
}
setAuthCache(DB_DICT_DATA_KEY,allDictDate)
}
})
</#if>
</#if>
</#list>
}
initDictConfig();
</#if>
</script>
<style scoped>
</style>

View File

@ -0,0 +1,61 @@
import {defHttp} from '/@/utils/http/axios';
import {Modal} from 'ant-design-vue';
enum Api {
list = '/${entityPackage}/${entityName?uncap_first}/list',
save='/${entityPackage}/${entityName?uncap_first}/add',
edit='/${entityPackage}/${entityName?uncap_first}/edit',
deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@ -0,0 +1,352 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
<#list columns as po>
<#if po.isShowList =='Y' && po.fieldName !='id'>
{
title: '${po.filedComment}',
align:"center",
<#if po.sort=='Y'>
sorter: true,
</#if>
<#if po.classType=='date'>
dataIndex: '${po.fieldName}',
customRender:({text}) =>{
return !text?"":(text.length>10?text.substr(0,10):text)
},
<#elseif po.fieldDbType=='Blob'>
dataIndex: '${po.fieldName}String'
<#elseif po.classType=='umeditor'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'htmlSlot' },
<#elseif po.classType=='pca'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'pcaSlot' },//TODO 未翻译
<#elseif po.classType=='file'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'fileSlot' },
<#elseif po.classType=='image'>
dataIndex: '${po.fieldName}',
customRender:render.renderAvatar,
<#elseif po.classType=='switch'>
dataIndex: '${po.fieldName}',
<#assign switch_extend_arr=['Y','N']>
<#if po.dictField?default("")?contains("[")>
<#assign switch_extend_arr=po.dictField?eval>
</#if>
<#list switch_extend_arr as a>
<#if a_index == 0>
<#assign switch_extend_arr1=a>
<#else>
<#assign switch_extend_arr2=a>
</#if>
</#list>
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
},
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
dataIndex: '${po.fieldName}_dictText'
<#elseif po.classType=='cat_tree'>
dataIndex: '${po.fieldName}',
<#if po.dictText?default("")?trim?length == 0>
customRender:({text}) => {
return render.renderCategoryTree(text,'${po.dictField?default("")}')
},
<#else>
customRender: (text, record) => (text ? record['${po.dictText}'] : '')
</#if>
<#else>
dataIndex: '${po.fieldName}'
</#if>
},
</#if>
</#list>
];
//查询数据
export const searchFormSchema: FormSchema[] = [
<#-- 开始循环 -->
<#list columns as po>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isQuery=='Y'>
<#assign query_flag=true>
<#assign query_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictField}">
</#if>
<#if po.queryMode=='single'>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${po.dictTable},${po.dictText},${po.dictField}"
},
<#elseif po.classType=='sel_user'>
component: 'JSelectUserByDept',
<#elseif po.classType=='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:"${po.dictField}"
</#if>
},
<#elseif po.classType=='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType=='list_multi'>
component: 'JMultiSelectTag',//暂无该组件
componentProps:{
dictCode:"query_field_dictCode?default("")"
},
<#elseif po.classType=='cat_tree'>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}",//back和事件未添加暂时有问题
},
<#elseif po.classType=='date'>
component: 'DatePicker',
<#elseif po.classType=='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.classType=='pca'>
component: 'JAreaLinkage',
<#elseif po.classType=='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:"${po.dictField}",
multi:${po.extendParams.popupMulti?c},
}
},
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
component: 'JDictSelectTag',
componentProps:{
<#if po.dictTable?default("")?trim?length gt 1>
dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
<#elseif po.dictField?default("")?trim?length gt 1>
dictCode:"${po.dictField}"
</#if>
},
<#else>
component: 'Input',
</#if>
<#else>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='date'>
component: 'RangePicker',
<#elseif po.classType=='datetime'>
component: 'RangePicker',
componentProps: {
showTime:true
},
<#else>
component: 'Input', //TODO 范围查询
</#if>
colProps: {span: 6},
},
</#if>
</#if>
</#list>
<#-- 结束循环 -->
];
//表单数据
export const formSchema: FormSchema[] = [
<#assign form_cat_tree = false>
<#assign form_cat_back = "">
<#assign bpm_flag=false>
<#list columns as po><#rt/>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isShow =='Y'>
<#assign form_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictField}">
</#if>
{
label: '${po.filedComment}',
field: '${po.fieldName}',
<#if po.classType =='date'>
component: 'DatePicker',
<#elseif po.fieldType =='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.fieldType =='time'>
component: 'TimePicker',
<#elseif po.classType =='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:${po.dictField},
multi:${po.extendParams.popupMulti?c},
}
}
<#elseif po.classType =='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType =='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:${po.dictField}
</#if>
}
<#elseif po.classType =='pca'>
component: 'JAreaLinkage',
<#elseif po.classType =='markdown'>
component: 'JMarkdownEditor',//注意string转换问题
<#elseif po.classType =='password'>
component: 'InputPassword',
<#elseif po.classType =='sel_user'>
component: 'JSelectUserByDept',
componentProps:{
labelKey:'realname',
}
<#elseif po.classType =='textarea'>
component: 'InputTextArea',//TODO 注意string转换问题
<#elseif po.classType=='list' || po.classType=='radio'>
component: 'JDictSelectTag',
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='list_multi' || po.classType=='checkbox'>
component: 'JMultiSelectTag',//TODO 暂无该组件
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${form_field_dictCode}"
}
<#elseif po.classType=='cat_tree'>
<#assign form_cat_tree = true>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}", //TODO back和事件未添加暂时有问题
}
<#if po.dictText?default("")?trim?length gt 1>
<#assign form_cat_back = "${po.dictText}">
</#if>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
component: 'InputNumber',
<#elseif po.classType=='file'>
component: 'JUpload',
componentProps:{
<#if po.uploadnum??>
maxCount:${po.uploadnum}
</#if>
}
<#elseif po.classType=='image'>
component: 'JImageUpload',
componentProps:{
<#if po.uploadnum??>
fileMax:${po.uploadnum}
</#if>
}
<#elseif po.classType=='umeditor'>
component: 'JCodeEditor', //TODO String后缀暂未添加
<#elseif po.classType == 'sel_tree'>
component: 'JTreeSelect',
componentProps:{
<#if po.dictText??>
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
<#elseif po.dictText?split(',')[1]??>
pidField:"${po.dictText?split(',')[1]}",
<#elseif po.dictText?split(',')[3]??>
hasChildField:"${po.dictText?split(',')[3]}",
</#if>
</#if>
pidValue:"${po.dictField}",
}
<#else>
component: 'Input',
</#if>
<#include "/common/utils.ftl">
<#if po.isShow == 'Y' && poHasCheck(po)>
dynamicRules: ({model,schema}) => {
<#if po.fieldName != 'id'>
<#assign fieldValidType = po.fieldValidType!''>
return [
<#-- 非空校验 -->
<#if po.nullable == 'N' || fieldValidType == '*'>
{ required: true, message: '请输入${po.filedComment}!'},
<#elseif fieldValidType!=''>
{ required: false},
</#if>
<#-- 唯一校验 -->
<#if fieldValidType == 'only'>
{...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
<#-- 6到16位数字 -->
<#elseif fieldValidType == 'n6-16'>
{ pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
<#-- 6到16位任意字符 -->
<#elseif fieldValidType == '*6-16'>
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
<#-- 6到18位字符串 -->
<#elseif fieldValidType == 's6-18'>
{ pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
<#-- 网址 -->
<#elseif fieldValidType == 'url'>
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
<#-- 电子邮件 -->
<#elseif fieldValidType == 'e'>
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
<#-- 手机号码 -->
<#elseif fieldValidType == 'm'>
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
<#-- 邮政编码 -->
<#elseif fieldValidType == 'p'>
{ pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
<#-- 字母 -->
<#elseif fieldValidType == 's'>
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
<#-- 数字 -->
<#elseif fieldValidType == 'n'>
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
<#-- 整数 -->
<#elseif fieldValidType == 'z'>
{ pattern: /^-?\d+$/, message: '请输入整数!'},
<#-- 金额 -->
<#elseif fieldValidType == 'money'>
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
<#-- 正则校验 -->
<#elseif fieldValidType != '' && fieldValidType != '*'>
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
<#-- 无校验 -->
<#else>
<#t>
</#if>
];
</#if>
},
</#if>
<#if po.readonly=='Y'>
dynamicDisabled:true
</#if>
},
</#if>
</#list>
];

View File

@ -0,0 +1,58 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../${entityName?uncap_first}.data';
import {saveOrUpdate} from '../${entityName?uncap_first}.api';
// Emits声明
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
//表单配置
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await resetFields();
setModalProps({confirmLoading: false,showFooter:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter })
});
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
//表单提交事件
async function handleSubmit(v) {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -266,6 +266,34 @@
<#if col.readonly=='Y'> <#if col.readonly=='Y'>
disabled:true, disabled:true,
</#if> </#if>
<#elseif col.classType =='sel_depart'>
type: FormTypes.sel_depart,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='sel_user'>
type: FormTypes.sel_user,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled: true,
</#if>
<#elseif col.classType =='image'> <#elseif col.classType =='image'>
type: FormTypes.image, type: FormTypes.image,
token:true, token:true,

View File

@ -0,0 +1,82 @@
import {defHttp} from "/@/utils/http/axios";
import {Modal} from 'ant-design-vue';
enum Api {
list = '/${entityPackage}/${entityName?uncap_first}/rootList',
save='/${entityPackage}/${entityName?uncap_first}/add',
edit='/${entityPackage}/${entityName?uncap_first}/edit',
delete${entityName} = '/sys/${entityName?uncap_first}/delete',
deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
loadTreeData = '/${entityPackage}/${entityName?uncap_first}/loadTreeRoot',
getChildList = '/${entityPackage}/${entityName?uncap_first}/childList',
getChildListBatch = '/${entityPackage}/${entityName?uncap_first}/getChildListBatch',
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
* @param params
*/
export const getImportUrl = Api.importExcel;
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除
*/
export const delete${entityName} = (params,handleSuccess) => {
return defHttp.delete({url: Api.delete${entityName}, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete${entityName} = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdateDict = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}
/**
* 查询全部树形节点数据
* @param params
*/
export const loadTreeData = (params) =>
defHttp.get({url: Api.loadTreeData,params});
/**
* 查询子节点数据
* @param params
*/
export const getChildList = (params) =>
defHttp.get({url: Api.getChildList, params});
/**
* 批量查询子节点数据
* @param params
*/
export const getChildListBatch = (params) =>
defHttp.get({url: Api.getChildListBatch, params},{isTransformResponse:false});

View File

@ -0,0 +1,352 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
//列表数据
export const columns: BasicColumn[] = [
<#list columns as po>
<#if po.isShowList =='Y' && po.fieldName !='id'>
{
title: '${po.filedComment}',
align:"center",
<#if po.sort=='Y'>
sorter: true,
</#if>
<#if po.classType=='date'>
dataIndex: '${po.fieldName}',
customRender:({text}) =>{
return !text?"":(text.length>10?text.substr(0,10):text)
},
<#elseif po.fieldDbType=='Blob'>
dataIndex: '${po.fieldName}String'
<#elseif po.classType=='umeditor'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'htmlSlot' },
<#elseif po.classType=='pca'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'pcaSlot' },//TODO 未翻译
<#elseif po.classType=='file'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'fileSlot' },
<#elseif po.classType=='image'>
dataIndex: '${po.fieldName}',
customRender:render.renderAvatar,
<#elseif po.classType=='switch'>
dataIndex: '${po.fieldName}',
<#assign switch_extend_arr=['Y','N']>
<#if po.dictField?default("")?contains("[")>
<#assign switch_extend_arr=po.dictField?eval>
</#if>
<#list switch_extend_arr as a>
<#if a_index == 0>
<#assign switch_extend_arr1=a>
<#else>
<#assign switch_extend_arr2=a>
</#if>
</#list>
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
},
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
dataIndex: '${po.fieldName}_dictText'
<#elseif po.classType=='cat_tree'>
dataIndex: '${po.fieldName}',
<#if po.dictText?default("")?trim?length == 0>
customRender:({text}) => {
return render.renderCategoryTree(text,'${po.dictField?default("")}')
},
<#else>
customRender: (text, record) => (text ? record['${po.dictText}'] : '')
</#if>
<#else>
dataIndex: '${po.fieldName}'
</#if>
},
</#if>
</#list>
];
//查询数据
export const searchFormSchema: FormSchema[] = [
<#-- 开始循环 -->
<#list columns as po>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isQuery=='Y'>
<#assign query_flag=true>
<#assign query_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictField}">
</#if>
<#if po.queryMode=='single'>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${po.dictTable},${po.dictText},${po.dictField}"
},
<#elseif po.classType=='sel_user'>
component: 'JSelectUserByDept',
<#elseif po.classType=='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:"${po.dictField}"
</#if>
},
<#elseif po.classType=='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType=='list_multi'>
component: 'JMultiSelectTag',//暂无该组件
componentProps:{
dictCode:"query_field_dictCode?default("")"
},
<#elseif po.classType=='cat_tree'>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}",//back和事件未添加暂时有问题
},
<#elseif po.classType=='date'>
component: 'DatePicker',
<#elseif po.classType=='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.classType=='pca'>
component: 'JAreaLinkage',
<#elseif po.classType=='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:"${po.dictField}",
multi:${po.extendParams.popupMulti?c},
}
},
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
component: 'JDictSelectTag',
componentProps:{
<#if po.dictTable?default("")?trim?length gt 1>
dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
<#elseif po.dictField?default("")?trim?length gt 1>
dictCode:"${po.dictField}"
</#if>
},
<#else>
component: 'Input',
</#if>
<#else>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='date'>
component: 'RangePicker',
<#elseif po.classType=='datetime'>
component: 'RangePicker',
componentProps: {
showTime:true
},
<#else>
component: 'Input', //TODO 范围查询
</#if>
colProps: {span: 6},
},
</#if>
</#if>
</#list>
<#-- 结束循环 -->
];
//表单数据
export const formSchema: FormSchema[] = [
<#assign form_cat_tree = false>
<#assign form_cat_back = "">
<#assign bpm_flag=false>
<#list columns as po><#rt/>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isShow =='Y'>
<#assign form_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictField}">
</#if>
{
label: '${po.filedComment}',
field: '${po.fieldName}',
<#if po.classType =='date'>
component: 'DatePicker',
<#elseif po.fieldType =='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.fieldType =='time'>
component: 'TimePicker',
<#elseif po.classType =='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:${po.dictField},
multi:${po.extendParams.popupMulti?c},
}
}
<#elseif po.classType =='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType =='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:${po.dictField}
</#if>
}
<#elseif po.classType =='pca'>
component: 'JAreaLinkage',
<#elseif po.classType =='markdown'>
component: 'JMarkdownEditor',//注意string转换问题
<#elseif po.classType =='password'>
component: 'InputPassword',
<#elseif po.classType =='sel_user'>
component: 'JSelectUserByDept',
componentProps:{
labelKey:'realname',
}
<#elseif po.classType =='textarea'>
component: 'InputTextArea',//TODO 注意string转换问题
<#elseif po.classType=='list' || po.classType=='radio'>
component: 'JDictSelectTag',
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='list_multi' || po.classType=='checkbox'>
component: 'JMultiSelectTag',//TODO 暂无该组件
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${form_field_dictCode}"
}
<#elseif po.classType=='cat_tree'>
<#assign form_cat_tree = true>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}", //TODO back和事件未添加暂时有问题
}
<#if po.dictText?default("")?trim?length gt 1>
<#assign form_cat_back = "${po.dictText}">
</#if>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
component: 'InputNumber',
<#elseif po.classType=='file'>
component: 'JUpload',
componentProps:{
<#if po.uploadnum??>
maxCount:${po.uploadnum}
</#if>
}
<#elseif po.classType=='image'>
component: 'JImageUpload',
componentProps:{
<#if po.uploadnum??>
fileMax:${po.uploadnum}
</#if>
}
<#elseif po.classType=='umeditor'>
component: 'JCodeEditor', //TODO String后缀暂未添加
<#elseif po.classType == 'sel_tree'>
component: 'JTreeSelect',
componentProps:{
<#if po.dictText??>
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
<#elseif po.dictText?split(',')[1]??>
pidField:"${po.dictText?split(',')[1]}",
<#elseif po.dictText?split(',')[3]??>
hasChildField:"${po.dictText?split(',')[3]}",
</#if>
</#if>
pidValue:"${po.dictField}",
}
<#else>
component: 'Input',
</#if>
<#include "/common/utils.ftl">
<#if po.isShow == 'Y' && poHasCheck(po)>
dynamicRules: ({model,schema}) => {
<#if po.fieldName != 'id'>
<#assign fieldValidType = po.fieldValidType!''>
return [
<#-- 非空校验 -->
<#if po.nullable == 'N' || fieldValidType == '*'>
{ required: true, message: '请输入${po.filedComment}!'},
<#elseif fieldValidType!=''>
{ required: false},
</#if>
<#-- 唯一校验 -->
<#if fieldValidType == 'only'>
{...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
<#-- 6到16位数字 -->
<#elseif fieldValidType == 'n6-16'>
{ pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
<#-- 6到16位任意字符 -->
<#elseif fieldValidType == '*6-16'>
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
<#-- 6到18位字符串 -->
<#elseif fieldValidType == 's6-18'>
{ pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
<#-- 网址 -->
<#elseif fieldValidType == 'url'>
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
<#-- 电子邮件 -->
<#elseif fieldValidType == 'e'>
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
<#-- 手机号码 -->
<#elseif fieldValidType == 'm'>
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
<#-- 邮政编码 -->
<#elseif fieldValidType == 'p'>
{ pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
<#-- 字母 -->
<#elseif fieldValidType == 's'>
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
<#-- 数字 -->
<#elseif fieldValidType == 'n'>
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
<#-- 整数 -->
<#elseif fieldValidType == 'z'>
{ pattern: /^-?\d+$/, message: '请输入整数!'},
<#-- 金额 -->
<#elseif fieldValidType == 'money'>
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
<#-- 正则校验 -->
<#elseif fieldValidType != '' && fieldValidType != '*'>
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
<#-- 无校验 -->
<#else>
<#t>
</#if>
];
</#if>
},
</#if>
<#if po.readonly=='Y'>
dynamicDisabled:true
</#if>
},
</#if>
</#list>
];

View File

@ -0,0 +1,87 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
<BasicForm @register="registerForm"/>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicModal, useModalInner} from '/src/components/Modal';
import {BasicForm, useForm} from '/src/components/Form';
import {formSchema} from '../${entityName?uncap_first}.data';
import {loadTreeData, saveOrUpdateDict} from '../${entityName?uncap_first}.api';
// 获取emit
const emit = defineEmits(['register', 'success']);
const isUpdate = ref(true);
const expandedRowKeys = ref([]);
const treeData = ref([]);
//表单配置
const [registerForm, {resetFields, setFieldsValue, validate, updateSchema}] = useForm({
schemas: formSchema,
showActionButtonGroup: false,
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 18 },
},
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await resetFields();
expandedRowKeys.value = [];
setModalProps({confirmLoading: false, minHeight: 80});
isUpdate.value = !!data?.isUpdate;
if (data?.record) {
//表单赋值
await setFieldsValue({
...data.record,
});
}
//父级节点树信息
treeData.value = await loadTreeData({'async': false,'pcode':''});
updateSchema({
field: 'pid',
componentProps: {treeData},
});
});
//设置标题
const getTitle = computed(() => (!unref(isUpdate) ? '新增字典' : '编辑字典'));
/**
* 根据pid获取展开的节点
* @param pid
* @param arr
*/
function getExpandKeysByPid(pid,arr){
if(pid && arr && arr.length>0){
for(let i=0;i<arr.length;i++){
if(arr[i].key==pid && unref(expandedRowKeys).indexOf(pid)<0){
expandedRowKeys.value.push(arr[i].key);
getExpandKeysByPid(arr[i]['parentId'],unref(treeData))
}else{
getExpandKeysByPid(pid,arr[i].children)
}
}
}
}
//表单提交事件
async function handleSubmit() {
try {
let values = await validate();
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdateDict(values, isUpdate.value);
//关闭弹窗
closeModal();
//展开的节点信息
await getExpandKeysByPid(values['pid'],unref(treeData))
//刷新列表(isUpdate:是否编辑;values:表单信息;expandedArr:展开的节点信息)
emit('success', {isUpdate: unref(isUpdate), values:{...values},expandedArr: unref(expandedRowKeys).reverse()});
} finally {
setModalProps({confirmLoading: false});
}
}
</script>

View File

@ -0,0 +1,295 @@
<template>
<div class="p-4">
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys" @expand="handleExpand" @fetch-success="onFetchSuccess">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:plus-outlined" @click="handleCreate"> 新增</a-button>
<a-upload name="file" :showUploadList="false" :customRequest="(file)=>handleImportXls(file,getImportUrl,importSuccess)">
<a-button type="primary" preIcon="ant-design:import-outlined">导入</a-button>
</a-upload>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="handleExportXls('${tableVo.ftlDescription}管理',getExportUrl)"> 导出</a-button>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="ant-design:down-outlined"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)"/>
</template>
</BasicTable>
<!--字典弹窗-->
<${entityName}Modal @register="registerModal" @success="handleSuccess"/>
</div>
</template>
<script lang="ts" setup>
//ts语法
import {ref, computed, unref, toRaw, nextTick} from 'vue';
import {BasicTable, useTable, TableAction} from '/src/components/Table';
import {useDrawer} from '/src/components/Drawer';
import ${entityName}Modal from './components/${entityName}Modal.vue';
import {useModal} from '/src/components/Modal';
import {useMethods} from '/src/hooks/system/useMethods';
import {columns} from './${entityName}.data';
import {list, delete${entityName}, batchDelete${entityName}, getExportUrl,getImportUrl, getChildList,getChildListBatch} from './${entityName}.api';
const checkedKeys = ref<Array<string | number>>([]);
const expandedRowKeys = ref([]);
const {handleExportXls,handleImportXls} = useMethods();
//字典model
const [registerModal, {openModal}] = useModal();
//注册table数据
const [registerTable, {reload, collapseAll, updateTableDataRecord, findTableDataRecord,getDataSource}] = useTable({
api: list,
rowKey: 'id',
columns,
striped: true,
useSearchForm: false,
showTableSetting: true,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
tableSetting: {fullScreen: true},
canResize: false,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
slots: {customRender: 'action'},
fixed: undefined,
},
})
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 10,
selectedRowKeys: checkedKeys,
onChange: onSelectChange
}
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
/**
* 新增事件
*/
function handleCreate() {
openModal(true, {
isUpdate: false,
});
}
/**
* 编辑事件
*/
async function handleEdit(record) {
openModal(true, {
record,
isUpdate: true,
});
}
/**
* 详情
*/
async function handleDetail(record) {
openModal(true, {
record,
isUpdate: true,
hideFooter: true,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await delete${entityName}({id: record.id}, importSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
const ids = checkedKeys.value.filter(item => !item.includes('loading'))
await batchDelete${entityName}({ids: ids}, importSuccess);
}
/**
* 导入
*/
function importSuccess() {
reload() && (expandedRowKeys.value = []);
}
/**
* 添加下级
*/
function handleAddSub(record) {
openModal(true, {
record,
isUpdate: false,
});
}
/**
* 成功回调
*/
async function handleSuccess({isUpdate, values, expandedArr}) {
if (isUpdate) {
//编辑回调
updateTableDataRecord(values.id, values);
} else {
if(!values['pid']){
//新增根节点
reload();
}else{
//新增子集
expandedRowKeys.value = [];
for (let key of unref(expandedArr)) {
await expandTreeNode(key)
}
}
}
}
/**
* 接口请求成功后回调
*/
function onFetchSuccess(result) {
getDataByResult(result.items)&&loadDataByExpandedRows();
}
/**
* 根据已展开的行查询数据(用于保存后刷新时异步加载子级的数据)
*/
async function loadDataByExpandedRows() {
if (unref(expandedRowKeys).length > 0) {
const res = await getChildListBatch({ parentIds: unref(expandedRowKeys).join(',')});
if (res.success && res.result.records.length>0) {
//已展开的数据批量子节点
let records = res.result.records
const listMap = new Map();
for (let item of records) {
let pid = item['pid'];
if (unref(expandedRowKeys).includes(pid)) {
let mapList = listMap.get(pid);
if (mapList == null) {
mapList = [];
}
mapList.push(item);
listMap.set(pid, mapList);
}
}
let childrenMap = listMap;
let fn = (list) => {
if(list) {
list.forEach(data => {
if (unref(expandedRowKeys).includes(data.id)) {
data.children = getDataByResult(childrenMap.get(data.id))
fn(data.children)
}
})
}
};
fn(getDataSource())
}
}
}
/**
* 处理数据集
*/
function getDataByResult(result){
if(result && result.length>0){
return result.map(item=>{
//判断是否标记了带有子节点
if(item["hasChild"]=='1'){
let loadChild = { id: item.id+'_loadChild', name: 'loading...', isLoading: true }
item.children = [loadChild]
}
return item
})
}
}
/**
*树节点展开合并
* */
async function handleExpand(expanded, record) {
// 判断是否是展开状态,展开状态(expanded)并且存在子集(children)并且未加载过(isLoading)的就去查询子节点数据
if (expanded) {
expandedRowKeys.value.push(record.id)
if (record.children.length > 0 && !!record.children[0].isLoading) {
let result = await getChildList({pid: record.id});
result=result.records?result.records:result;
if (result && result.length > 0) {
record.children = getDataByResult(result);
} else {
record.children = null
record.hasChild = '0'
}
}
} else {
let keyIndex = expandedRowKeys.value.indexOf(record.id)
if (keyIndex >= 0) {
expandedRowKeys.value.splice(keyIndex, 1);
}
}
}
/**
*操作表格后处理树节点展开合并
* */
async function expandTreeNode(key) {
let record = findTableDataRecord(key)
expandedRowKeys.value.push(key);
let result = await getChildList({pid: key});
if (result && result.length > 0) {
record.children = getDataByResult(result);
} else {
record.children = null
record.hasChild = '0'
}
updateTableDataRecord(key, record);
}
/**
* 操作栏
*/
function getTableAction(record) {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
{
label: '删除',
popConfirm: {
title: '确定删除吗?',
confirm: handleDelete.bind(null, record),
},
},
{
label: '添加下级',
onClick: handleAddSub.bind(null, {pid: record.id}),
}
]
}
</script>
<style scoped>
</style>

View File

@ -255,6 +255,34 @@
<#if col.readonly=='Y'> <#if col.readonly=='Y'>
disabled:true, disabled:true,
</#if> </#if>
<#elseif col.classType =='sel_depart'>
type: FormTypes.sel_depart,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='sel_user'>
type: FormTypes.sel_user,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled: true,
</#if>
<#elseif col.classType =='image'> <#elseif col.classType =='image'>
type: FormTypes.image, type: FormTypes.image,
token:true, token:true,

View File

@ -119,7 +119,7 @@ public class ${entityName}Controller {
*/ */
@AutoLog(value = "${tableVo.ftlDescription}-编辑") @AutoLog(value = "${tableVo.ftlDescription}-编辑")
@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑") @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
@PutMapping(value = "/edit") @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) { public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
${entityName} ${entityName?uncap_first} = new ${entityName}(); ${entityName} ${entityName?uncap_first} = new ${entityName}();
BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first}); BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});

View File

@ -266,6 +266,34 @@
<#if col.readonly=='Y'> <#if col.readonly=='Y'>
disabled:true, disabled:true,
</#if> </#if>
<#elseif col.classType =='sel_depart'>
type: JVXETypes.departSelect,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='sel_user'>
type: JVXETypes.userSelect,
<#if col.extendParams.multiSelect?default(true) == false>
multi: false,
</#if>
<#if col.extendParams.store?default("")?trim?length gt 1>
store: "${col.extendParams.store}",
</#if>
<#if col.extendParams.text?default("")?trim?length gt 1>
text: "${col.extendParams.text}",
</#if>
<#if col.readonly=='Y'>
disabled: true,
</#if>
<#elseif col.classType =='image'> <#elseif col.classType =='image'>
type: JVXETypes.image, type: JVXETypes.image,
token:true, token:true,

View File

@ -0,0 +1,244 @@
<template>
<div>
<#assign list_need_category=false>
<#assign list_need_pca=false>
<#assign bpm_flag=false>
<#-- 开始循环 -->
<#list columns as po>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
<#assign list_need_category=true>
</#if>
<#if po.classType=='pca'>
<#assign list_need_pca=true>
</#if>
</#list>
<#-- 结束循环 -->
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<ExcelButton :config="excelConfig"></ExcelButton>
<a-dropdown v-if="checkedKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button>批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template #htmlSlot="{text}">
<div v-html="text"></div>
</template>
<template #fileSlot="{text}">
<span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
<a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
</template>
</BasicTable>
<!-- 表单区域 -->
<${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
</div>
</template>
<script lang="ts" setup>
import {ref, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import ExcelButton from '/@/components/jeecg/ExcelButton.vue'
import {useModal} from '/@/components/Modal';
import ${entityName}Modal from './components/${entityName}Modal.vue'
import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
<#if list_need_category>
import { loadCategoryData } from '/@/api/common/api'
import { getAuthCache, setAuthCache } from '/@/utils/auth';
import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
</#if>
const checkedKeys = ref<Array<string | number>>([]);
//注册model
const [registerModal, {openModal}] = useModal();
//注册table数据
const [registerTable, {reload}] = useTable({
title: '${tableVo.ftlDescription}',
api: list,
rowKey: 'id',
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToTime: [
<#list columns as po>
<#if po.isQuery=='Y'>
<#if po.queryMode!='single'>
<#if po.classType=='date'>
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
<#elseif po.classType=='datetime'>
['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
</#if>
</#if>
</#if>
</#list>
],
},
striped: true,
useSearchForm: true,
showTableSetting: true,
clickToRowSelect: false,
bordered: true,
showIndexColumn: false,
tableSetting: {fullScreen: true},
actionColumn: {
width: 120,
title: '操作',
dataIndex: 'action',
slots: {customRender: 'action'},
fixed: 'right',
},
})
/**
* excel导入导出配置
*/
const excelConfig = {
export: {
name:'${tableVo.ftlDescription}',
url: getExportUrl,
},
import: {
url: getImportUrl,
success: reload,
}
}
/**
* 选择列配置
*/
const rowSelection = {
type: 'checkbox',
columnWidth: 30,
selectedRowKeys: checkedKeys,
onChange: onSelectChange
}
/**
* 选择事件
*/
function onSelectChange(selectedRowKeys: (string | number)[]) {
checkedKeys.value = selectedRowKeys;
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, reload);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: checkedKeys.value}, reload);
}
/**
* 成功回调
*/
function handleSuccess() {
reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
}
}
]
}
<#if list_need_category>
/**
* 初始化字典配置
*/
function initDictConfig(){
<#list columns as po>
<#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
<#if po.classType=='cat_tree' && list_need_category==true>
loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
if (res) {
let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
if(!allDictDate['${po.dictField?default("")}']){
Object.assign(allDictDate,{'${po.dictField?default("")}':res})
}
setAuthCache(DB_DICT_DATA_KEY,allDictDate)
}
})
</#if>
</#if>
</#list>
}
initDictConfig();
</#if>
</script>
<style scoped>
</style>

View File

@ -0,0 +1,72 @@
import {defHttp} from '/@/utils/http/axios';
import {Modal} from 'ant-design-vue';
enum Api {
list = '/${entityPackage}/${entityName?uncap_first}/list',
save='/${entityPackage}/${entityName?uncap_first}/add',
edit='/${entityPackage}/${entityName?uncap_first}/edit',
deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
<#list subTables as sub><#rt/>
${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId',
</#list>
}
/**
* 导出api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* 导入api
*/
export const getImportUrl = Api.importExcel;
<#list subTables as sub><#rt/>
/**
* 查询子表数据
* @param params
*/
export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List;
</#list>
/**
* 列表接口
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
* 删除单个
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
* 批量删除
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
Modal.confirm({
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
* 保存或者更新
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

View File

@ -0,0 +1,698 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
//列表数据
export const columns: BasicColumn[] = [
<#list columns as po>
<#if po.isShowList =='Y' && po.fieldName !='id'>
{
title: '${po.filedComment}',
align:"center",
<#if po.sort=='Y'>
sorter: true,
</#if>
<#if po.classType=='date'>
dataIndex: '${po.fieldName}',
customRender:({text}) =>{
return !text?"":(text.length>10?text.substr(0,10):text)
},
<#elseif po.fieldDbType=='Blob'>
dataIndex: '${po.fieldName}String'
<#elseif po.classType=='umeditor'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'htmlSlot' },
<#elseif po.classType=='pca'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'pcaSlot' },//TODO 未翻译
<#elseif po.classType=='file'>
dataIndex: '${po.fieldName}',
slots: { customRender: 'fileSlot' },
<#elseif po.classType=='image'>
dataIndex: '${po.fieldName}',
customRender:render.renderAvatar,
<#elseif po.classType=='switch'>
dataIndex: '${po.fieldName}',
<#assign switch_extend_arr=['Y','N']>
<#if po.dictField?default("")?contains("[")>
<#assign switch_extend_arr=po.dictField?eval>
</#if>
<#list switch_extend_arr as a>
<#if a_index == 0>
<#assign switch_extend_arr1=a>
<#else>
<#assign switch_extend_arr2=a>
</#if>
</#list>
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
},
<#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
dataIndex: '${po.fieldName}_dictText'
<#elseif po.classType=='cat_tree'>
dataIndex: '${po.fieldName}',
<#if po.dictText?default("")?trim?length == 0>
customRender:({text}) => {
return render.renderCategoryTree(text,'${po.dictField?default("")}')
},
<#else>
customRender: (text, record) => (text ? record['${po.dictText}'] : '')
</#if>
<#else>
dataIndex: '${po.fieldName}'
</#if>
},
</#if>
</#list>
];
//查询数据
export const searchFormSchema: FormSchema[] = [
<#-- 开始循环 -->
<#list columns as po>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isQuery=='Y'>
<#assign query_flag=true>
<#assign query_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign query_field_dictCode="${po.dictField}">
</#if>
<#if po.queryMode=='single'>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${po.dictTable},${po.dictText},${po.dictField}"
},
<#elseif po.classType=='sel_user'>
component: 'JSelectUserByDept',
<#elseif po.classType=='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:"${po.dictField}"
</#if>
},
<#elseif po.classType=='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType=='list_multi'>
component: 'JMultiSelectTag',//暂无该组件
componentProps:{
dictCode:"query_field_dictCode?default("")"
},
<#elseif po.classType=='cat_tree'>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}",//back和事件未添加暂时有问题
},
<#elseif po.classType=='date'>
component: 'DatePicker',
<#elseif po.classType=='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.classType=='pca'>
component: 'JAreaLinkage',
<#elseif po.classType=='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:"${po.dictField}",
multi:${po.extendParams.popupMulti?c},
}
},
<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
<#-- ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
component: 'JDictSelectTag',
componentProps:{
<#if po.dictTable?default("")?trim?length gt 1>
dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
<#elseif po.dictField?default("")?trim?length gt 1>
dictCode:"${po.dictField}"
</#if>
},
<#else>
component: 'Input',
</#if>
<#else>
{
label: "${po.filedComment}",
field: "${po.fieldName}",
<#if po.classType=='date'>
component: 'RangePicker',
<#elseif po.classType=='datetime'>
component: 'RangePicker',
componentProps: {
showTime:true
},
<#else>
component: 'Input', //TODO 范围查询
</#if>
colProps: {span: 6},
},
</#if>
</#if>
</#list>
<#-- 结束循环 -->
];
//表单数据
export const formSchema: FormSchema[] = [
<#assign form_cat_tree = false>
<#assign form_cat_back = "">
<#assign bpm_flag=false>
<#list columns as po><#rt/>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isShow =='Y'>
<#assign form_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictField}">
</#if>
{
label: '${po.filedComment}',
field: '${po.fieldName}',
<#if po.classType =='date'>
component: 'DatePicker',
<#elseif po.fieldType =='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.fieldType =='time'>
component: 'TimePicker',
<#elseif po.classType =='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:${po.dictField},
multi:${po.extendParams.popupMulti?c},
}
}
<#elseif po.classType =='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType =='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:${po.dictField}
</#if>
}
<#elseif po.classType =='pca'>
component: 'JAreaLinkage',
<#elseif po.classType =='markdown'>
component: 'JMarkdownEditor',//注意string转换问题
<#elseif po.classType =='password'>
component: 'InputPassword',
<#elseif po.classType =='sel_user'>
component: 'JSelectUserByDept',
componentProps:{
labelKey:'realname',
}
<#elseif po.classType =='textarea'>
component: 'InputTextArea',//TODO 注意string转换问题
<#elseif po.classType=='list' || po.classType=='radio'>
component: 'JDictSelectTag',
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='list_multi' || po.classType=='checkbox'>
component: 'JMultiSelectTag',//TODO 暂无该组件
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${form_field_dictCode}"
}
<#elseif po.classType=='cat_tree'>
<#assign form_cat_tree = true>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}", //TODO back和事件未添加暂时有问题
}
<#if po.dictText?default("")?trim?length gt 1>
<#assign form_cat_back = "${po.dictText}">
</#if>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
component: 'InputNumber',
<#elseif po.classType=='file'>
component: 'JUpload',
componentProps:{
<#if po.uploadnum??>
maxCount:${po.uploadnum}
</#if>
}
<#elseif po.classType=='image'>
component: 'JImageUpload',
componentProps:{
<#if po.uploadnum??>
fileMax:${po.uploadnum}
</#if>
}
<#elseif po.classType=='umeditor'>
component: 'JCodeEditor', //TODO String后缀暂未添加
<#elseif po.classType == 'sel_tree'>
component: 'JTreeSelect',
componentProps:{
<#if po.dictText??>
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
<#elseif po.dictText?split(',')[1]??>
pidField:"${po.dictText?split(',')[1]}",
<#elseif po.dictText?split(',')[3]??>
hasChildField:"${po.dictText?split(',')[3]}",
</#if>
</#if>
pidValue:"${po.dictField}",
}
<#else>
component: 'Input',
</#if>
<#include "/common/utils.ftl">
<#if po.isShow == 'Y' && poHasCheck(po)>
dynamicRules: ({model,schema}) => {
<#if po.fieldName != 'id'>
<#assign fieldValidType = po.fieldValidType!''>
return [
<#-- 非空校验 -->
<#if po.nullable == 'N' || fieldValidType == '*'>
{ required: true, message: '请输入${po.filedComment}!'},
<#elseif fieldValidType!=''>
{ required: false},
</#if>
<#-- 唯一校验 -->
<#if fieldValidType == 'only'>
{...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
<#-- 6到16位数字 -->
<#elseif fieldValidType == 'n6-16'>
{ pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
<#-- 6到16位任意字符 -->
<#elseif fieldValidType == '*6-16'>
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
<#-- 6到18位字符串 -->
<#elseif fieldValidType == 's6-18'>
{ pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
<#-- 网址 -->
<#elseif fieldValidType == 'url'>
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
<#-- 电子邮件 -->
<#elseif fieldValidType == 'e'>
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
<#-- 手机号码 -->
<#elseif fieldValidType == 'm'>
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
<#-- 邮政编码 -->
<#elseif fieldValidType == 'p'>
{ pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
<#-- 字母 -->
<#elseif fieldValidType == 's'>
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
<#-- 数字 -->
<#elseif fieldValidType == 'n'>
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
<#-- 整数 -->
<#elseif fieldValidType == 'z'>
{ pattern: /^-?\d+$/, message: '请输入整数!'},
<#-- 金额 -->
<#elseif fieldValidType == 'money'>
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
<#-- 正则校验 -->
<#elseif fieldValidType != '' && fieldValidType != '*'>
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
<#-- 无校验 -->
<#else>
<#t>
</#if>
];
</#if>
},
</#if>
<#if po.readonly=='Y'>
dynamicDisabled:true
</#if>
},
</#if>
</#list>
];
//子表单数据
<#list subTables as sub>
<#if sub.foreignRelationType =='1'>
export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
<#assign form_cat_tree = false>
<#assign form_cat_back = "">
<#assign bpm_flag=false>
<#list sub.colums as po><#rt/>
<#if po.fieldDbName=='bpm_status'>
<#assign bpm_flag=true>
</#if>
<#if po.isShow =='Y'>
<#assign form_field_dictCode="">
<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
<#elseif po.dictField?default("")?trim?length gt 1>
<#assign form_field_dictCode="${po.dictField}">
</#if>
{
label: '${po.filedComment}',
field: '${po.fieldName}',
<#if po.classType =='date'>
component: 'DatePicker',
<#elseif po.fieldType =='datetime'>
component: 'DatePicker',
componentProps: {
showTime:true
},
<#elseif po.fieldType =='time'>
component: 'TimePicker',
<#elseif po.classType =='popup'>
component: 'JPopup',
componentProps: ({ formActionType }) => {
const {setFieldsValue} = formActionType;
return{
setFieldsValue:setFieldsValue,
code:"${po.dictTable}",
fieldConfig:${po.dictField},
multi:${po.extendParams.popupMulti?c},
}
}
<#elseif po.classType =='sel_depart'>
component: 'JSelectDept',
<#elseif po.classType =='switch'>
component: 'JSwitch',
componentProps:{
<#if po.dictField != 'is_open'>
options:${po.dictField}
</#if>
}
<#elseif po.classType =='pca'>
component: 'JAreaLinkage',
<#elseif po.classType =='markdown'>
component: 'JMarkdownEditor',//注意string转换问题
<#elseif po.classType =='password'>
component: 'InputPassword',
<#elseif po.classType =='sel_user'>
component: 'JSelectUserByDept',
componentProps:{
labelKey:'realname',
}
<#elseif po.classType =='textarea'>
component: 'InputTextArea',//TODO 注意string转换问题
<#elseif po.classType=='list' || po.classType=='radio'>
component: 'JDictSelectTag',
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='list_multi' || po.classType=='checkbox'>
component: 'JMultiSelectTag',//TODO 暂无该组件
componentProps:{
dictCode:"${form_field_dictCode}"
}
<#elseif po.classType=='sel_search'>
component: 'JSearchSelect',
componentProps:{
dict:"${form_field_dictCode}"
}
<#elseif po.classType=='cat_tree'>
<#assign form_cat_tree = true>
component: 'JCategorySelect',
componentProps:{
pcode:"${po.dictField?default("")}", //TODO back和事件未添加暂时有问题
}
<#if po.dictText?default("")?trim?length gt 1>
<#assign form_cat_back = "${po.dictText}">
</#if>
<#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
component: 'InputNumber',
<#elseif po.classType=='file'>
component: 'JUpload',
componentProps:{
<#if po.uploadnum??>
maxCount:${po.uploadnum}
</#if>
}
<#elseif po.classType=='image'>
component: 'JImageUpload',
componentProps:{
<#if po.uploadnum??>
fileMax:${po.uploadnum}
</#if>
}
<#elseif po.classType=='umeditor'>
component: 'JCodeEditor', //TODO String后缀暂未添加
<#elseif po.classType == 'sel_tree'>
component: 'JTreeSelect',
componentProps:{
<#if po.dictText??>
<#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
<#elseif po.dictText?split(',')[1]??>
pidField:"${po.dictText?split(',')[1]}",
<#elseif po.dictText?split(',')[3]??>
hasChildField:"${po.dictText?split(',')[3]}",
</#if>
</#if>
pidValue:"${po.dictField}",
}
<#else>
component: 'Input',
</#if>
<#include "/common/utils.ftl">
<#if po.isShow == 'Y' && poHasCheck(po)>
dynamicRules: ({model,schema}) => {
<#if po.fieldName != 'id'>
<#assign fieldValidType = po.fieldValidType!''>
return [
<#-- 非空校验 -->
<#if po.nullable == 'N' || fieldValidType == '*'>
{ required: true, message: '请输入${po.filedComment}!'},
<#elseif fieldValidType!=''>
{ required: false},
</#if>
<#-- 唯一校验 -->
<#if fieldValidType == 'only'>
{...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
<#-- 6到16位数字 -->
<#elseif fieldValidType == 'n6-16'>
{ pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
<#-- 6到16位任意字符 -->
<#elseif fieldValidType == '*6-16'>
{ pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
<#-- 6到18位字符串 -->
<#elseif fieldValidType == 's6-18'>
{ pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
<#-- 网址 -->
<#elseif fieldValidType == 'url'>
{ pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
<#-- 电子邮件 -->
<#elseif fieldValidType == 'e'>
{ pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
<#-- 手机号码 -->
<#elseif fieldValidType == 'm'>
{ pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
<#-- 邮政编码 -->
<#elseif fieldValidType == 'p'>
{ pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
<#-- 字母 -->
<#elseif fieldValidType == 's'>
{ pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
<#-- 数字 -->
<#elseif fieldValidType == 'n'>
{ pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
<#-- 整数 -->
<#elseif fieldValidType == 'z'>
{ pattern: /^-?\d+$/, message: '请输入整数!'},
<#-- 金额 -->
<#elseif fieldValidType == 'money'>
{ pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
<#-- 正则校验 -->
<#elseif fieldValidType != '' && fieldValidType != '*'>
{ pattern: '${fieldValidType}', message: '不符合校验规则!'},
<#-- 无校验 -->
<#else>
<#t>
</#if>
];
</#if>
},
</#if>
<#if po.readonly=='Y'>
dynamicDisabled:true
</#if>
},
</#if>
</#list>
];
</#if>
</#list>
//子表表格配置
<#list subTables as sub>
<#if sub.foreignRelationType =='0'>
export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [
<#assign popupBackFields = "">
<#-- 循环子表的列 开始 -->
<#list sub.colums as col><#rt/>
<#if col.isShow =='Y'>
<#if col.filedComment !='外键' >
{
title: '${col.filedComment}',
key: '${autoStringSuffixForModel(col)}',
<#if col.classType =='date'>
type: JVxeTypes.date,
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='datetime'>
type: JVxeTypes.datetime,
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='textarea'>
type: JVxeTypes.textarea,
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif "int,decimal,double,"?contains(col.classType)>
type: JVxeTypes.inputNumber,
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='list' || col.classType =='radio'>
type: JVxeTypes.select,
options:[],
<#if col.dictTable?default("")?trim?length gt 1>
dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
<#else>
dictCode:"${col.dictField}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='list_multi' || col.classType =='checkbox'>
type: JVxeTypes.selectMultiple,
options:[],
<#if col.dictTable?default("")?trim?length gt 1>
dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
<#else>
dictCode:"${col.dictField}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='sel_search'>
type: JVxeTypes.selectSearch,
<#if col.dictTable?default("")?trim?length gt 1>
dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
<#else>
dictCode:"${col.dictField}",
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='image'>
type: JVxeTypes.image,
token:true,
responseName:"message",
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#if col.uploadnum??>
number: ${col.uploadnum},
</#if>
<#elseif col.classType =='file'>
type: JVxeTypes.file,
token:true,
responseName:"message",
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#if col.uploadnum??>
number: ${col.uploadnum},
</#if>
<#elseif col.classType =='switch'>
type: JVxeTypes.checkbox,
<#if col.dictField == 'is_open'>
customValue: ['Y', 'N'],
<#else>
customValue: ${col.dictField},
</#if>
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#elseif col.classType =='popup'>
<#if popupBackFields?length gt 0>
<#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}">
<#else>
<#assign popupBackFields = "${col.dictText}">
</#if>
type: JVxeTypes.popup,
popupCode:"${col.dictTable}",
field:"${col.dictField}",
orgFields:"${col.dictField}",
destFields:"${Format.underlineToHump(col.dictText)}",
<#if col.readonly=='Y'>
disabled:true,
</#if>
<#else>
type: JVxeTypes.input,
<#if col.readonly=='Y'>
disabled:true,
</#if>
</#if>
<#if col.classType =='list_multi' || col.classType =='checkbox'>
width:"250px",
<#else>
width:"200px",
</#if>
<#if col.classType =='file'>
placeholder: '请选择文件',
<#else>
placeholder: '请输入${'$'}{title}',
</#if>
<#if col.defaultVal??>
<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int">
defaultValue:${col.defaultVal},
<#else>
defaultValue:"${col.defaultVal}",
</#if>
<#else>
defaultValue:'',
</#if>
<#-- 子表的校验 -->
<#assign subFieldValidType = col.fieldValidType!''>
<#-- 非空校验 -->
<#if col.nullable == 'N' || subFieldValidType == '*'>
validateRules: [{ required: true, message: '${'$'}{title}不能为空' }],
<#-- 其他情况下,只要有值就被认为是正则校验 -->
<#elseif subFieldValidType?length gt 0>
<#assign subMessage = '格式不正确'>
<#if subFieldValidType == 'only' >
<#assign subMessage = '不能重复'>
</#if>
validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }],
</#if>
},
</#if>
</#if>
</#list>
<#-- 循环子表的列 结束 -->
]
</#if>
</#list>

View File

@ -0,0 +1,179 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
<BasicForm @register="registerForm" ref="formRef"/>
<!-- 子表单区域 -->
<a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs">
<#list subTables as sub><#rt/>
<#if sub.foreignRelationType =='1'>
<a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
<${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form>
</a-tab-pane>
<#else>
<a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
<JVxeTable
keep-source
resizable
:ref="refKeys[${sub_index}]"
:loading="${sub.entityName?uncap_first}Table.loading"
:columns="${sub.entityName?uncap_first}Table.columns"
:dataSource="${sub.entityName?uncap_first}Table.dataSource"
:maxHeight="300"
:rowNumber="true"
:rowSelection="true"
:toolbar="true"
/>
</a-tab-pane>
</#if>
</#list>
</a-tabs>
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref,reactive} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import { JVxeTable } from '/@/components/jeecg/JVxeTable'
import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
<#list subTables as sub>
<#if sub.foreignRelationType =='1'>
import ${sub.entityName}Form from './${sub.entityName}Form.vue'
</#if>
</#list>
import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}Columns</#if></#list>} from '../${entityName?uncap_first}.data';
import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api';
import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
// Emits声明
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
<#assign hasOne2Many = false>
<#assign hasOne2One = false>
const activeKey = ref('${subTables[0].entityName?uncap_first}');
<#list subTables as sub>
<#if sub.foreignRelationType =='0'>
<#assign hasOne2Many = true>
const ${sub.entityName?uncap_first} = ref();
</#if>
<#if sub.foreignRelationType =='1'>
<#assign hasOne2One = true>
const ${sub.entityName?uncap_first}Form = ref();
</#if>
</#list>
const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>};
<#list subTables as sub>
<#if sub.foreignRelationType =='0'>
const ${sub.entityName?uncap_first}Table = reactive({
loading: false,
dataSource: [],
columns:${sub.entityName?uncap_first}Columns
})
</#if>
</#list>
//表单配置
const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
});
//表单赋值
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//重置表单
await reset();
setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
//表单赋值
await setFieldsValue({
...data.record,
});
<#list subTables as sub><#rt/>
<#if sub.foreignRelationType =='1'>
${sub.entityName?uncap_first}Form.value.initFormData(${sub.entityName?uncap_first}List,data?.record?.id)
</#if>
</#list>
<#list subTables as sub><#rt/>
<#if sub.foreignRelationType =='0'>
requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table)
</#if>
</#list>
}
// 隐藏底部时禁用整个表单
setProps({ disabled: !data?.showFooter })
});
//方法配置
const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>);
//设置标题
const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
async function reset(){
await resetFields();
activeKey.value = ref('${subTables[0].entityName?uncap_first}');
<#list subTables as sub>
<#if sub.foreignRelationType =='0'>
${sub.entityName?uncap_first}Table.dataSource = [];
</#if>
<#if sub.foreignRelationType =='1'>
${sub.entityName?uncap_first}Form.value.resetFields();
</#if>
</#list>
}
function classifyIntoFormData(allValues) {
let main = Object.assign({}, allValues.formValue)
return {
...main, // 展开
<#assign subManyIndex = 0>
<#list subTables as sub><#rt/>
<#if sub.foreignRelationType =='0'>
${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData,
<#assign subManyIndex = subManyIndex+1>
<#else>
${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(),
</#if>
</#list>
}
}
<#if hasOne2One==true>
//校验所有一对一子表表单
function validateSubForm(allValues){
return new Promise((resolve,reject)=>{
Promise.all([
<#list subTables as sub><#rt/>
<#if sub.foreignRelationType =='1'>
${sub.entityName?uncap_first}Form.value.validateForm(${sub_index}),
</#if>
</#list>
]).then(() => {
resolve(allValues)
}).catch(e => {
if (e.error === VALIDATE_FAILED) {
// 如果有未通过表单验证的子表就自动跳转到它所在的tab
activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index]
} else {
console.error(e)
}
})
})
}
</#if>
//表单提交事件
async function requestAddOrEdit(values) {
try {
setModalProps({confirmLoading: true});
//提交表单
await saveOrUpdate(values, isUpdate.value);
//关闭弹窗
closeModal();
//刷新列表
emit('success');
} finally {
setModalProps({confirmLoading: false});
}
}
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,64 @@
<#list subTables as sub>
<#if sub.foreignRelationType=='1'>
#segment#${sub.entityName}Form.vue
<template>
<BasicForm @register="registerForm"/>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
import {BasicForm, useForm} from '/@/components/Form/index';
import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
import {defHttp} from '/@/utils/http/axios';
import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
export default defineComponent({
name:"${sub.entityName}Form",
components: {BasicForm},
emits:['register'],
setup(_,{emit}) {
const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({
labelWidth: 150,
schemas: ${sub.entityName?uncap_first}FormSchema,
showActionButtonGroup: false,
});
/**
*初始化加载数据
*/
function initFormData(url,id){
if(id){
defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{
res.success && setFieldsValue({...res.result[0]});
})
}
}
/**
*获取表单数据
*/
function getFormData(){
return [getFieldsValue()];
}
/**
*表单校验
*/
function validateForm(index){
return new Promise((resolve, reject) => {
// 验证子表表单
validate().then(()=>{
return resolve()
}).catch(()=> {
return reject({ error: VALIDATE_FAILED ,index})
})
})
}
return {
registerForm,
resetFields,
initFormData,
getFormData,
validateForm
}
}
})
</script>
</#if>
</#list>

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