Bläddra i källkod

1.账单推送
2.佩服审批

liuhy 3 månader sedan
förälder
incheckning
72660c9d2d
48 ändrade filer med 2733 tillägg och 16 borttagningar
  1. 3 0
      db/.back_电信北区稽核/电信北区稽核-backup-20231225175251.pdma.json
  2. 3 0
      db/.back_电信北区稽核/电信北区稽核-backup-2023814101343.pdma.json
  3. 3 0
      db/.back_电信北区稽核/电信北区稽核-backup-202389170127.pdma.json
  4. 199 0
      db/.back_能耗可视化/能耗可视化-backup-20231011142352.pdma.json
  5. 199 0
      db/.back_能耗可视化/能耗可视化-backup-202391144759.pdma.json
  6. 199 0
      db/.back_能耗可视化/能耗可视化-backup-202391151800.pdma.json
  7. 60 0
      db/增量SQL/archive_menu.sql
  8. 46 0
      db/增量SQL/archive_tables.sql
  9. 77 0
      db/增量SQL/bill_tables.sql
  10. 23 0
      db/增量SQL/bill_tables_update.sql
  11. 121 0
      db/增量SQL/bpm_minimal_menu_dict.sql
  12. 30 0
      db/增量SQL/pay_bill_refactor.sql
  13. 51 0
      db/增量SQL/pay_bill_tables.sql
  14. 120 0
      db/增量SQL/pay_scene_dict.sql
  15. 161 0
      db/增量SQL/warm_flow_tables.sql
  16. 0 0
      db/电信北区稽核.pdma.json
  17. 199 0
      db/能耗可视化.pdma.json
  18. 1 8
      pom.xml
  19. 8 0
      tnc-base/tnc-base-api/tnc-system-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java
  20. 1 0
      tnc-base/tnc-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
  21. 3 0
      tnc-sms/pom.xml
  22. 99 0
      tnc-sms/src/main/java/org/jeecg/modules/archive/controller/ArchiveAccountController.java
  23. 63 0
      tnc-sms/src/main/java/org/jeecg/modules/archive/controller/ArchiveQualificationFileController.java
  24. 2 0
      tnc-sms/src/main/java/org/jeecg/modules/smscheck/controller/TncEnableScheduling.java
  25. 6 0
      tnc-sms/src/main/java/org/jeecg/modules/smscheck/entity/SysUser.java
  26. 3 0
      tnc-sms/src/main/resources/application.yml
  27. 17 0
      tnc-sms/src/main/resources/org/jeecg/modules/bill/mapper/xml/BillCommonFileMapper.xml
  28. 43 0
      tnc-sms/src/main/resources/org/jeecg/modules/bill/mapper/xml/BillCustomerMapper.xml
  29. 8 0
      tnc-system/pom.xml
  30. 62 0
      tnc-system/src/main/assembly/assembly-dx.xml
  31. 204 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/controller/BpmTaskController.java
  32. 156 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/controller/ProcessDefinitionController.java
  33. 127 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/controller/ProcessInstanceController.java
  34. 46 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/vo/BpmTaskVo.java
  35. 27 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/vo/CompleteTaskVo.java
  36. 33 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/vo/ProcessDefinitionVo.java
  37. 35 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/vo/ProcessInstanceVo.java
  38. 25 0
      tnc-system/src/main/java/org/jeecg/modules/bpm/vo/StartProcessVo.java
  39. 32 0
      tnc-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
  40. 112 0
      tnc-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
  41. 6 0
      tnc-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java
  42. 7 0
      tnc-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
  43. 32 0
      tnc-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
  44. 19 0
      tnc-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
  45. 7 0
      tnc-system/src/main/resources/application-prod.yml
  46. 18 7
      tnc-system/src/main/resources/application-test.yml
  47. 14 1
      tnc-system/src/main/resources/application.yml
  48. 23 0
      tnc-system/src/main/resources/bpm/sample-approve.bpmn20.xml

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 0
db/.back_电信北区稽核/电信北区稽核-backup-20231225175251.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 0
db/.back_电信北区稽核/电信北区稽核-backup-2023814101343.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 3 - 0
db/.back_电信北区稽核/电信北区稽核-backup-202389170127.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 199 - 0
db/.back_能耗可视化/能耗可视化-backup-20231011142352.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 199 - 0
db/.back_能耗可视化/能耗可视化-backup-202391144759.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 199 - 0
db/.back_能耗可视化/能耗可视化-backup-202391151800.pdma.json


+ 60 - 0
db/增量SQL/archive_menu.sql

@@ -0,0 +1,60 @@
+-- 档案管理菜单(可选:若使用动态菜单,执行本脚本后可在侧栏看到「档案管理」)
+-- 执行前请先执行 archive_tables.sql
+
+START TRANSACTION;
+
+DELETE FROM sys_permission WHERE id IN ('ARCHIVE_MENU_ROOT_0001', 'ARCHIVE_MENU_LIST_0001', 'ARCHIVE_MENU_FORM_0001', 'ARCHIVE_MENU_DETAIL_0001');
+
+-- 一级菜单:档案管理
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'ARCHIVE_MENU_ROOT_0001', '', '档案管理', '/archive', 'layouts/RouteView', NULL, '/archive/account/list',
+  0, NULL, '1', 40.00, 0, 'folder',
+  1, 0, 0, 0, 0, '档案账号与资质文件管理',
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:档案账号列表
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'ARCHIVE_MENU_LIST_0001', 'ARCHIVE_MENU_ROOT_0001', '档案账号列表', '/archive/account/list', 'archive/ArchiveAccountList', NULL, NULL,
+  1, 'archive:account:list', '1', 1.00, 0, 'user',
+  1, 1, 0, 0, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:新建/编辑(hidden,通过列表跳转)
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'ARCHIVE_MENU_FORM_0001', 'ARCHIVE_MENU_ROOT_0001', '新建/编辑档案子账号', '/archive/account/form', 'archive/ArchiveAccountForm', NULL, NULL,
+  1, 'archive:account:add', '1', 2.00, 0, NULL,
+  1, 1, 0, 1, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:档案账号详情(hidden)
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'ARCHIVE_MENU_DETAIL_0001', 'ARCHIVE_MENU_ROOT_0001', '档案账号详情', '/archive/account/detail', 'archive/ArchiveAccountDetail', NULL, NULL,
+  1, 'archive:account:detail', '1', 3.00, 0, NULL,
+  1, 1, 0, 1, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+COMMIT;

+ 46 - 0
db/增量SQL/archive_tables.sql

@@ -0,0 +1,46 @@
+-- ----------------------------
+-- 档案管理功能相关表
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for archive_account
+-- ----------------------------
+DROP TABLE IF EXISTS `archive_account`;
+CREATE TABLE `archive_account`  (
+  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
+  `sys_user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关联主系统用户ID,同步账号有值,子账号为空',
+  `account_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'sync' COMMENT '账号类型:sync=同步自主系统, local=档案子账号',
+  `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '姓名',
+  `mobile` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
+  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
+  `org_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门编码',
+  `org_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门名称',
+  `sync_time` datetime NULL DEFAULT NULL COMMENT '最近一次从主系统同步时间',
+  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
+  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uniq_archive_sys_user_id`(`sys_user_id`) USING BTREE COMMENT '同一系统用户只同步一条',
+  INDEX `idx_archive_account_type`(`account_type`) USING BTREE,
+  INDEX `idx_archive_account_name`(`name`) USING BTREE,
+  INDEX `idx_archive_account_mobile`(`mobile`) USING BTREE,
+  INDEX `idx_archive_account_create_time`(`create_time`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '档案账号表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for archive_qualification_file
+-- ----------------------------
+DROP TABLE IF EXISTS `archive_qualification_file`;
+CREATE TABLE `archive_qualification_file`  (
+  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
+  `account_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '档案账号ID',
+  `file_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '文件名',
+  `file_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '文件路径/URL',
+  `file_size` bigint(20) NULL DEFAULT NULL COMMENT '文件大小(字节)',
+  `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
+  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_archive_file_account`(`account_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '档案资质文件表' ROW_FORMAT = Dynamic;

+ 77 - 0
db/增量SQL/bill_tables.sql

@@ -0,0 +1,77 @@
+-- ----------------------------
+-- 账单数据发送功能相关表
+-- ----------------------------
+
+-- ----------------------------
+-- Table structure for bill_batch
+-- ----------------------------
+DROP TABLE IF EXISTS `bill_batch`;
+CREATE TABLE `bill_batch`  (
+  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
+  `batch_no` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '批次号',
+  `send_rule_type` tinyint(1) NULL DEFAULT NULL COMMENT '发送规则类型:1-固定年月日,2-每月几日',
+  `send_date` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送日期,固定年月日时存储具体日期,每月几日时存储日期数字1-31',
+  `sender_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送人邮箱',
+  `sender_user_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送人用户ID',
+  `customer_count` int(11) NULL DEFAULT 0 COMMENT '客户总数',
+  `sent_count` int(11) NULL DEFAULT 0 COMMENT '已发送条数',
+  `import_time` datetime NULL DEFAULT NULL COMMENT '导入时间',
+  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人',
+  `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uniq_bill_batch_no`(`batch_no`) USING BTREE,
+  INDEX `idx_bill_batch_sender`(`sender_user_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '账单批次表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for bill_customer
+-- ----------------------------
+DROP TABLE IF EXISTS `bill_customer`;
+CREATE TABLE `bill_customer`  (
+  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
+  `batch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '批次ID',
+  `serial_no` int(11) NULL DEFAULT NULL COMMENT '序号',
+  `customer_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户名称',
+  `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '邮箱',
+  `contract_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '合同号',
+  `developer_email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '发展人邮箱',
+  `bill_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '账单种类',
+  `new_manager` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '新客户经理',
+  `contact_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人',
+  `contact_phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话',
+  `new_developer` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '新业务发展人',
+  `send_date` date NULL DEFAULT NULL COMMENT '发送日期',
+  `send_status` tinyint(1) NULL DEFAULT 0 COMMENT '发送状态:0-未发送,1-发送成功,2-发送失败',
+  `send_time` datetime NULL DEFAULT NULL COMMENT '发送时间',
+  `send_result` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发送结果描述',
+  `error_msg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '错误信息',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_bill_customer_batch`(`batch_id`) USING BTREE,
+  INDEX `idx_bill_customer_contract`(`contract_no`) USING BTREE,
+  INDEX `idx_bill_customer_status`(`send_status`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '账单客户表' ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for bill_common_file
+-- ----------------------------
+DROP TABLE IF EXISTS `bill_common_file`;
+CREATE TABLE `bill_common_file`  (
+  `id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
+  `file_name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '文件名',
+  `file_path` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '文件路径/URL',
+  `file_size` bigint(20) NULL DEFAULT NULL COMMENT '文件大小(字节)',
+  `bill_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账单种类,从文件名解析',
+  `contract_no` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '合同号,从文件名解析',
+  `date_str` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '日期字符串,从文件名解析,如202505',
+  `upload_time` datetime NULL DEFAULT NULL COMMENT '上传时间',
+  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_bill_file_contract`(`contract_no`) USING BTREE,
+  INDEX `idx_bill_file_type`(`bill_type`) USING BTREE,
+  INDEX `idx_bill_file_date`(`date_str`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '通用文件表' ROW_FORMAT = Dynamic;
+

+ 23 - 0
db/增量SQL/bill_tables_update.sql

@@ -0,0 +1,23 @@
+-- ----------------------------
+-- 账单批次关联合同文件功能 - 数据库变更
+-- 执行日期: 2026-03-03
+-- ----------------------------
+
+-- 为 bill_common_file 表添加 batch_id 字段
+ALTER TABLE `bill_common_file` 
+ADD COLUMN `batch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '批次ID' AFTER `id`;
+
+-- 添加批次ID索引
+ALTER TABLE `bill_common_file` 
+ADD INDEX `idx_bill_file_batch`(`batch_id`) USING BTREE;
+
+-- 添加唯一索引,确保同一批次下文件名唯一(用于覆盖逻辑)
+-- 注意:如果 batch_id 为 NULL,则不受此约束影响
+ALTER TABLE `bill_common_file` 
+ADD UNIQUE INDEX `uniq_batch_filename`(`batch_id`, `file_name`) USING BTREE;
+
+-- ----------------------------
+-- 账单批次发送账期设置
+-- ----------------------------
+ALTER TABLE `bill_batch` 
+ADD COLUMN `send_periods` varchar(500) NULL COMMENT '发送账期,多个逗号分隔,格式yyyyMM如202601,202602' AFTER `send_date`;

+ 121 - 0
db/增量SQL/bpm_minimal_menu_dict.sql

@@ -0,0 +1,121 @@
+-- 最小工作流(方案3): 菜单 + 字典 初始化脚本
+-- 适用: MySQL
+-- 说明:
+-- 1) 本脚本会新增一个一级菜单【流程管理】及其子菜单(流程定义/我的待办/我的已办/流程发起)
+-- 2) 本脚本会补充字典【流程状态 bpm_status】(如已存在同 code 的字典请按需手动去重)
+-- 3) 由于 sys_permission 主键为 id,本脚本使用“按 url/perms/name 清理后插入”的方式尽量保证可重复执行
+
+START TRANSACTION;
+
+-- =========================
+-- 1. 字典:流程状态 bpm_status
+-- =========================
+-- 注意:如果你的库中已存在 code=bpm_status 的字典,这里会先删除再插入(避免重复)。如你不希望删除,可改成只 insert。
+DELETE FROM sys_dict_item WHERE dict_id IN (SELECT id FROM sys_dict WHERE dict_code='bpm_status');
+DELETE FROM sys_dict WHERE dict_code='bpm_status';
+
+INSERT INTO sys_dict (id, dict_name, dict_code, description, del_flag, create_by, create_time, update_by, update_time, type)
+VALUES ('BPM_DICT_STATUS_0001', '流程状态', 'bpm_status', '流程状态', 0, 'admin', NOW(), NULL, NULL, 0);
+
+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
+('BPM_DICT_STATUS_ITEM_1', 'BPM_DICT_STATUS_0001', '草稿', 'draft', NULL, 1, 1, 'admin', NOW(), NULL, NULL),
+('BPM_DICT_STATUS_ITEM_2', 'BPM_DICT_STATUS_0001', '审批中', 'running', NULL, 2, 1, 'admin', NOW(), NULL, NULL),
+('BPM_DICT_STATUS_ITEM_3', 'BPM_DICT_STATUS_0001', '已通过', 'passed', NULL, 3, 1, 'admin', NOW(), NULL, NULL),
+('BPM_DICT_STATUS_ITEM_4', 'BPM_DICT_STATUS_0001', '已驳回', 'rejected', NULL, 4, 1, 'admin', NOW(), NULL, NULL),
+('BPM_DICT_STATUS_ITEM_5', 'BPM_DICT_STATUS_0001', '已撤回', 'revoked', NULL, 5, 1, 'admin', NOW(), NULL, NULL);
+
+-- =========================
+-- 2. 菜单:流程管理(一级菜单)
+-- =========================
+-- 清理:按 url/component/perms/name 清理可能存在的旧记录(避免重复)
+DELETE FROM sys_permission WHERE url IN ('/bpm', '/bpm/process-definition', '/bpm/process/design', '/bpm/task/todo', '/bpm/task/done', '/bpm/process/start');
+DELETE FROM sys_permission WHERE component IN (
+  'layouts/RouteView',
+  'modules/bpm/process/ProcessDefinitionList',
+  'modules/bpm/process/ProcessDesigner',
+  'modules/bpm/task/MyTaskList',
+  'modules/bpm/task/MyDoneList',
+  'modules/bpm/process/StartProcess'
+) AND name IN ('流程管理','流程定义','流程设计','我的待办','我的已办','流程发起');
+
+-- 一级菜单
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_ROOT_0001', '', '流程管理', '/bpm', 'layouts/RouteView', NULL, NULL,
+  0, NULL, '1', 50.00, 0, 'profile',
+  1, 0, 0, 0, 0, '最小工作流菜单(方案3)',
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:流程定义
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_PROC_DEF_0001', 'BPM_MENU_ROOT_0001', '流程定义', '/bpm/process-definition', 'modules/bpm/process/ProcessDefinitionList', NULL, NULL,
+  1, NULL, '1', 1.00, 0, 'deployment-unit',
+  1, 1, 0, 0, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:流程设计(画布设计器)
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_DESIGN_0001', 'BPM_MENU_ROOT_0001', '流程设计', '/bpm/process/design', 'modules/bpm/process/ProcessDesigner', NULL, NULL,
+  1, NULL, '1', 1.50, 0, 'edit',
+  1, 1, 0, 0, 0, '可视化流程设计器',
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:我的待办
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_TASK_TODO_0001', 'BPM_MENU_ROOT_0001', '我的待办', '/bpm/task/todo', 'modules/bpm/task/MyTaskList', NULL, NULL,
+  1, NULL, '1', 2.00, 0, 'clock-circle',
+  1, 1, 0, 0, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:我的已办
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_TASK_DONE_0001', 'BPM_MENU_ROOT_0001', '我的已办', '/bpm/task/done', 'modules/bpm/task/MyDoneList', NULL, NULL,
+  1, NULL, '1', 3.00, 0, 'check-square',
+  1, 1, 0, 0, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+-- 子菜单:流程发起
+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, hide_tab, description,
+  create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external
+) VALUES (
+  'BPM_MENU_START_0001', 'BPM_MENU_ROOT_0001', '流程发起', '/bpm/process/start', 'modules/bpm/process/StartProcess', NULL, NULL,
+  1, NULL, '1', 4.00, 0, 'play-circle',
+  1, 1, 0, 0, 0, NULL,
+  'admin', NOW(), NULL, NULL, 0, 0, '1', 0
+);
+
+COMMIT;
+

+ 30 - 0
db/增量SQL/pay_bill_refactor.sql

@@ -0,0 +1,30 @@
+-- 赔付单流程与结构改造 - 增量 SQL
+-- 1. 主表 sms_pay_bill 增加客户名称;保留 pay_reason 作赔付描述;状态支持 5已赔付 6稽核结果
+ALTER TABLE `sms_pay_bill`
+  ADD COLUMN `customer_name` varchar(200) DEFAULT NULL COMMENT '客户名称' AFTER `pay_dept_code`;
+-- 注释:pay_reason 沿用为赔付描述;contract_no/pay_amount/complaint_order_no/fee_start_month/fee_end_month 弃用,数据在明细表
+-- 状态扩展: 0待一级 1待二级 2已通过 3未通过 4已取消 5已赔付 6稽核结果
+
+-- 2. 明细表 sms_pay_bill_item(每条对应一行)
+CREATE TABLE IF NOT EXISTS `sms_pay_bill_item` (
+  `id` varchar(32) NOT NULL COMMENT '主键',
+  `bill_id` varchar(32) NOT NULL COMMENT '赔付单主表id',
+  `business_phone` varchar(20) NOT NULL COMMENT '业务号码',
+  `contract_no` varchar(100) DEFAULT NULL COMMENT '合同号',
+  `pay_amount` decimal(18,2) DEFAULT NULL COMMENT '赔付金额(元)',
+  `pay_period` varchar(50) DEFAULT NULL COMMENT '赔付账期(文本)',
+  `pay_desc` text COMMENT '赔付描述',
+  `pay_scene_first` varchar(50) DEFAULT NULL COMMENT '赔付场景一级',
+  `pay_scene_second` varchar(50) DEFAULT NULL COMMENT '赔付场景二级',
+  `complaint_order_no` varchar(100) DEFAULT NULL COMMENT '赔付工单编号',
+  `oa_bill_no` varchar(100) DEFAULT NULL COMMENT 'OA审批单编号',
+  `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+  `sort_order` int(11) DEFAULT '0' COMMENT '排序',
+  PRIMARY KEY (`id`),
+  KEY `idx_bill_id` (`bill_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赔付单明细表';
+
+-- 3. 附件表 sms_pay_bill_file 增加类型与材料命名
+ALTER TABLE `sms_pay_bill_file`
+  ADD COLUMN `file_type` varchar(50) DEFAULT NULL COMMENT '材料种类: approval/intent/pay_work/license/other' AFTER `bill_id`,
+  ADD COLUMN `file_title` varchar(255) DEFAULT NULL COMMENT '材料命名' AFTER `file_type`;

+ 51 - 0
db/增量SQL/pay_bill_tables.sql

@@ -0,0 +1,51 @@
+-- 赔付单相关表
+CREATE TABLE `sms_pay_bill` (
+  `id` varchar(32) NOT NULL COMMENT '主键',
+  `bill_no` varchar(50) DEFAULT NULL COMMENT '审批单号',
+  `pay_dept_code` varchar(100) DEFAULT NULL COMMENT '赔付部门编码',
+  `contract_no` varchar(100) DEFAULT NULL COMMENT '合同号',
+  `pay_amount` decimal(18,2) DEFAULT NULL COMMENT '赔付金额',
+  `pay_time` datetime DEFAULT NULL COMMENT '赔付时间(最终通过时间)',
+  `complaint_order_no` varchar(100) DEFAULT NULL COMMENT '投诉工单号',
+  `pay_reason` text COMMENT '赔付原因',
+  `fee_start_month` varchar(7) DEFAULT NULL COMMENT '费用开始月份(yyyy-MM)',
+  `fee_end_month` varchar(7) DEFAULT NULL COMMENT '费用结束月份(yyyy-MM)',
+  `op_dept_code` varchar(100) DEFAULT NULL COMMENT '赔付操作部门',
+  `status` int(11) DEFAULT '0' COMMENT '状态: 0待一级审核, 1待二级审核, 2已通过, 3未通过, 4已取消',
+  `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赔付单主表';
+
+CREATE TABLE `sms_pay_bill_phone` (
+  `id` varchar(32) NOT NULL,
+  `bill_id` varchar(32) NOT NULL COMMENT '赔付单ID',
+  `phone` varchar(20) NOT NULL COMMENT '赔付号码',
+  PRIMARY KEY (`id`),
+  INDEX `idx_bill_id` (`bill_id`),
+  INDEX `idx_phone` (`phone`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赔付号码从表';
+
+CREATE TABLE `sms_pay_bill_file` (
+  `id` varchar(32) NOT NULL,
+  `bill_id` varchar(32) NOT NULL COMMENT '赔付单ID',
+  `file_name` varchar(255) DEFAULT NULL COMMENT '文件名',
+  `file_url` varchar(500) DEFAULT NULL COMMENT '文件URL',
+  `file_size` bigint(20) DEFAULT NULL COMMENT '文件大小',
+  PRIMARY KEY (`id`),
+  INDEX `idx_bill_id` (`bill_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赔付单附件表';
+
+CREATE TABLE `sms_pay_bill_log` (
+  `id` varchar(32) NOT NULL,
+  `bill_id` varchar(32) NOT NULL COMMENT '赔付单ID',
+  `op_user` varchar(50) DEFAULT NULL COMMENT '操作人',
+  `op_type` varchar(50) DEFAULT NULL COMMENT '操作类型(提交/审核/驳回/取消)',
+  `op_content` text COMMENT '操作内容/意见',
+  `create_time` datetime DEFAULT NULL COMMENT '操作时间',
+  PRIMARY KEY (`id`),
+  INDEX `idx_bill_id` (`bill_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='赔付单审批记录表';
+

+ 120 - 0
db/增量SQL/pay_scene_dict.sql

@@ -0,0 +1,120 @@
+-- 赔付场景字典:一级 + 二级(同一字典,一级 item_value 无 __,二级为 一级code__序号)
+-- 适用: MySQL
+-- 执行后需刷新字典缓存或重新登录
+
+START TRANSACTION;
+
+DELETE FROM sys_dict_item WHERE dict_id IN (SELECT id FROM sys_dict WHERE dict_code = 'pay_scene');
+DELETE FROM sys_dict WHERE dict_code = 'pay_scene';
+
+INSERT INTO sys_dict (id, dict_name, dict_code, description, del_flag, create_by, create_time, update_by, update_time, type)
+VALUES ('PAY_SCENE_DICT_0001', '赔付场景', 'pay_scene', '赔付场景一级二级分类', 0, 'admin', NOW(), NULL, NULL, 0);
+
+-- 一级 9 条(item_value 不含 __)
+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
+('PAY_SCENE_L1_01', 'PAY_SCENE_DICT_0001', '业务规则费用争议', 'business_rule', NULL, 1, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_02', 'PAY_SCENE_DICT_0001', '影响客户感知或使用', 'customer_perception', NULL, 2, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_03', 'PAY_SCENE_DICT_0001', '营销活动规则', 'marketing_rule', NULL, 3, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_04', 'PAY_SCENE_DICT_0001', '流量费用争议', 'flow_fee', NULL, 4, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_05', 'PAY_SCENE_DICT_0001', '增值业务订购费用争议', 'value_add', NULL, 5, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_06', 'PAY_SCENE_DICT_0001', '渠道服务质量', 'channel_quality', NULL, 6, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_07', 'PAY_SCENE_DICT_0001', '网络质量', 'network_quality', NULL, 7, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_08', 'PAY_SCENE_DICT_0001', '防汛救灾', 'flood_relief', NULL, 8, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L1_09', 'PAY_SCENE_DICT_0001', '其它', 'other', NULL, 9, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:business_rule
+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
+('PAY_SCENE_L2_BR_01', 'PAY_SCENE_DICT_0001', '已定购的业务未使用(包括销号未使用等)', 'business_rule__01', NULL, 10, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_02', 'PAY_SCENE_DICT_0001', '合约到期后未提示变更套餐,仍收取原套餐费用', 'business_rule__02', NULL, 11, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_03', 'PAY_SCENE_DICT_0001', '关停期间套餐费用争议', 'business_rule__03', NULL, 12, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_04', 'PAY_SCENE_DICT_0001', '二次放号营销活动规则争议', 'business_rule__04', NULL, 13, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_05', 'PAY_SCENE_DICT_0001', '月底无法取消业务次月未使用要求减免', 'business_rule__05', NULL, 14, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_06', 'PAY_SCENE_DICT_0001', '语音超出套餐费用争议', 'business_rule__06', NULL, 15, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_07', 'PAY_SCENE_DICT_0001', 'wifi费用争议', 'business_rule__07', NULL, 16, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_08', 'PAY_SCENE_DICT_0001', '短信包争议-否认订购', 'business_rule__08', NULL, 17, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_09', 'PAY_SCENE_DICT_0001', '短信包争议-未使用', 'business_rule__09', NULL, 18, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_10', 'PAY_SCENE_DICT_0001', '短信包争议-重复订购', 'business_rule__10', NULL, 19, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_11', 'PAY_SCENE_DICT_0001', '国话、宽带及IPTV安装调试费', 'business_rule__11', NULL, 20, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_12', 'PAY_SCENE_DICT_0001', '国际湿游费用争议-流量', 'business_rule__12', NULL, 21, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_13', 'PAY_SCENE_DICT_0001', '国际湿游费用争议-流量包', 'business_rule__13', NULL, 22, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_14', 'PAY_SCENE_DICT_0001', '国际湿游费用争议-语音', 'business_rule__14', NULL, 23, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_15', 'PAY_SCENE_DICT_0001', '年付宽带转月付', 'business_rule__15', NULL, 24, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_16', 'PAY_SCENE_DICT_0001', '销户小额欠费赔付', 'business_rule__16', NULL, 25, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_17', 'PAY_SCENE_DICT_0001', '携号转网费用争议', 'business_rule__17', NULL, 26, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_18', 'PAY_SCENE_DICT_0001', 'IPTV、副卡等未纳入融合产品,导致出账', 'business_rule__18', NULL, 27, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_19', 'PAY_SCENE_DICT_0001', '信控停机提醒未下发或下发失败', 'business_rule__19', NULL, 28, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_20', 'PAY_SCENE_DICT_0001', '信控停机提醒-用户感和延迟', 'business_rule__20', NULL, 29, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_BR_21', 'PAY_SCENE_DICT_0001', '其它费用争议', 'business_rule__21', NULL, 30, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:customer_perception
+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
+('PAY_SCENE_L2_CP_01', 'PAY_SCENE_DICT_0001', '满意度修复', 'customer_perception__01', NULL, 31, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CP_02', 'PAY_SCENE_DICT_0001', '其他(其它用户认为公司侧不完善,影响其感知的问题)', 'customer_perception__02', NULL, 32, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CP_03', 'PAY_SCENE_DICT_0001', '充值缴费未到账或延迟到账(常态下)', 'customer_perception__03', NULL, 33, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CP_04', 'PAY_SCENE_DICT_0001', '服务不到位引起用户不满', 'customer_perception__04', NULL, 34, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CP_05', 'PAY_SCENE_DICT_0001', '渠道服务不一致(包括查询、业务办理等)', 'customer_perception__05', NULL, 35, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CP_06', 'PAY_SCENE_DICT_0001', '停开机问题(如缴费不开机)', 'customer_perception__06', NULL, 36, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:marketing_rule
+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
+('PAY_SCENE_L2_MR_01', 'PAY_SCENE_DICT_0001', '权益领取过期或未到账', 'marketing_rule__01', NULL, 37, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_02', 'PAY_SCENE_DICT_0001', '活动返费未到帐', 'marketing_rule__02', NULL, 38, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_03', 'PAY_SCENE_DICT_0001', '代理商返费未到帐', 'marketing_rule__03', NULL, 39, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_04', 'PAY_SCENE_DICT_0001', '套餐/营销活动未开通或取消', 'marketing_rule__04', NULL, 40, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_05', 'PAY_SCENE_DICT_0001', '营销宣传提示不到位或不一致', 'marketing_rule__05', NULL, 41, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_06', 'PAY_SCENE_DICT_0001', '用户否认使用流量', 'marketing_rule__06', NULL, 42, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_07', 'PAY_SCENE_DICT_0001', '定向流量未免流,导致出账', 'marketing_rule__07', NULL, 43, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_MR_08', 'PAY_SCENE_DICT_0001', '家中孩子老人使用', 'marketing_rule__08', NULL, 44, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:flow_fee
+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
+('PAY_SCENE_L2_FF_01', 'PAY_SCENE_DICT_0001', '流量包订购争议-否认订购', 'flow_fee__01', NULL, 45, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_02', 'PAY_SCENE_DICT_0001', '流量包订购争议-未使用', 'flow_fee__02', NULL, 46, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_03', 'PAY_SCENE_DICT_0001', '流量包订购争议-重复订购', 'flow_fee__03', NULL, 47, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_04', 'PAY_SCENE_DICT_0001', '流量未结转', 'flow_fee__04', NULL, 48, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_05', 'PAY_SCENE_DICT_0001', '未配置流量提醒', 'flow_fee__05', NULL, 49, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_06', 'PAY_SCENE_DICT_0001', '未下发或下发失败提醒短信', 'flow_fee__06', NULL, 50, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_07', 'PAY_SCENE_DICT_0001', '用户否认接收提醒信息', 'flow_fee__07', NULL, 51, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FF_08', 'PAY_SCENE_DICT_0001', '用户感知提醒短信延迟', 'flow_fee__08', NULL, 52, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:value_add
+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
+('PAY_SCENE_L2_VA_01', 'PAY_SCENE_DICT_0001', '用户否认使用或订购-点播类', 'value_add__01', NULL, 53, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_VA_02', 'PAY_SCENE_DICT_0001', '用户否认使用或订购-订购类', 'value_add__02', NULL, 54, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_VA_03', 'PAY_SCENE_DICT_0001', '家中孩子老人使用-点播类', 'value_add__03', NULL, 55, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_VA_04', 'PAY_SCENE_DICT_0001', '家中孩子老人使用-订购类', 'value_add__04', NULL, 56, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_VA_05', 'PAY_SCENE_DICT_0001', '订购无法查询或不规范', 'value_add__05', NULL, 57, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:channel_quality
+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
+('PAY_SCENE_L2_CQ_01', 'PAY_SCENE_DICT_0001', '业务受理人工差错', 'channel_quality__01', NULL, 58, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_02', 'PAY_SCENE_DICT_0001', '业务受理系统差错', 'channel_quality__02', NULL, 59, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_03', 'PAY_SCENE_DICT_0001', '业务介绍不全', 'channel_quality__03', NULL, 60, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_04', 'PAY_SCENE_DICT_0001', '传递错误信息', 'channel_quality__04', NULL, 61, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_05', 'PAY_SCENE_DICT_0001', '服务态度', 'channel_quality__05', NULL, 62, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_06', 'PAY_SCENE_DICT_0001', '流程执行差错', 'channel_quality__06', NULL, 63, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_07', 'PAY_SCENE_DICT_0001', '缺乏受理技巧', 'channel_quality__07', NULL, 64, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_08', 'PAY_SCENE_DICT_0001', '(装维)当当慢', 'channel_quality__08', NULL, 65, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_09', 'PAY_SCENE_DICT_0001', '传递错误信息(10000号渠道)', 'channel_quality__09', NULL, 66, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_10', 'PAY_SCENE_DICT_0001', '服务态度(10000号渠道)', 'channel_quality__10', NULL, 67, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_11', 'PAY_SCENE_DICT_0001', '流程执行差错(10000号渠道)', 'channel_quality__11', NULL, 68, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_12', 'PAY_SCENE_DICT_0001', '缺乏受理技巧(10000号渠道)', 'channel_quality__12', NULL, 69, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_13', 'PAY_SCENE_DICT_0001', '业务介绍不全(10000号渠道)', 'channel_quality__13', NULL, 70, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_14', 'PAY_SCENE_DICT_0001', '业务受理人工差错(10000号渠道)', 'channel_quality__14', NULL, 71, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_CQ_15', 'PAY_SCENE_DICT_0001', '业务受理系统差错(10000号渠道)', 'channel_quality__15', NULL, 72, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:network_quality
+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
+('PAY_SCENE_L2_NQ_01', 'PAY_SCENE_DICT_0001', '临时断站或网络突发', 'network_quality__01', NULL, 73, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_NQ_02', 'PAY_SCENE_DICT_0001', '网络部门确认无法立即解决的网络问题', 'network_quality__02', NULL, 74, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:flood_relief
+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
+('PAY_SCENE_L2_FR_01', 'PAY_SCENE_DICT_0001', '通信费用', 'flood_relief__01', NULL, 75, 1, 'admin', NOW(), NULL, NULL),
+('PAY_SCENE_L2_FR_02', 'PAY_SCENE_DICT_0001', '卫星直连费用', 'flood_relief__02', NULL, 76, 1, 'admin', NOW(), NULL, NULL);
+
+-- 二级:other
+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
+('PAY_SCENE_L2_OT_01', 'PAY_SCENE_DICT_0001', '其他', 'other__01', NULL, 77, 1, 'admin', NOW(), NULL, NULL);
+
+COMMIT;

+ 161 - 0
db/增量SQL/warm_flow_tables.sql

@@ -0,0 +1,161 @@
+-- Warm-Flow 工作流引擎 全量建表脚本(MySQL)
+-- 来源:https://gitee.com/dromara/warm-flow/blob/master/sql/mysql/warm-flow-all.sql
+-- 首次集成执行本脚本;后续版本升级请使用官方 warm-flow_x.x.x-upgrade.sql
+
+CREATE TABLE IF NOT EXISTS `flow_definition`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `flow_code` varchar(40) NOT NULL COMMENT '流程编码',
+ `flow_name` varchar(100) NOT NULL COMMENT '流程名称',
+ `model_value` varchar(40) NOT NULL DEFAULT 'CLASSICS' COMMENT '设计器模型(CLASSICS经典模型 MIMIC仿钉钉模型)',
+ `category` varchar(100) DEFAULT NULL COMMENT '流程类别',
+ `version` varchar(20) NOT NULL COMMENT '流程版本',
+ `is_publish` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否发布(0未发布 1已发布 9失效)',
+ `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)',
+ `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径',
+ `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态(0挂起 1激活)',
+ `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型',
+ `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径',
+ `ext` varchar(500) DEFAULT NULL COMMENT '业务详情 存业务表对象json字符串',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='流程定义表';
+
+CREATE TABLE IF NOT EXISTS `flow_node`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `node_type` tinyint(1) NOT NULL COMMENT '节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关)',
+ `definition_id` bigint NOT NULL COMMENT '流程定义id',
+ `node_code` varchar(100) NOT NULL COMMENT '流程节点编码',
+ `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称',
+ `permission_flag` varchar(200) DEFAULT NULL COMMENT '权限标识(权限类型:权限标识,可以多个,用@@隔开)',
+ `node_ratio` varchar(200) DEFAULT NULL COMMENT '流程签署比例值',
+ `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标',
+ `any_node_skip` varchar(100) DEFAULT NULL COMMENT '任意结点跳转',
+ `listener_type` varchar(100) DEFAULT NULL COMMENT '监听器类型',
+ `listener_path` varchar(400) DEFAULT NULL COMMENT '监听器路径',
+ `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义(Y是 N否)',
+ `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径',
+ `version` varchar(20) NOT NULL COMMENT '版本',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `ext` text COMMENT '节点扩展属性',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='流程节点表';
+
+CREATE TABLE IF NOT EXISTS `flow_skip`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `definition_id` bigint NOT NULL COMMENT '流程定义id',
+ `now_node_code` varchar(100) NOT NULL COMMENT '当前流程节点的编码',
+ `now_node_type` tinyint(1) DEFAULT NULL COMMENT '当前节点类型',
+ `next_node_code` varchar(100) NOT NULL COMMENT '下一个流程节点的编码',
+ `next_node_type` tinyint(1) DEFAULT NULL COMMENT '下一个节点类型',
+ `skip_name` varchar(100) DEFAULT NULL COMMENT '跳转名称',
+ `skip_type` varchar(40) DEFAULT NULL COMMENT '跳转类型(PASS审批通过 REJECT退回)',
+ `skip_condition` varchar(200) DEFAULT NULL COMMENT '跳转条件',
+ `coordinate` varchar(100) DEFAULT NULL COMMENT '坐标',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='节点跳转关联表';
+
+CREATE TABLE IF NOT EXISTS `flow_instance`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id',
+ `business_id` varchar(40) NOT NULL COMMENT '业务id',
+ `node_type` tinyint(1) NOT NULL COMMENT '节点类型',
+ `node_code` varchar(40) NOT NULL COMMENT '流程节点编码',
+ `node_name` varchar(100) DEFAULT NULL COMMENT '流程节点名称',
+ `variable` text COMMENT '任务变量',
+ `flow_status` varchar(20) NOT NULL COMMENT '流程状态',
+ `activity_status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '流程激活状态',
+ `def_json` text COMMENT '流程定义json',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `ext` varchar(500) DEFAULT NULL COMMENT '扩展字段',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='流程实例表';
+
+CREATE TABLE IF NOT EXISTS `flow_task`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `definition_id` bigint NOT NULL COMMENT '对应flow_definition表的id',
+ `instance_id` bigint NOT NULL COMMENT '对应flow_instance表的id',
+ `node_code` varchar(100) NOT NULL COMMENT '节点编码',
+ `node_name` varchar(100) DEFAULT NULL COMMENT '节点名称',
+ `node_type` tinyint(1) NOT NULL COMMENT '节点类型',
+ `flow_status` varchar(20) NOT NULL COMMENT '流程状态',
+ `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义',
+ `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(64) DEFAULT '' COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='待办任务表';
+
+CREATE TABLE IF NOT EXISTS `flow_his_task`
+(
+ `id` bigint(20) NOT NULL COMMENT '主键id',
+ `definition_id` bigint(20) NOT NULL COMMENT '对应flow_definition表的id',
+ `instance_id` bigint(20) NOT NULL COMMENT '对应flow_instance表的id',
+ `task_id` bigint(20) NOT NULL COMMENT '对应flow_task表的id',
+ `node_code` varchar(100) DEFAULT NULL COMMENT '开始节点编码',
+ `node_name` varchar(100) DEFAULT NULL COMMENT '开始节点名称',
+ `node_type` tinyint(1) DEFAULT NULL COMMENT '开始节点类型',
+ `target_node_code` varchar(200) DEFAULT NULL COMMENT '目标节点编码',
+ `target_node_name` varchar(200) DEFAULT NULL COMMENT '结束节点名称',
+ `approver` varchar(40) DEFAULT NULL COMMENT '审批人',
+ `cooperate_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '协作方式',
+ `collaborator` varchar(500) DEFAULT NULL COMMENT '协作人',
+ `skip_type` varchar(10) NOT NULL COMMENT '流转类型',
+ `flow_status` varchar(20) NOT NULL COMMENT '流程状态',
+ `form_custom` char(1) DEFAULT 'N' COMMENT '审批表单是否自定义',
+ `form_path` varchar(100) DEFAULT NULL COMMENT '审批表单路径',
+ `message` varchar(500) DEFAULT NULL COMMENT '审批意见',
+ `variable` TEXT DEFAULT NULL COMMENT '任务变量',
+ `ext` TEXT DEFAULT NULL COMMENT '业务详情',
+ `create_time` datetime DEFAULT NULL COMMENT '任务开始时间',
+ `update_time` datetime DEFAULT NULL COMMENT '审批完成时间',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COMMENT ='历史任务记录表';
+
+CREATE TABLE IF NOT EXISTS `flow_user`
+(
+ `id` bigint NOT NULL COMMENT '主键id',
+ `type` char(1) NOT NULL COMMENT '人员类型',
+ `processed_by` varchar(80) DEFAULT NULL COMMENT '权限人',
+ `associated` bigint NOT NULL COMMENT '任务表id',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `create_by` varchar(80) DEFAULT NULL COMMENT '创建人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `update_by` varchar(64) DEFAULT '' COMMENT '更新人',
+ `del_flag` char(1) DEFAULT '0' COMMENT '删除标志',
+ `tenant_id` varchar(40) DEFAULT NULL COMMENT '租户id',
+ PRIMARY KEY (`id`) USING BTREE,
+ KEY `user_processed_type` (`processed_by`, `type`),
+ KEY `user_associated` (`associated`) USING BTREE
+) ENGINE = InnoDB COMMENT ='流程用户表';

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
db/电信北区稽核.pdma.json


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 199 - 0
db/能耗可视化.pdma.json


+ 1 - 8
pom.xml

@@ -83,14 +83,7 @@
 	    </snapshotRepository>
 	</distributionManagement>
 	<repositories>
-		<repository>
-            <id>aliyun</id>
-            <name>aliyun Repository</name>
-            <url>https://maven.aliyun.com/repository/public</url>
-            <snapshots>
-				<enabled>false</enabled>
-			</snapshots>
-        </repository>
+		<!-- NOTE: aliyun 仓库在部分网络环境下可能无法解析,构建时会失败;这里临时禁用,仅保留 jeecg 仓库,其他依赖走 Maven Central 默认仓库 -->
 		<repository>
             <id>jeecg</id>
             <name>jeecg Repository</name>

+ 8 - 0
tnc-base/tnc-base-api/tnc-system-api/src/main/java/org/jeecg/common/system/api/ISysBaseAPI.java

@@ -139,6 +139,14 @@ public interface ISysBaseAPI extends CommonAPI {
      */
     public JSONObject queryAllUser(String userIds, Integer pageNo, Integer pageSize);
 
+    /**
+     * 19b 分页查询用户(供档案同步用),含手机号、部门编码、部门名称
+     * @param pageNo 当前页数
+     * @param pageSize 每页显示条数
+     * @return JSONObject 含 list(每项含 id, title, email, mobile, orgCode, orgName), total
+     */
+    public JSONObject queryAllUserForArchiveSync(Integer pageNo, Integer pageSize);
+
     /**
      * 20获取所有角色
      * @return

+ 1 - 0
tnc-base/tnc-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java

@@ -88,6 +88,7 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/sys/user/register", "anon");//用户注册
         filterChainDefinitionMap.put("/sys/user/phoneVerification", "anon");//用户忘记密码验证手机号
         filterChainDefinitionMap.put("/sys/user/passwordChange", "anon");//用户更改密码
+        filterChainDefinitionMap.put("/sys/user/resetAdminPassword", "anon");//重置admin密码(临时,用完请删除)
         filterChainDefinitionMap.put("/auth/2step-code", "anon");//登录验证码
         filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token
         filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览

+ 3 - 0
tnc-sms/pom.xml

@@ -20,6 +20,9 @@
             <groupId>org.jeecgframework.boot</groupId>
             <artifactId>tnc-system-api</artifactId>
         </dependency>
+
+        <!-- bill模块依赖:Excel/邮件/Minio/Shiro等能力由 tnc-base-core 统一提供 -->
+
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>

+ 99 - 0
tnc-sms/src/main/java/org/jeecg/modules/archive/controller/ArchiveAccountController.java

@@ -0,0 +1,99 @@
+package org.jeecg.modules.archive.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.archive.entity.ArchiveAccount;
+import org.jeecg.modules.archive.service.IArchiveAccountService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 档案账号 Controller
+ */
+@Slf4j
+@Api(tags = "档案管理-档案账号")
+@RestController
+@RequestMapping("/archive/account")
+public class ArchiveAccountController extends JeecgController<ArchiveAccount, IArchiveAccountService> {
+
+    @Autowired
+    private IArchiveAccountService archiveAccountService;
+
+    @ApiOperation("分页列表")
+    @GetMapping(value = "/list")
+    public Result<?> queryPageList(ArchiveAccount account,
+                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                   HttpServletRequest req) {
+        QueryWrapper<ArchiveAccount> queryWrapper = QueryGenerator.initQueryWrapper(account, req.getParameterMap());
+        Page<ArchiveAccount> page = new Page<>(pageNo, pageSize);
+        IPage<ArchiveAccount> pageList = archiveAccountService.page(page, queryWrapper);
+        return Result.OK(pageList);
+    }
+
+    @ApiOperation("详情")
+    @GetMapping(value = "/queryById")
+    public Result<?> queryById(@RequestParam(name = "id") String id) {
+        ArchiveAccount account = archiveAccountService.getById(id);
+        if (account == null) {
+            return Result.error("未找到对应数据");
+        }
+        return Result.OK(account);
+    }
+
+    @AutoLog(value = "档案账号-新增子账号")
+    @ApiOperation("新增档案子账号")
+    @PostMapping(value = "/add")
+    public Result<?> add(@RequestBody ArchiveAccount account) {
+        account.setAccountType("local");
+        account.setSysUserId(null);
+        archiveAccountService.save(account);
+        return Result.OK("添加成功!");
+    }
+
+    @AutoLog(value = "档案账号-编辑")
+    @ApiOperation("编辑(仅子账号可编辑)")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+    public Result<?> edit(@RequestBody ArchiveAccount account) {
+        boolean ok = archiveAccountService.updateLocalAccount(account);
+        if (ok) {
+            return Result.OK("编辑成功!");
+        }
+        return Result.error("仅支持编辑档案子账号,或记录不存在");
+    }
+
+    @AutoLog(value = "档案账号-删除")
+    @ApiOperation("删除(仅子账号可删除)")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id") String id) {
+        try {
+            archiveAccountService.removeAccountById(id);
+            return Result.OK("删除成功!");
+        } catch (IllegalArgumentException e) {
+            return Result.error(e.getMessage());
+        }
+    }
+
+    @AutoLog(value = "档案账号-立即同步主系统")
+    @ApiOperation("立即同步主系统账号到档案")
+    @PostMapping(value = "/syncNow")
+    public Result<?> syncNow() {
+        try {
+            archiveAccountService.syncNowFromMainSystem();
+            return Result.OK("同步任务已触发,请稍后刷新列表查看");
+        } catch (Exception e) {
+            log.error("同步失败", e);
+            return Result.error("同步失败: " + e.getMessage());
+        }
+    }
+}

+ 63 - 0
tnc-sms/src/main/java/org/jeecg/modules/archive/controller/ArchiveQualificationFileController.java

@@ -0,0 +1,63 @@
+package org.jeecg.modules.archive.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.modules.archive.entity.ArchiveQualificationFile;
+import org.jeecg.modules.archive.service.IArchiveQualificationFileService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 档案资质文件 Controller
+ */
+@Slf4j
+@Api(tags = "档案管理-资质文件")
+@RestController
+@RequestMapping("/archive/file")
+public class ArchiveQualificationFileController {
+
+    @Autowired
+    private IArchiveQualificationFileService qualificationFileService;
+
+    @ApiOperation("按档案账号ID查询资质文件列表")
+    @GetMapping(value = "/listByAccount")
+    public Result<?> listByAccountId(@RequestParam(name = "accountId") String accountId) {
+        List<ArchiveQualificationFile> list = qualificationFileService.listByAccountId(accountId);
+        return Result.OK(list);
+    }
+
+    @AutoLog(value = "档案资质文件-添加")
+    @ApiOperation("添加资质文件记录(上传文件后调用,传入 filePath/fileName 等)")
+    @PostMapping(value = "/add")
+    public Result<?> add(@RequestBody ArchiveQualificationFile file) {
+        if (file.getCreateTime() == null) {
+            file.setCreateTime(new Date());
+        }
+        qualificationFileService.save(file);
+        return Result.OK("添加成功!");
+    }
+
+    @AutoLog(value = "档案资质文件-删除")
+    @ApiOperation("删除资质文件")
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id") String id) {
+        qualificationFileService.removeById(id);
+        return Result.OK("删除成功!");
+    }
+
+    @ApiOperation("根据ID查询")
+    @GetMapping(value = "/queryById")
+    public Result<?> queryById(@RequestParam(name = "id") String id) {
+        ArchiveQualificationFile file = qualificationFileService.getById(id);
+        if (file == null) {
+            return Result.error("未找到对应数据");
+        }
+        return Result.OK(file);
+    }
+}

+ 2 - 0
tnc-sms/src/main/java/org/jeecg/modules/smscheck/controller/TncEnableScheduling.java

@@ -66,4 +66,6 @@ public class TncEnableScheduling {
         log.info("tncEnableScheduling结束");
     }
 
+
+
 }

+ 6 - 0
tnc-sms/src/main/java/org/jeecg/modules/smscheck/entity/SysUser.java

@@ -178,4 +178,10 @@ public class SysUser implements Serializable {
 
     /**设备id uniapp推送用*/
     private String clientId;
+
+    /**
+     * 用户邮箱SMTP密钥
+     */
+    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+    private String mailSecret;
 }

+ 3 - 0
tnc-sms/src/main/resources/application.yml

@@ -0,0 +1,3 @@
+mybatis-plus:
+  mapper-locations: classpath*:mapper/**/*.xml
+

+ 17 - 0
tnc-sms/src/main/resources/org/jeecg/modules/bill/mapper/xml/BillCommonFileMapper.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bill.mapper.BillCommonFileMapper">
+
+    <!-- 根据合同号、账单种类、日期匹配文件 -->
+    <select id="selectByMatch" resultType="org.jeecg.modules.bill.entity.BillCommonFile">
+        SELECT * FROM bill_common_file 
+        WHERE contract_no = #{contractNo}
+        AND date_str = #{dateStr}
+        <if test="billType != null and billType != ''">
+            AND bill_type = #{billType}
+        </if>
+        ORDER BY create_time DESC
+    </select>
+
+</mapper>
+

+ 43 - 0
tnc-sms/src/main/resources/org/jeecg/modules/bill/mapper/xml/BillCustomerMapper.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.bill.mapper.BillCustomerMapper">
+
+    <!-- 根据批次ID查询客户列表 -->
+    <select id="selectByBatchId" resultType="org.jeecg.modules.bill.entity.BillCustomer">
+        SELECT * FROM bill_customer WHERE batch_id = #{batchId} ORDER BY serial_no
+    </select>
+
+    <!-- 根据批次ID删除客户 -->
+    <delete id="deleteByBatchId">
+        DELETE FROM bill_customer WHERE batch_id = #{batchId}
+    </delete>
+
+    <!-- 统计批次已发送数量 -->
+    <select id="countSentByBatchId" resultType="int">
+        SELECT COUNT(*) FROM bill_customer 
+        WHERE batch_id = #{batchId} AND send_status = 1
+    </select>
+
+    <!-- 根据批次ID统计客户总数 -->
+    <select id="countByBatchId" resultType="int">
+        SELECT COUNT(*) FROM bill_customer WHERE batch_id = #{batchId}
+    </select>
+
+    <!-- 根据批次ID + 合同号 + 邮箱查询客户 -->
+    <select id="selectByBatchAndKey" resultType="org.jeecg.modules.bill.entity.BillCustomer">
+        SELECT * FROM bill_customer 
+        WHERE batch_id = #{batchId} 
+        AND contract_no = #{contractNo} 
+        AND email = #{email}
+        LIMIT 1
+    </select>
+
+    <!-- 批量删除客户 -->
+    <delete id="deleteByIds">
+        DELETE FROM bill_customer WHERE id IN
+        <foreach collection="ids" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>

+ 8 - 0
tnc-system/pom.xml

@@ -69,6 +69,13 @@
 			<artifactId>jimureport-spring-boot-starter</artifactId>
 		</dependency>
 
+		<!-- Flowable 工作流(官方依赖) -->
+		<dependency>
+			<groupId>org.flowable</groupId>
+			<artifactId>flowable-spring-boot-starter-process</artifactId>
+			<version>6.8.0</version>
+		</dependency>
+
 	</dependencies>
 
 	<build>
@@ -87,6 +94,7 @@
 				<artifactId>maven-assembly-plugin</artifactId>
 				<configuration>
 					<descriptors>
+						<!--suppress UnresolvedMavenProperty -->
 						<descriptor>src/main/assembly/assembly-${profile.name}.xml</descriptor>
 					</descriptors>
 					<tarLongFileMode>gnu</tarLongFileMode>

+ 62 - 0
tnc-system/src/main/assembly/assembly-dx.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
+
+    <!--
+       可自定义,这里指定的是项目环境
+       profile.name 是父工程中多环境 profile.properties 中的配置
+       ${project.build.finalName}-${profile.name}.tar.gz
+    -->
+    <id>${profile.name}</id>
+
+    <!--
+       打包的类型,如果有N个,将会打N个类型的包
+       tar.gz、zip、war、jar、war、dir
+    -->
+    <formats>
+        <format>zip</format>
+    </formats>
+
+    <fileSets>
+        <!--
+            0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;
+            0644->即用户具有读写权限,组用户和其它用户具有只读权限;
+        -->
+        <!-- 将 src/main/bin 目录下的所有文件,输出到打包后的 / 根目录中 -->
+        <fileSet>
+            <directory>${basedir}/src/main/bin/${profile.name}</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0755</fileMode>
+            <filtered>true</filtered>
+            <lineEnding>unix</lineEnding>
+            <includes>
+                <include>**.bat</include>
+            </includes>
+        </fileSet>
+
+        <!-- 指target/classes 目录下的配置文件,输出到打包后的 config 目录中 -->
+        <fileSet>
+            <directory>${basedir}/target/classes</directory>
+            <outputDirectory>config</outputDirectory>
+            <fileMode>0644</fileMode>
+            <includes>
+                <include>application.yml</include>
+                <include>application-${profile.name}.yml</include>
+                <include>config/*-${profile.name}.xml</include>
+                <include>jeecg/**</include>
+            </includes>
+        </fileSet>
+
+        <!-- 将项目启动jar打包到 / 根目录中 -->
+        <fileSet>
+            <directory>${basedir}/target</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0755</fileMode>
+            <includes>
+                <include>${project.build.finalName}.jar</include>
+            </includes>
+        </fileSet>
+
+    </fileSets>
+
+</assembly>

+ 204 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/controller/BpmTaskController.java

@@ -0,0 +1,204 @@
+package org.jeecg.modules.bpm.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.TaskService;
+import org.flowable.engine.history.HistoricProcessInstance;
+import org.flowable.task.api.Task;
+import org.flowable.task.api.history.HistoricTaskInstance;
+import org.flowable.task.api.history.HistoricTaskInstanceQuery;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.bpm.vo.BpmTaskVo;
+import org.jeecg.modules.bpm.vo.CompleteTaskVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 流程任务(待办/已办/办理/驳回)
+ */
+@Slf4j
+@Api(tags = "流程任务")
+@RestController
+@RequestMapping("/bpm/task")
+public class BpmTaskController {
+
+    @Autowired
+    private TaskService taskService;
+    @Autowired
+    private HistoryService historyService;
+    @Autowired
+    private ISysBaseAPI sysBaseApi;
+
+    private String getBusinessKeyByProcessInstanceId(String processInstanceId) {
+        if (processInstanceId == null) return null;
+        HistoricProcessInstance hi = historyService.createHistoricProcessInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .singleResult();
+        return hi != null ? hi.getBusinessKey() : null;
+    }
+
+    private BpmTaskVo taskToVo(Task task) {
+        BpmTaskVo vo = new BpmTaskVo();
+        vo.setId(task.getId());
+        vo.setName(task.getName());
+        vo.setProcessInstanceId(task.getProcessInstanceId());
+        vo.setProcessDefinitionId(task.getProcessDefinitionId());
+        vo.setBusinessKey(getBusinessKeyByProcessInstanceId(task.getProcessInstanceId()));
+        vo.setAssignee(task.getAssignee());
+        if (task.getAssignee() != null) {
+            LoginUser u = sysBaseApi.getUserById(task.getAssignee());
+            vo.setAssigneeName(u != null ? u.getRealname() : task.getAssignee());
+        }
+        vo.setCreateTime(task.getCreateTime());
+        HistoricProcessInstance hi = historyService.createHistoricProcessInstanceQuery()
+                .processInstanceId(task.getProcessInstanceId()).singleResult();
+        if (hi != null) {
+            vo.setProcessDefinitionName(hi.getProcessDefinitionName());
+            vo.setStartUserId(hi.getStartUserId());
+            if (hi.getStartUserId() != null) {
+                LoginUser u = sysBaseApi.getUserById(hi.getStartUserId());
+                vo.setStartUserName(u != null ? u.getRealname() : hi.getStartUserId());
+            }
+        }
+        return vo;
+    }
+
+    private BpmTaskVo historicTaskToVo(HistoricTaskInstance ti) {
+        BpmTaskVo vo = new BpmTaskVo();
+        vo.setId(ti.getId());
+        vo.setName(ti.getName());
+        vo.setProcessInstanceId(ti.getProcessInstanceId());
+        vo.setProcessDefinitionId(ti.getProcessDefinitionId());
+        vo.setBusinessKey(getBusinessKeyByProcessInstanceId(ti.getProcessInstanceId()));
+        vo.setAssignee(ti.getAssignee());
+        if (ti.getAssignee() != null) {
+            LoginUser u = sysBaseApi.getUserById(ti.getAssignee());
+            vo.setAssigneeName(u != null ? u.getRealname() : ti.getAssignee());
+        }
+        vo.setCreateTime(ti.getCreateTime());
+        vo.setEndTime(ti.getEndTime());
+        HistoricProcessInstance hi = historyService.createHistoricProcessInstanceQuery()
+                .processInstanceId(ti.getProcessInstanceId()).singleResult();
+        if (hi != null) {
+            vo.setProcessDefinitionName(hi.getProcessDefinitionName());
+            vo.setStartUserId(hi.getStartUserId());
+            if (hi.getStartUserId() != null) {
+                LoginUser u = sysBaseApi.getUserById(hi.getStartUserId());
+                vo.setStartUserName(u != null ? u.getRealname() : hi.getStartUserId());
+            }
+        }
+        return vo;
+    }
+
+    @ApiOperation("我的待办")
+    @GetMapping("/todo")
+    public Result<Map<String, Object>> todo(
+            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String userId = user != null ? user.getUsername() : null;
+        if (userId == null) {
+            Map<String, Object> empty = new HashMap<>();
+            empty.put("records", new java.util.ArrayList<>());
+            empty.put("total", 0L);
+            return Result.OK(empty);
+        }
+        long total = taskService.createTaskQuery().taskAssignee(userId).count();
+        List<Task> list = taskService.createTaskQuery()
+                .taskAssignee(userId)
+                .orderByTaskCreateTime().desc()
+                .listPage((pageNo - 1) * pageSize, pageSize);
+        List<BpmTaskVo> voList = list.stream().map(this::taskToVo).collect(Collectors.toList());
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", voList);
+        map.put("total", total);
+        return Result.OK(map);
+    }
+
+    @ApiOperation("我的已办")
+    @GetMapping("/done")
+    public Result<Map<String, Object>> done(
+            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String userId = user != null ? user.getUsername() : null;
+        if (userId == null) {
+            Map<String, Object> empty = new HashMap<>();
+            empty.put("records", new java.util.ArrayList<>());
+            empty.put("total", 0L);
+            return Result.OK(empty);
+        }
+        HistoricTaskInstanceQuery q = historyService.createHistoricTaskInstanceQuery()
+                .taskAssignee(userId).finished();
+        long total = q.count();
+        List<HistoricTaskInstance> list = q.orderByHistoricTaskInstanceEndTime().desc()
+                .listPage((pageNo - 1) * pageSize, pageSize);
+        List<BpmTaskVo> voList = list.stream().map(this::historicTaskToVo).collect(Collectors.toList());
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", voList);
+        map.put("total", total);
+        return Result.OK(map);
+    }
+
+    @ApiOperation("任务详情")
+    @GetMapping("/detail")
+    public Result<BpmTaskVo> detail(@RequestParam String taskId) {
+        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
+        if (task == null) {
+            return Result.error("任务不存在或已完成");
+        }
+        BpmTaskVo vo = taskToVo(task);
+        Map<String, Object> vars = taskService.getVariables(taskId);
+        vo.setVariables(vars);
+        return Result.OK(vo);
+    }
+
+    @ApiOperation("办理通过")
+    @PostMapping("/complete")
+    public Result<?> complete(@RequestBody CompleteTaskVo vo) {
+        if (vo.getTaskId() == null || vo.getTaskId().isEmpty()) {
+            return Result.error("任务ID不能为空");
+        }
+        try {
+            Map<String, Object> vars = vo.getVariables() != null ? vo.getVariables() : new HashMap<>();
+            if (vo.getComment() != null && !vo.getComment().isEmpty()) {
+                taskService.addComment(vo.getTaskId(), null, vo.getComment());
+            }
+            taskService.complete(vo.getTaskId(), vars);
+            return Result.OK("办理成功");
+        } catch (Exception e) {
+            log.error("办理失败", e);
+            return Result.error("办理失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("驳回")
+    @PostMapping("/reject")
+    public Result<?> reject(@RequestBody CompleteTaskVo vo) {
+        if (vo.getTaskId() == null || vo.getTaskId().isEmpty()) {
+            return Result.error("任务ID不能为空");
+        }
+        try {
+            if (vo.getComment() != null && !vo.getComment().isEmpty()) {
+                taskService.addComment(vo.getTaskId(), null, vo.getComment());
+            }
+            Map<String, Object> vars = vo.getVariables() != null ? vo.getVariables() : new HashMap<>();
+            vars.put("approvalResult", "reject");
+            taskService.complete(vo.getTaskId(), vars);
+            return Result.OK("已驳回");
+        } catch (Exception e) {
+            log.error("驳回失败", e);
+            return Result.error("驳回失败:" + e.getMessage());
+        }
+    }
+}

+ 156 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/controller/ProcessDefinitionController.java

@@ -0,0 +1,156 @@
+package org.jeecg.modules.bpm.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.RepositoryService;
+import org.flowable.engine.repository.Deployment;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.jeecg.common.api.vo.Result;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipInputStream;
+
+/**
+ * 流程定义管理(Flowable)
+ */
+@Slf4j
+@Api(tags = "流程定义")
+@RestController
+@RequestMapping("/bpm/process-definition")
+public class ProcessDefinitionController {
+
+    @Autowired
+    private RepositoryService repositoryService;
+
+    @ApiOperation("分页列表")
+    @GetMapping("/list")
+    public Result<Map<String, Object>> list(
+            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+            @RequestParam(required = false) String name,
+            @RequestParam(required = false) String key) {
+        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
+                .processDefinitionNameLike(name != null && !name.isEmpty() ? "%" + name + "%" : null)
+                .processDefinitionKeyLike(key != null && !key.isEmpty() ? "%" + key + "%" : null)
+                .latestVersion()
+                .orderByProcessDefinitionKey().asc()
+                .listPage((pageNo - 1) * pageSize, pageSize);
+        long total = repositoryService.createProcessDefinitionQuery()
+                .processDefinitionNameLike(name != null && !name.isEmpty() ? "%" + name + "%" : null)
+                .processDefinitionKeyLike(key != null && !key.isEmpty() ? "%" + key + "%" : null)
+                .latestVersion()
+                .count();
+
+        List<org.jeecg.modules.bpm.vo.ProcessDefinitionVo> voList = new ArrayList<>();
+        for (ProcessDefinition pd : list) {
+            org.jeecg.modules.bpm.vo.ProcessDefinitionVo vo = new org.jeecg.modules.bpm.vo.ProcessDefinitionVo();
+            vo.setId(pd.getId());
+            vo.setKey(pd.getKey());
+            vo.setName(pd.getName());
+            vo.setVersion(pd.getVersion());
+            vo.setDeploymentId(pd.getDeploymentId());
+            Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(pd.getDeploymentId()).singleResult();
+            vo.setDeploymentTime(deployment != null ? deployment.getDeploymentTime() : null);
+            vo.setSuspended(pd.isSuspended());
+            voList.add(vo);
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", voList);
+        map.put("total", total);
+        return Result.OK(map);
+    }
+
+    @ApiOperation("部署(上传 BPMN 或 ZIP)")
+    @PostMapping("/deploy")
+    public Result<?> deploy(
+            @RequestParam("file") MultipartFile file,
+            @RequestParam(required = false) String deploymentName) {
+        String name = deploymentName != null && !deploymentName.isEmpty() ? deploymentName : file.getOriginalFilename();
+        try {
+            if (name != null && name.endsWith(".zip")) {
+                repositoryService.createDeployment()
+                        .name(name)
+                        .addZipInputStream(new ZipInputStream(file.getInputStream()))
+                        .deploy();
+            } else {
+                repositoryService.createDeployment()
+                        .name(name)
+                        .addInputStream(file.getOriginalFilename(), file.getInputStream())
+                        .deploy();
+            }
+            return Result.OK("部署成功");
+        } catch (Exception e) {
+            log.error("部署失败", e);
+            return Result.error("部署失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("删除部署")
+    @DeleteMapping("/delete")
+    public Result<?> delete(@RequestParam String deploymentId) {
+        try {
+            repositoryService.deleteDeployment(deploymentId, true);
+            return Result.OK("删除成功");
+        } catch (Exception e) {
+            log.error("删除失败", e);
+            return Result.error("删除失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("挂起流程定义")
+    @PutMapping("/suspend/{processDefinitionId}")
+    public Result<?> suspend(@PathVariable String processDefinitionId) {
+        try {
+            repositoryService.suspendProcessDefinitionById(processDefinitionId);
+            return Result.OK("已挂起");
+        } catch (Exception e) {
+            log.error("挂起失败", e);
+            return Result.error("挂起失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("激活流程定义")
+    @PutMapping("/activate/{processDefinitionId}")
+    public Result<?> activate(@PathVariable String processDefinitionId) {
+        try {
+            repositoryService.activateProcessDefinitionById(processDefinitionId);
+            return Result.OK("已激活");
+        } catch (Exception e) {
+            log.error("激活失败", e);
+            return Result.error("激活失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("流程图(PNG)")
+    @GetMapping("/diagram/{processDefinitionId}")
+    public void diagram(
+            @ApiParam("流程定义ID") @PathVariable String processDefinitionId,
+            HttpServletResponse response) throws Exception {
+        InputStream is = repositoryService.getProcessDiagram(processDefinitionId);
+        if (is == null) {
+            response.sendError(HttpServletResponse.SC_NOT_FOUND, "无流程图");
+            return;
+        }
+        response.setContentType("image/png");
+        try (OutputStream os = response.getOutputStream()) {
+            byte[] buf = new byte[4096];
+            int len;
+            while ((len = is.read(buf)) != -1) {
+                os.write(buf, 0, len);
+            }
+        } finally {
+            is.close();
+        }
+    }
+}

+ 127 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/controller/ProcessInstanceController.java

@@ -0,0 +1,127 @@
+package org.jeecg.modules.bpm.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
+import org.flowable.engine.HistoryService;
+import org.flowable.engine.IdentityService;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.engine.runtime.ProcessInstanceBuilder;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.modules.bpm.vo.ProcessInstanceVo;
+import org.jeecg.modules.bpm.vo.StartProcessVo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 流程实例(发起/我发起的/撤销)
+ */
+@Slf4j
+@Api(tags = "流程实例")
+@RestController
+@RequestMapping("/bpm/process-instance")
+public class ProcessInstanceController {
+
+    @Autowired
+    private RuntimeService runtimeService;
+    @Autowired
+    private HistoryService historyService;
+    @Autowired
+    private IdentityService identityService;
+
+    @ApiOperation("发起流程")
+    @PostMapping("/start")
+    public Result<ProcessInstanceVo> start(@RequestBody StartProcessVo vo) {
+        String key = vo.getProcessDefinitionIdOrKey();
+        if (key == null || key.isEmpty()) {
+            return Result.error("流程定义 key 不能为空");
+        }
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String userId = user != null ? user.getUsername() : "anonymous";
+        Map<String, Object> variables = vo.getVariables() != null ? vo.getVariables() : new HashMap<>();
+
+        try {
+            identityService.setAuthenticatedUserId(userId);
+            ProcessInstanceBuilder builder = runtimeService.createProcessInstanceBuilder()
+                    .businessKey(vo.getBusinessKey())
+                    .variables(variables);
+            if (key.contains(":")) {
+                builder.processDefinitionId(key);
+            } else {
+                builder.processDefinitionKey(key);
+            }
+            ProcessInstance pi = builder.start();
+            identityService.setAuthenticatedUserId(null);
+
+            ProcessInstanceVo result = new ProcessInstanceVo();
+            result.setId(pi.getId());
+            result.setBusinessKey(pi.getBusinessKey());
+            result.setProcessDefinitionId(pi.getProcessDefinitionId());
+            result.setStartUserId(userId);
+            result.setEnded(false);
+            return Result.OK("发起成功", result);
+        } catch (Exception e) {
+            log.error("发起流程失败", e);
+            return Result.error("发起失败:" + e.getMessage());
+        }
+    }
+
+    @ApiOperation("我发起的列表")
+    @GetMapping("/list")
+    public Result<Map<String, Object>> list(
+            @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+            @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        String userId = user != null ? user.getUsername() : null;
+        if (userId == null) {
+            Map<String, Object> empty = new HashMap<>();
+            empty.put("records", new ArrayList<>());
+            empty.put("total", 0L);
+            return Result.OK(empty);
+        }
+        long total = historyService.createHistoricProcessInstanceQuery()
+                .startedBy(userId)
+                .count();
+        List<org.flowable.engine.history.HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
+                .startedBy(userId)
+                .orderByProcessInstanceStartTime().desc()
+                .listPage((pageNo - 1) * pageSize, pageSize);
+
+        List<ProcessInstanceVo> voList = new ArrayList<>();
+        for (org.flowable.engine.history.HistoricProcessInstance hi : list) {
+            ProcessInstanceVo vo = new ProcessInstanceVo();
+            vo.setId(hi.getId());
+            vo.setBusinessKey(hi.getBusinessKey());
+            vo.setProcessDefinitionId(hi.getProcessDefinitionId());
+            vo.setProcessDefinitionName(hi.getProcessDefinitionName());
+            vo.setStartUserId(hi.getStartUserId());
+            vo.setStartTime(hi.getStartTime());
+            vo.setEnded(hi.getEndTime() != null);
+            voList.add(vo);
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("records", voList);
+        map.put("total", total);
+        return Result.OK(map);
+    }
+
+    @ApiOperation("撤销流程")
+    @PostMapping("/cancel")
+    public Result<?> cancel(@RequestParam String processInstanceId) {
+        try {
+            runtimeService.deleteProcessInstance(processInstanceId, "用户撤销");
+            return Result.OK("已撤销");
+        } catch (Exception e) {
+            log.error("撤销失败", e);
+            return Result.error("撤销失败:" + e.getMessage());
+        }
+    }
+}

+ 46 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/vo/BpmTaskVo.java

@@ -0,0 +1,46 @@
+package org.jeecg.modules.bpm.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 流程任务 VO(待办/已办/任务详情)
+ */
+@Data
+@ApiModel(value = "流程任务", description = "流程任务信息")
+public class BpmTaskVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("任务ID")
+    private String id;
+    @ApiModelProperty("任务名称")
+    private String name;
+    @ApiModelProperty("流程实例ID")
+    private String processInstanceId;
+    @ApiModelProperty("流程定义ID")
+    private String processDefinitionId;
+    @ApiModelProperty("流程定义名称")
+    private String processDefinitionName;
+    @ApiModelProperty("业务Key")
+    private String businessKey;
+    @ApiModelProperty("办理人ID")
+    private String assignee;
+    @ApiModelProperty("办理人姓名")
+    private String assigneeName;
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+    @ApiModelProperty("办理时间(已办)")
+    private Date endTime;
+    @ApiModelProperty("发起人ID")
+    private String startUserId;
+    @ApiModelProperty("发起人姓名")
+    private String startUserName;
+    @ApiModelProperty("流程变量(任务详情用)")
+    private Map<String, Object> variables;
+}

+ 27 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/vo/CompleteTaskVo.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.bpm.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * 办理任务(通过/驳回)请求 VO
+ */
+@Data
+@ApiModel(value = "办理任务", description = "通过或驳回")
+public class CompleteTaskVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "任务ID", required = true)
+    private String taskId;
+    @ApiModelProperty("审批意见")
+    private String comment;
+    @ApiModelProperty("是否通过,true=通过 false=驳回")
+    private Boolean pass;
+    @ApiModelProperty("流程变量,用于下一节点条件或业务,如 approvalResult、amount")
+    private Map<String, Object> variables;
+}

+ 33 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/vo/ProcessDefinitionVo.java

@@ -0,0 +1,33 @@
+package org.jeecg.modules.bpm.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 流程定义列表/详情 VO
+ */
+@Data
+@ApiModel(value = "流程定义", description = "流程定义信息")
+public class ProcessDefinitionVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("流程定义ID")
+    private String id;
+    @ApiModelProperty("流程定义Key")
+    private String key;
+    @ApiModelProperty("流程名称")
+    private String name;
+    @ApiModelProperty("版本")
+    private Integer version;
+    @ApiModelProperty("部署ID")
+    private String deploymentId;
+    @ApiModelProperty("部署时间")
+    private Date deploymentTime;
+    @ApiModelProperty("是否挂起")
+    private Boolean suspended;
+}

+ 35 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/vo/ProcessInstanceVo.java

@@ -0,0 +1,35 @@
+package org.jeecg.modules.bpm.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 流程实例 VO
+ */
+@Data
+@ApiModel(value = "流程实例", description = "流程实例信息")
+public class ProcessInstanceVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("流程实例ID")
+    private String id;
+    @ApiModelProperty("业务Key")
+    private String businessKey;
+    @ApiModelProperty("流程定义ID")
+    private String processDefinitionId;
+    @ApiModelProperty("流程定义名称")
+    private String processDefinitionName;
+    @ApiModelProperty("发起人ID")
+    private String startUserId;
+    @ApiModelProperty("发起人姓名")
+    private String startUserName;
+    @ApiModelProperty("发起时间")
+    private Date startTime;
+    @ApiModelProperty("是否结束")
+    private Boolean ended;
+}

+ 25 - 0
tnc-system/src/main/java/org/jeecg/modules/bpm/vo/StartProcessVo.java

@@ -0,0 +1,25 @@
+package org.jeecg.modules.bpm.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Map;
+
+/**
+ * 发起流程请求 VO
+ */
+@Data
+@ApiModel(value = "发起流程", description = "发起流程请求")
+public class StartProcessVo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "流程定义ID 或 流程定义Key", required = true)
+    private String processDefinitionIdOrKey;
+    @ApiModelProperty("业务Key,关联业务主键")
+    private String businessKey;
+    @ApiModelProperty("流程变量,用于网关条件等,如 amount、level")
+    private Map<String, Object> variables;
+}

+ 32 - 0
tnc-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java

@@ -119,6 +119,38 @@ public class SysDepartController {
 		return result;
 	}
 
+	/**
+	 * 按当前用户数据权限查询部门树:有 departIds 时按多部门权限,否则按当前部门 orgCode 及下级
+	 * 用于赔付单等仅能选择数据权限范围内部门的场景
+	 */
+	@RequestMapping(value = "/queryTreeListByDataPermission", method = RequestMethod.GET)
+	public Result<List<SysDepartTreeModel>> queryTreeListByDataPermission() {
+		Result<List<SysDepartTreeModel>> result = new Result<>();
+		try {
+			LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+			if (user == null) {
+				result.setResult(Collections.emptyList());
+				result.setSuccess(true);
+				return result;
+			}
+			if (StringUtils.isNotBlank(user.getDepartIds())) {
+				List<SysDepartTreeModel> list = sysDepartService.queryMyDeptTreeList(user.getDepartIds());
+				result.setResult(list != null ? list : Collections.emptyList());
+			} else if (StringUtils.isNotBlank(user.getOrgCode())) {
+				List<SysDepartTreeModel> list = sysDepartService.queryTreeListByOrgCode(user.getOrgCode());
+				result.setResult(list != null ? list : Collections.emptyList());
+			} else {
+				result.setResult(Collections.emptyList());
+			}
+			result.setSuccess(true);
+		} catch (Exception e) {
+			log.error(e.getMessage(), e);
+			result.setSuccess(false);
+			result.setResult(Collections.emptyList());
+		}
+		return result;
+	}
+
 	/**
 	 * 异步查询部门list
 	 * @param parentId 父节点 异步加载时传递

+ 112 - 0
tnc-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java

@@ -39,6 +39,7 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
 import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -92,6 +93,15 @@ public class SysUserController {
     @Value("${jeecg.path.upload}")
     private String upLoadPath;
 
+    @Value("${spring.mail.host}")
+    private String mailHost;
+
+    @Value("${spring.mail.port}")
+    private int mailPort;
+
+    @Value("${spring.mail.protocol:smtps}")
+    private String mailProtocol;
+
     @Autowired
     private BaseCommonService baseCommonService;
 
@@ -395,6 +405,25 @@ public class SysUserController {
         return result;
     }
 
+    /**
+     * 重置admin密码(开放接口,无需登录)
+     * 使用完毕后建议删除或注释掉该接口,避免被恶意调用
+     */
+    @RequestMapping(value = "/resetAdminPassword", method = RequestMethod.GET)
+    public Result<?> resetAdminPassword() {
+        SysUser user = sysUserService.getUserByName("admin");
+        if (user == null) {
+            return Result.error("admin用户不存在!");
+        }
+        String salt = oConvertUtils.randomGen(8);
+        String password = "123456";
+        String passwordEncode = PasswordUtil.encrypt(user.getUsername(), password, salt);
+        user.setSalt(salt);
+        user.setPassword(passwordEncode);
+        sysUserService.updateById(user);
+        return Result.ok("admin密码已重置为: " + password);
+    }
+
     /**
      * 修改密码
      */
@@ -1569,4 +1598,87 @@ public class SysUserController {
         return ls;
     }
 
+    /**
+     * 测试邮箱SMTP连接
+     */
+    @RequestMapping(value = "/testEmailConnection", method = RequestMethod.POST)
+    public Result<?> testEmailConnection(@RequestBody JSONObject json) {
+        String mailSecret = json.getString("mailSecret");
+        if (StringUtils.isBlank(mailSecret)) {
+            return Result.error("邮箱密钥不能为空!");
+        }
+        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        if (loginUser == null) {
+            return Result.error("用户未登录!");
+        }
+        // 获取用户邮箱
+        SysUser user = sysUserService.getById(loginUser.getId());
+        if (user == null || StringUtils.isBlank(user.getEmail())) {
+            return Result.error("当前用户未设置邮箱地址,请先在个人信息中设置邮箱!");
+        }
+        try {
+            JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
+            mailSender.setHost(mailHost);
+            mailSender.setPort(mailPort);
+            mailSender.setProtocol(mailProtocol);
+            mailSender.setUsername(user.getEmail());
+            mailSender.setPassword(mailSecret);
+            Properties props = mailSender.getJavaMailProperties();
+            props.put("mail.smtp.auth", "true");
+            props.put("mail.smtp.starttls.enable", "true");
+            props.put("mail.smtp.starttls.required", "true");
+            props.put("mail.smtp.timeout", "10000");
+            props.put("mail.smtp.connectiontimeout", "10000");
+            mailSender.testConnection();
+            return Result.ok("邮箱连接测试成功!");
+        } catch (Exception e) {
+            log.error("邮箱连接测试失败", e);
+            return Result.error("邮箱连接测试失败");
+        }
+    }
+
+    /**
+     * 保存邮箱密钥绑定
+     */
+    @RequestMapping(value = "/bindEmail", method = RequestMethod.PUT)
+    public Result<?> bindEmail(@RequestBody JSONObject json) {
+        String mailSecret = json.getString("mailSecret");
+        if (StringUtils.isBlank(mailSecret)) {
+            return Result.error("邮箱密钥不能为空!");
+        }
+        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        if (loginUser == null) {
+            return Result.error("用户未登录!");
+        }
+        SysUser user = sysUserService.getById(loginUser.getId());
+        if (user == null) {
+            return Result.error("用户不存在!");
+        }
+        if (StringUtils.isBlank(user.getEmail())) {
+            return Result.error("当前用户未设置邮箱地址,请先在个人信息中设置邮箱!");
+        }
+        user.setMailSecret(mailSecret);
+        sysUserService.updateById(user);
+        return Result.ok("邮箱密钥绑定成功!");
+    }
+
+    /**
+     * 查询当前用户邮箱绑定状态
+     */
+    @RequestMapping(value = "/getEmailBinding", method = RequestMethod.GET)
+    public Result<JSONObject> getEmailBinding() {
+        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+        if (loginUser == null) {
+            return Result.error("用户未登录!");
+        }
+        SysUser user = sysUserService.getById(loginUser.getId());
+        if (user == null) {
+            return Result.error("用户不存在!");
+        }
+        JSONObject result = new JSONObject();
+        result.put("email", user.getEmail());
+        result.put("hasBound", StringUtils.isNotBlank(user.getMailSecret()));
+        return Result.OK(result);
+    }
+
 }

+ 6 - 0
tnc-system/src/main/java/org/jeecg/modules/system/entity/SysUser.java

@@ -188,4 +188,10 @@ public class SysUser implements Serializable {
     private String clientId;
 
     private String roleName;
+
+    /**
+     * 用户邮箱SMTP密钥
+     */
+    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+    private String mailSecret;
 }

+ 7 - 0
tnc-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java

@@ -24,6 +24,13 @@ public interface ISysDepartService extends IService<SysDepart>{
      */
     List<SysDepartTreeModel> queryMyDeptTreeList(String departIds);
 
+    /**
+     * 根据部门编码查询本部门及下级部门树(用于数据权限:仅当前部门及子部门)
+     * @param orgCode 部门编码
+     * @return 树形部门列表
+     */
+    List<SysDepartTreeModel> queryTreeListByOrgCode(String orgCode);
+
     /**
      * 查询所有部门信息,并分节点进行显示
      * @return

+ 32 - 0
tnc-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java

@@ -626,6 +626,38 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 		return json;
 	}
 
+	@Override
+	public JSONObject queryAllUserForArchiveSync(Integer pageNo, Integer pageSize) {
+		JSONObject json = new JSONObject();
+		QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>().eq("status", 1).eq("del_flag", 0);
+		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
+		IPage<SysUser> pageList = userMapper.selectPage(page, queryWrapper);
+		com.alibaba.fastjson.JSONArray list = new com.alibaba.fastjson.JSONArray();
+		for (SysUser user : pageList.getRecords()) {
+			JSONObject item = new JSONObject();
+			item.put("id", user.getId());
+			item.put("title", user.getRealname());
+			item.put("email", user.getEmail());
+			item.put("mobile", user.getPhone());
+			item.put("orgCode", user.getOrgCode());
+			String orgName = null;
+			if (oConvertUtils.isNotEmpty(user.getOrgCode())) {
+				String departId = departMapper.queryDepartIdByOrgCode(user.getOrgCode());
+				if (oConvertUtils.isNotEmpty(departId)) {
+					SysDepart depart = sysDepartService.getById(departId);
+					if (depart != null) {
+						orgName = depart.getDepartName();
+					}
+				}
+			}
+			item.put("orgName", orgName);
+			list.add(item);
+		}
+		json.put("list", list);
+		json.put("total", pageList.getTotal());
+		return json;
+	}
+
 	@Override
 	public List<ComboModel> queryAllRole() {
 		List<ComboModel> list = new ArrayList<ComboModel>();

+ 19 - 0
tnc-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java

@@ -83,6 +83,25 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 		return listResult;
 	}
 
+	@Override
+	public List<SysDepartTreeModel> queryTreeListByOrgCode(String orgCode) {
+		if (oConvertUtils.isEmpty(orgCode)) {
+			return new ArrayList<>();
+		}
+		LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
+		query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
+		query.and(w -> w.eq(SysDepart::getOrgCode, orgCode).or().likeRight(SysDepart::getOrgCode, orgCode));
+		query.orderByAsc(SysDepart::getDepartOrder);
+		List<SysDepart> listDepts = this.list(query);
+		for (SysDepart dept : listDepts) {
+			if (orgCode.equals(dept.getOrgCode())) {
+				dept.setParentId(null);
+				break;
+			}
+		}
+		return FindsDepartsChildrenUtil.wrapTreeDataToTreeList(listDepts);
+	}
+
 	/**
 	 * queryTreeList 对应 queryTreeList 查询所有的部门数据,以树结构形式响应给前端
 	 */

+ 7 - 0
tnc-system/src/main/resources/application-prod.yml

@@ -26,12 +26,19 @@ spring:
       max-request-size: 50MB
   mail:
     host: smtp.qq.com
+    port: 465
     username: 1556146884@qq.com
     password: zaidmiapzmnziejh
     properties:
       mail:
         smtp:
           auth: true
+          ssl:
+            enable: true
+          socketFactory:
+            port: 465
+            class: javax.net.ssl.SSLSocketFactory
+            fallback: false
           starttls:
             enable: true
             required: true

+ 18 - 7
tnc-system/src/main/resources/application-test.yml

@@ -26,12 +26,19 @@ spring:
       max-request-size: 50MB
   mail:
     host: smtp.qq.com
-    username: 956901244@qq.com
-    password: fphnaaucbuqvbbbd
+    port: 465
+    username: 1556146884@qq.com
+    password: zaidmiapzmnziejh
     properties:
       mail:
         smtp:
           auth: true
+          ssl:
+            enable: true
+          socketFactory:
+            port: 465
+            class: javax.net.ssl.SSLSocketFactory
+            fallback: false
           starttls:
             enable: true
             required: true
@@ -139,7 +146,7 @@ spring:
           url: jdbc:mysql://127.0.0.1:3306/tnc?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
           #url: jdbc:mysql://223.223.177.220:3306/tnc?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
           username: root
-          password: webyun
+          password: 852852qqqq
           driver-class-name: com.mysql.cj.jdbc.Driver
           # 多数据源配置`噗;'。
           #multi-datasource1:
@@ -219,12 +226,16 @@ jeecg:
       # 配置百度地图的AK,申请地址:https://lbs.baidu.com/apiconsole/key?application=key#/home
       baidu: ??
   # 在线预览文件服务器地址配置
-  file-view-domain: http://223.223.177.220:8012
+  file-view-domain: http://8.162.10.97:8012
   # minio文件上传
   minio:
-    minio_url: http://223.223.177.220:9001
-    minio_name: minioadmin
-    minio_pass: minioadmin
+    #minio_url: http://223.223.177.220:9001
+    #minio_name: minioadmin
+    #minio_pass: minioadmin
+    #bucketName: default
+    minio_url: http://8.162.10.97:9000
+    minio_name: myrootuser
+    minio_pass: mystrongpassword
     bucketName: default
   #大屏报表参数设置
   jmreport:

+ 14 - 1
tnc-system/src/main/resources/application.yml

@@ -2,4 +2,17 @@ spring:
   application:
     name: tnc-system
   profiles:
-    active: test
+    active: test
+
+# Flowable 配置
+flowable:
+  # 关闭 flowable 自带的 id 生成(由 Jeecg 接管或使用默认)
+  db-identity-used: false
+  # 自动创建/更新数据库表
+  database-schema-update: true
+  # 流程图字体配置(防止 Linux 环境乱码)
+  activity-font-name: "宋体"
+  label-font-name: "宋体"
+  annotation-font-name: "宋体"
+  # 异步执行器配置
+  async-executor-activate: true

+ 23 - 0
tnc-system/src/main/resources/bpm/sample-approve.bpmn20.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
+             xmlns:flowable="http://flowable.org/bpmn"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             targetNamespace="http://www.flowable.org/processdef">
+  <process id="sampleApprove" name="示例审批流程" isExecutable="true">
+    <startEvent id="start" name="开始"/>
+    <userTask id="taskApprove" name="审批" flowable:assignee="${assignee}">
+      <documentation>审批人:发起时或监听器中设置 assignee 变量为系统用户 id</documentation>
+    </userTask>
+    <exclusiveGateway id="gateway1" name="按金额分支"/>
+    <sequenceFlow sourceRef="start" targetRef="taskApprove"/>
+    <sequenceFlow sourceRef="taskApprove" targetRef="gateway1"/>
+    <sequenceFlow sourceRef="gateway1" targetRef="endHigh" name="高金额">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${amount != null && amount > 10000}]]></conditionExpression>
+    </sequenceFlow>
+    <sequenceFlow sourceRef="gateway1" targetRef="endLow" name="低金额">
+      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${amount == null || amount <= 10000}]]></conditionExpression>
+    </sequenceFlow>
+    <endEvent id="endHigh" name="高金额结束"/>
+    <endEvent id="endLow" name="低金额结束"/>
+  </process>
+</definitions>

Vissa filer visades inte eftersom för många filer har ändrats