Commit ba3fe15ec5d65d140e2fce416349ab01a571b22f
Merge branch 'develop' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk21
Showing
544 changed files
with
11761 additions
and
5517 deletions
Too many changes.
To preserve performance only 100 of 544 files are displayed.
README.md
pom.xml
| ... | ... | @@ -15,13 +15,13 @@ |
| 15 | 15 | <!-- 各种 module 拓展 --> |
| 16 | 16 | <module>yudao-module-system</module> |
| 17 | 17 | <module>yudao-module-infra</module> |
| 18 | -<!-- <module>yudao-module-member</module>--> | |
| 18 | + <module>yudao-module-member</module> | |
| 19 | 19 | <!-- <module>yudao-module-bpm</module>--> |
| 20 | 20 | <!-- <module>yudao-module-report</module>--> |
| 21 | 21 | <!-- <module>yudao-module-mp</module>--> |
| 22 | -<!-- <module>yudao-module-pay</module>--> | |
| 23 | -<!-- <module>yudao-module-mall</module>--> | |
| 24 | -<!-- <module>yudao-module-crm</module>--> | |
| 22 | + <module>yudao-module-pay</module> | |
| 23 | + <module>yudao-module-mall</module> | |
| 24 | + <module>yudao-module-crm</module> | |
| 25 | 25 | <!-- 示例项目 --> |
| 26 | 26 | <!-- <module>yudao-example</module>--> |
| 27 | 27 | </modules> | ... | ... |
sql/mysql/Ureport.sql renamed to sql/mysql/optinal/Ureport.sql
sql/mysql/optinal/crm.sql deleted
| 1 | --- `ruoyi-vue-pro`.crm_contact_business_link definition | |
| 2 | - | |
| 3 | -CREATE TABLE `crm_contact_business_link` ( | |
| 4 | - `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', | |
| 5 | - `contact_id` int(11) DEFAULT NULL COMMENT '联系人id', | |
| 6 | - `business_id` int(11) DEFAULT NULL COMMENT '商机id', | |
| 7 | - `creator` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者', | |
| 8 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 9 | - `updater` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者', | |
| 10 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 11 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 12 | - `tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户编号', | |
| 13 | - PRIMARY KEY (`id`), | |
| 14 | - UNIQUE KEY `crm_contact_business_link_un` (`contact_id`,`business_id`,`deleted`,`tenant_id`) | |
| 15 | -) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='联系人商机关联表'; | |
| 16 | 0 | \ No newline at end of file |
sql/mysql/optinal/mall.sql deleted
sql/mysql/optinal/pay_wallet.sql deleted
| 1 | --- ---------------------------- | |
| 2 | --- 转账单表 | |
| 3 | --- ---------------------------- | |
| 4 | -DROP TABLE IF EXISTS `pay_transfer`; | |
| 5 | -CREATE TABLE `pay_transfer` | |
| 6 | -( | |
| 7 | - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', | |
| 8 | - `no` varchar(64) NOT NULL COMMENT '转账单号', | |
| 9 | - `app_id` bigint NOT NULL COMMENT '应用编号', | |
| 10 | - `channel_id` bigint NOT NULL COMMENT '转账渠道编号', | |
| 11 | - `channel_code` varchar(32) NOT NULL COMMENT '转账渠道编码', | |
| 12 | - `merchant_transfer_id` varchar(64) NOT NULL COMMENT '商户转账单编号', | |
| 13 | - `type` int NOT NULL COMMENT '类型', | |
| 14 | - `status` tinyint NOT NULL COMMENT '转账状态', | |
| 15 | - `success_time` datetime NULL COMMENT '转账成功时间', | |
| 16 | - `price` int NOT NULL COMMENT '转账金额,单位:分', | |
| 17 | - `subject` varchar(512) NOT NULL COMMENT '转账标题', | |
| 18 | - `user_name` varchar(64) NULL COMMENT '收款人姓名', | |
| 19 | - `alipay_logon_id` varchar(64) NULL COMMENT '支付宝登录号', | |
| 20 | - `openid` varchar(64) NULL COMMENT '微信 openId', | |
| 21 | - `notify_url` varchar(1024) NOT NULL COMMENT '异步通知商户地址', | |
| 22 | - `user_ip` varchar(50) NOT NULL COMMENT '用户 IP', | |
| 23 | - `channel_extras` varchar(512) NULL DEFAULT NULL COMMENT '渠道的额外参数', | |
| 24 | - `channel_transfer_no` varchar(64) NULL DEFAULT NULL COMMENT '渠道转账单号', | |
| 25 | - `channel_error_code` varchar(128) NULL DEFAULT NULL COMMENT '调用渠道的错误码', | |
| 26 | - `channel_error_msg` varchar(256) NULL DEFAULT NULL COMMENT '调用渠道的错误提示', | |
| 27 | - `channel_notify_data` varchar(4096) NULL DEFAULT NULL COMMENT '渠道的同步/异步通知的内容', | |
| 28 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', | |
| 29 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 30 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | |
| 31 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 32 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 33 | - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | |
| 34 | - PRIMARY KEY (`id`) USING BTREE | |
| 35 | -) ENGINE=InnoDB COMMENT='转账单表'; | |
| 36 | - | |
| 37 | --- ---------------------------- | |
| 38 | --- Table structure for pay_demo_transfer | |
| 39 | --- ---------------------------- | |
| 40 | -DROP TABLE IF EXISTS `pay_demo_transfer`; | |
| 41 | -CREATE TABLE `pay_demo_transfer` ( | |
| 42 | - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '订单编号', | |
| 43 | - `app_id` bigint NOT NULL COMMENT '应用编号', | |
| 44 | - `type` int NOT NULL COMMENT '转账类型', | |
| 45 | - `price` int NOT NULL COMMENT '转账金额,单位:分', | |
| 46 | - `user_name` varchar(64) NULL COMMENT '收款人姓名', | |
| 47 | - `alipay_logon_id` varchar(64) NULL COMMENT '支付宝登录号', | |
| 48 | - `openid` varchar(64) NULL COMMENT '微信 openId', | |
| 49 | - `transfer_status` tinyint NOT NULL DEFAULT 0 COMMENT '转账状态', | |
| 50 | - `pay_transfer_id` bigint NULL DEFAULT NULL COMMENT '转账订单编号', | |
| 51 | - `pay_channel_code` varchar(16) NULL DEFAULT NULL COMMENT '转账支付成功渠道', | |
| 52 | - `transfer_time` datetime NULL DEFAULT NULL COMMENT '转账支付时间', | |
| 53 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '' COMMENT '创建者', | |
| 54 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 55 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '' COMMENT '更新者', | |
| 56 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 57 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 58 | - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | |
| 59 | - PRIMARY KEY (`id`) USING BTREE | |
| 60 | -) ENGINE = InnoDB COMMENT = '示例业务转账订单'; | |
| 61 | - | |
| 62 | - | |
| 63 | --- ALTER TABLE `pay_channel` | |
| 64 | --- MODIFY COLUMN `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '支付渠道配置' AFTER `app_id`; | |
| 65 | - | |
| 66 | --- ---------------------------- | |
| 67 | --- 充值套餐表 | |
| 68 | --- ---------------------------- | |
| 69 | -DROP TABLE IF EXISTS `pay_wallet_recharge_package`; | |
| 70 | -CREATE TABLE `pay_wallet_recharge_package` | |
| 71 | -( | |
| 72 | - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', | |
| 73 | - `name` varchar(64) NOT NULL COMMENT '套餐名', | |
| 74 | - `pay_price` int NOT NULL COMMENT '支付金额', | |
| 75 | - `bonus_price` int NOT NULL COMMENT '赠送金额', | |
| 76 | - `status` tinyint NOT NULL COMMENT '状态', | |
| 77 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT '' COMMENT '创建者', | |
| 78 | - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 79 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', | |
| 80 | - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', | |
| 81 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 82 | - `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', | |
| 83 | - PRIMARY KEY (`id`) USING BTREE | |
| 84 | -) ENGINE=InnoDB COMMENT='充值套餐表'; | |
| 85 | - | |
| 86 | --- ---------------------------- | |
| 87 | --- Table structure for pay_wallet_recharge | |
| 88 | --- ---------------------------- | |
| 89 | -DROP TABLE IF EXISTS `pay_wallet_recharge`; | |
| 90 | -CREATE TABLE `pay_wallet_recharge` ( | |
| 91 | - `id` bigint(0) NOT NULL AUTO_INCREMENT COMMENT '编号', | |
| 92 | - `wallet_id` bigint(0) NOT NULL COMMENT '会员钱包 id', | |
| 93 | - `total_price` int(0) NOT NULL COMMENT '用户实际到账余额,例如充 100 送 20,则该值是 120', | |
| 94 | - `pay_price` int(0) NOT NULL COMMENT '实际支付金额', | |
| 95 | - `bonus_price` int(0) NOT NULL COMMENT '钱包赠送金额', | |
| 96 | - `package_id` bigint(0) DEFAULT NULL COMMENT '充值套餐编号', | |
| 97 | - `pay_status` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已支付:[0:未支付 1:已经支付过]', | |
| 98 | - `pay_order_id` bigint(0) DEFAULT NULL COMMENT '支付订单编号', | |
| 99 | - `pay_channel_code` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '支付成功的支付渠道', | |
| 100 | - `pay_time` datetime(0) DEFAULT NULL COMMENT '订单支付时间', | |
| 101 | - `pay_refund_id` bigint(0) DEFAULT NULL COMMENT '支付退款单编号', | |
| 102 | - `refund_total_price` int(0) NOT NULL DEFAULT 0 COMMENT '退款金额,包含赠送金额', | |
| 103 | - `refund_pay_price` int(0) NOT NULL DEFAULT 0 COMMENT '退款支付金额', | |
| 104 | - `refund_bonus_price` int(0) NOT NULL DEFAULT 0 COMMENT '退款钱包赠送金额', | |
| 105 | - `refund_time` datetime(0) DEFAULT NULL COMMENT '退款时间', | |
| 106 | - `refund_status` int(0) NOT NULL DEFAULT 0 COMMENT '退款状态', | |
| 107 | - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者', | |
| 108 | - `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', | |
| 109 | - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者', | |
| 110 | - `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间', | |
| 111 | - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', | |
| 112 | - `tenant_id` bigint(0) NOT NULL DEFAULT 0 COMMENT '租户编号', | |
| 113 | - PRIMARY KEY (`id`) USING BTREE | |
| 114 | -) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '会员钱包充值' ROW_FORMAT = Dynamic; | |
| 115 | - | |
| 116 | --- 钱包充值套餐,钱包余额菜单脚本 | |
| 117 | - | |
| 118 | -INSERT INTO system_menu( | |
| 119 | - name, permission, type, sort, parent_id, | |
| 120 | - path, icon, component, status, component_name | |
| 121 | -) | |
| 122 | -VALUES ( | |
| 123 | - '钱包管理', '', 1, 5, 1117, | |
| 124 | - 'wallet', 'ep:caret-right', '', 0, '' | |
| 125 | - ); | |
| 126 | -SELECT @parentId1 := LAST_INSERT_ID(); | |
| 127 | - | |
| 128 | -INSERT INTO system_menu( | |
| 129 | - name, permission, type, sort, parent_id, | |
| 130 | - path, icon, component, status, component_name | |
| 131 | -) | |
| 132 | -VALUES ( | |
| 133 | - '充值套餐', '', 2, 2, @parentId1, | |
| 134 | - 'wallet-recharge-package', 'fa:leaf', 'pay/wallet/rechargePackage/index', 0, 'WalletRechargePackage' | |
| 135 | - ); | |
| 136 | -SELECT @parentId := LAST_INSERT_ID(); | |
| 137 | - | |
| 138 | --- 按钮 SQL | |
| 139 | -INSERT INTO system_menu( | |
| 140 | - name, permission, type, sort, parent_id, | |
| 141 | - path, icon, component, status | |
| 142 | -) | |
| 143 | -VALUES ( | |
| 144 | - '钱包充值套餐查询', 'pay:wallet-recharge-package:query', 3, 1, @parentId, | |
| 145 | - '', '', '', 0 | |
| 146 | - ); | |
| 147 | -INSERT INTO system_menu( | |
| 148 | - name, permission, type, sort, parent_id, | |
| 149 | - path, icon, component, status | |
| 150 | -) | |
| 151 | -VALUES ( | |
| 152 | - '钱包充值套餐创建', 'pay:wallet-recharge-package:create', 3, 2, @parentId, | |
| 153 | - '', '', '', 0 | |
| 154 | - ); | |
| 155 | -INSERT INTO system_menu( | |
| 156 | - name, permission, type, sort, parent_id, | |
| 157 | - path, icon, component, status | |
| 158 | -) | |
| 159 | -VALUES ( | |
| 160 | - '钱包充值套餐更新', 'pay:wallet-recharge-package:update', 3, 3, @parentId, | |
| 161 | - '', '', '', 0 | |
| 162 | - ); | |
| 163 | -INSERT INTO system_menu( | |
| 164 | - name, permission, type, sort, parent_id, | |
| 165 | - path, icon, component, status | |
| 166 | -) | |
| 167 | -VALUES ( | |
| 168 | - '钱包充值套餐删除', 'pay:wallet-recharge-package:delete', 3, 4, @parentId, | |
| 169 | - '', '', '', 0 | |
| 170 | - ); | |
| 171 | - | |
| 172 | -INSERT INTO system_menu( | |
| 173 | - name, permission, type, sort, parent_id, | |
| 174 | - path, icon, component, status, component_name | |
| 175 | -) | |
| 176 | -VALUES ( | |
| 177 | - '钱包余额', '', 2, 1, @parentId1, | |
| 178 | - 'wallet-balance', 'fa:leaf', 'pay/wallet/balance/index', 0, 'WalletBalance' | |
| 179 | - ); | |
| 180 | - | |
| 181 | -SELECT @parentId := LAST_INSERT_ID(); | |
| 182 | - | |
| 183 | --- 按钮 SQL | |
| 184 | -INSERT INTO system_menu( | |
| 185 | - name, permission, type, sort, parent_id, | |
| 186 | - path, icon, component, status | |
| 187 | -) | |
| 188 | -VALUES ( | |
| 189 | - '钱包余额查询', 'pay:wallet:query', 3, 1, @parentId, | |
| 190 | - '', '', '', 0 | |
| 191 | - ); | |
| 192 | - | |
| 193 | --- 支付实战和转账实战数据库脚本 | |
| 194 | - | |
| 195 | -update system_menu set deleted = 1 where id = 2161; | |
| 196 | - | |
| 197 | -INSERT INTO system_menu( | |
| 198 | - name, permission, type, sort, parent_id, | |
| 199 | - path, icon, component, status, component_name | |
| 200 | -) | |
| 201 | -VALUES ( | |
| 202 | - '接入示例', '', 1, 99, 1117, | |
| 203 | - 'demo', 'ep:caret-right', '', 0, '' | |
| 204 | - ); | |
| 205 | - | |
| 206 | -SELECT @parentId1 := LAST_INSERT_ID(); | |
| 207 | - | |
| 208 | -INSERT INTO system_menu( | |
| 209 | - name, permission, type, sort, parent_id, | |
| 210 | - path, icon, component, status, component_name | |
| 211 | -) | |
| 212 | -VALUES ( | |
| 213 | - '支付实战', '', 2, 1, @parentId1, | |
| 214 | - 'demo-order', 'fa:leaf', 'pay/demo/order/index', 0, NULL | |
| 215 | - ); | |
| 216 | - | |
| 217 | -INSERT INTO system_menu( | |
| 218 | - name, permission, type, sort, parent_id, | |
| 219 | - path, icon, component, status, component_name | |
| 220 | -) | |
| 221 | -VALUES ( | |
| 222 | - '转账实战', '', 2, 1, @parentId1, | |
| 223 | - 'demo-transfer', 'fa:leaf', 'pay/demo/transfer/index', 0, NULL | |
| 224 | - ); | |
| 225 | - | |
| 226 | --- 转账状态和转账类型数据字典 | |
| 227 | -INSERT INTO `system_dict_type`(`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES ('支付转账类型', 'pay_transfer_type', 0, '', '1', '2023-10-28 16:27:18', '1', '2023-10-28 16:27:18', b'0', '1970-01-01 00:00:00'); | |
| 228 | -INSERT INTO `system_dict_type`(`name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES ('转账订单状态', 'pay_transfer_status', 0, '', '1', '2023-10-28 16:18:32', '1', '2023-10-28 16:18:32', b'0', '1970-01-01 00:00:00'); | |
| 229 | - | |
| 230 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '钱包余额', '4', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:37', '1', '2023-10-28 16:28:37', b'0'); | |
| 231 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '银行卡', '3', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:28:21', '1', '2023-10-28 16:28:21', b'0'); | |
| 232 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '微信余额', '2', 'pay_transfer_type', 0, 'info', '', '', '1', '2023-10-28 16:28:07', '1', '2023-10-28 16:28:07', b'0'); | |
| 233 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '支付宝余额', '1', 'pay_transfer_type', 0, 'default', '', '', '1', '2023-10-28 16:27:44', '1', '2023-10-28 16:27:44', b'0'); | |
| 234 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (4, '转账失败', '30', 'pay_transfer_status', 0, 'warning', '', '', '1', '2023-10-28 16:24:16', '1', '2023-10-28 16:24:16', b'0'); | |
| 235 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (3, '转账成功', '20', 'pay_transfer_status', 0, 'success', '', '', '1', '2023-10-28 16:23:50', '1', '2023-10-28 16:23:50', b'0'); | |
| 236 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, '转账进行中', '10', 'pay_transfer_status', 0, 'info', '', '', '1', '2023-10-28 16:23:12', '1', '2023-10-28 16:23:12', b'0'); | |
| 237 | -INSERT INTO `system_dict_data`(`sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '等待转账', '0', 'pay_transfer_status', 0, 'default', '', '', '1', '2023-10-28 16:21:43', '1', '2023-10-28 16:23:22', b'0'); | |
| 238 | - | |
| 239 | --- 转账订单菜单脚本 | |
| 240 | - | |
| 241 | -INSERT INTO system_menu( | |
| 242 | - name, permission, type, sort, parent_id, | |
| 243 | - path, icon, component, status, component_name | |
| 244 | -) | |
| 245 | -VALUES ( | |
| 246 | - '转账订单', '', 2, 3, 1117, | |
| 247 | - 'transfer', 'ep:credit-card', 'pay/transfer/index', 0, 'PayTransfer' | |
| 248 | - ); | |
| 249 | - | |
| 250 | --- 转账通知脚本 | |
| 251 | - | |
| 252 | -ALTER TABLE `pay_app` | |
| 253 | - ADD COLUMN `transfer_notify_url` varchar(1024) NOT NULL COMMENT '转账结果的回调地址' AFTER `refund_notify_url`; | |
| 254 | -ALTER TABLE `pay_notify_task` | |
| 255 | - MODIFY COLUMN `merchant_order_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci COMMENT '商户订单编号' AFTER `status`, | |
| 256 | - ADD COLUMN `merchant_transfer_id` varchar(64) COMMENT '商户转账单编号' AFTER `merchant_order_id`; | |
| 257 | 0 | \ No newline at end of file |
sql/mysql/ruoyi-vue-pro.sql
| ... | ... | @@ -2370,6 +2370,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i |
| 2370 | 2370 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2369, '拼团记录', 'promotion:combination-record:query', 2, 2, 2303, 'record', 'ep:avatar', 'mall/promotion/combination/record/index.vue', 'PromotionCombinationRecord', 0, b'1', b'1', b'1', '1', '2023-10-08 07:10:22', '1', '2023-10-08 07:34:11', b'0'); |
| 2371 | 2371 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2374, '会员统计', '', 2, 2, 2358, 'member', 'ep:avatar', 'statistics/member/index', 'MemberStatistics', 0, b'1', b'1', b'1', '', '2023-10-11 04:39:24', '1', '2023-10-11 12:50:22', b'0'); |
| 2372 | 2372 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2375, '会员统计查询', 'statistics:member:query', 3, 1, 2374, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-11 04:39:24', '', '2023-10-11 04:39:24', b'0'); |
| 2373 | +--此处缺少trade:order:query 和 trade:order:update权限,会导致订单的发货和更多按钮无法显示。 | |
| 2373 | 2374 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2376, '订单核销', 'trade:order:pick-up', 3, 10, 2076, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-10-14 17:11:58', '1', '2023-10-14 17:11:58', b'0'); |
| 2374 | 2375 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2377, '文章分类', '', 2, 0, 2387, 'article/category', 'fa:certificate', 'mall/promotion/article/category/index', 'ArticleCategory', 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '1', '2023-10-16 09:38:26', b'0'); |
| 2375 | 2376 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2378, '分类查询', 'promotion:article-category:query', 3, 1, 2377, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-10-16 01:26:18', '', '2023-10-16 01:26:18', b'0'); |
| ... | ... | @@ -2478,6 +2479,15 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i |
| 2478 | 2479 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2523, '客户限制配置导出', 'crm:customer-limit-config:export', 3, 5, 2518, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-18 13:33:53', '', '2023-11-18 13:33:53', b'0'); |
| 2479 | 2480 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2524, '系统配置', '', 1, 99, 2397, 'config', 'ep:connection', '', '', 0, b'1', b'1', b'1', '1', '2023-11-18 21:58:00', '1', '2023-11-18 21:58:00', b'0'); |
| 2480 | 2481 | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2525, 'WebSocket 测试', '', 2, 7, 2, 'websocket', 'ep:connection', 'infra/webSocket/index', 'InfraWebSocket', 0, b'1', b'1', b'1', '1', '2023-11-23 19:41:55', '1', '2023-11-24 19:22:30', b'0'); |
| 2482 | +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, | |
| 2483 | + `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, | |
| 2484 | + `updater`, `update_time`, `deleted`) | |
| 2485 | +VALUES (2526, '抄送流程', '', 2, 21, 1200, 'processInstanceCC', 'eye', '/bpm/task/cc/index', | |
| 2486 | + 'BpmCCProcessInstance', 0, true, true, true, 1, '2023-01-13 16:14:00', '1', '2023-01-13 16:14:00', false), | |
| 2487 | + (2527, '抄送流程查询', 'bpm:process-instance-cc:query', 3, 1, 2526, '', '', '', NULL, 0, b'1', b'1', b'1', '1', | |
| 2488 | + '2023-01-13 16:14:00', '1', '2023-01-13 16:14:00', b'0'), | |
| 2489 | + (2528, '抄送流程创建', 'bpm:process-instance-cc:create', 3, 2, 2526, '', '', '', NULL, 0, b'1', b'1', b'1', '1', | |
| 2490 | + '2023-01-13 16:14:00', '1', '2023-01-13 16:14:00', b'0'); | |
| 2481 | 2491 | COMMIT; |
| 2482 | 2492 | |
| 2483 | 2493 | -- ---------------------------- | ... | ... |
yudao-dependencies/pom.xml
| ... | ... | @@ -26,7 +26,7 @@ |
| 26 | 26 | <mybatis-plus.version>3.5.4.1</mybatis-plus.version> |
| 27 | 27 | <mybatis-plus-generator.version>3.5.4.1</mybatis-plus-generator.version> |
| 28 | 28 | <dynamic-datasource.version>4.2.0</dynamic-datasource.version> |
| 29 | - <mybatis-plus-join.version>1.4.7.2</mybatis-plus-join.version> | |
| 29 | + <mybatis-plus-join.version>1.4.8.1</mybatis-plus-join.version> | |
| 30 | 30 | <redisson.version>3.25.0</redisson.version> |
| 31 | 31 | <dm8.jdbc.version>8.1.3.62</dm8.jdbc.version> |
| 32 | 32 | <!-- 消息队列 --> |
| ... | ... | @@ -62,6 +62,7 @@ |
| 62 | 62 | <jsch.version>0.1.55</jsch.version> |
| 63 | 63 | <tika-core.version>2.9.1</tika-core.version> |
| 64 | 64 | <ip2region.version>2.7.0</ip2region.version> |
| 65 | + <bizlog-sdk.version>3.0.6</bizlog-sdk.version> | |
| 65 | 66 | <!-- 三方云服务相关 --> |
| 66 | 67 | <okio.version>3.5.0</okio.version> |
| 67 | 68 | <okhttp3.version>4.11.0</okhttp3.version> |
| ... | ... | @@ -100,6 +101,17 @@ |
| 100 | 101 | <version>${revision}</version> |
| 101 | 102 | </dependency> |
| 102 | 103 | <dependency> |
| 104 | + <groupId>io.github.mouzt</groupId> | |
| 105 | + <artifactId>bizlog-sdk</artifactId> | |
| 106 | + <version>${bizlog-sdk.version}</version> | |
| 107 | + <exclusions> | |
| 108 | + <exclusion> <!-- 排除掉springboot依赖使用项目的 --> | |
| 109 | + <groupId>org.springframework.boot</groupId> | |
| 110 | + <artifactId>spring-boot-starter</artifactId> | |
| 111 | + </exclusion> | |
| 112 | + </exclusions> | |
| 113 | + </dependency> | |
| 114 | + <dependency> | |
| 103 | 115 | <groupId>cn.iocoder.boot</groupId> |
| 104 | 116 | <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> |
| 105 | 117 | <version>${revision}</version> | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/TerminalEnum.java
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuCreateOrUpdateReqVO.java renamed to yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/SortablePageParam.java
100755 → 100644
| 1 | -package cn.iocoder.yudao.module.product.controller.admin.sku.vo; | |
| 1 | +package cn.iocoder.yudao.framework.common.pojo; | |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 4 | import lombok.Data; |
| ... | ... | @@ -7,10 +7,13 @@ import lombok.ToString; |
| 7 | 7 | |
| 8 | 8 | import java.util.List; |
| 9 | 9 | |
| 10 | -@Schema(description = "管理后台 - 商品 SKU 创建/更新 Request VO") | |
| 10 | +@Schema(description = "可排序的分页参数") | |
| 11 | 11 | @Data |
| 12 | 12 | @EqualsAndHashCode(callSuper = true) |
| 13 | 13 | @ToString(callSuper = true) |
| 14 | -public class ProductSkuCreateOrUpdateReqVO extends ProductSkuBaseVO { | |
| 14 | +public class SortablePageParam extends PageParam { | |
| 15 | 15 | |
| 16 | -} | |
| 16 | + @Schema(description = "排序字段") | |
| 17 | + private List<SortingField> sortingFields; | |
| 18 | + | |
| 19 | +} | |
| 17 | 20 | \ No newline at end of file | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/DateUtils.java
| ... | ... | @@ -177,4 +177,14 @@ public class DateUtils { |
| 177 | 177 | return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now()); |
| 178 | 178 | } |
| 179 | 179 | |
| 180 | + /** | |
| 181 | + * 是否昨天 | |
| 182 | + * | |
| 183 | + * @param date 日期 | |
| 184 | + * @return 是否 | |
| 185 | + */ | |
| 186 | + public static boolean isYesterday(LocalDateTime date) { | |
| 187 | + return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now().minusDays(1)); | |
| 188 | + } | |
| 189 | + | |
| 180 | 190 | } | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
| ... | ... | @@ -6,6 +6,7 @@ import java.time.Duration; |
| 6 | 6 | import java.time.LocalDate; |
| 7 | 7 | import java.time.LocalDateTime; |
| 8 | 8 | import java.time.LocalTime; |
| 9 | +import java.time.temporal.ChronoUnit; | |
| 9 | 10 | import java.time.temporal.TemporalAdjusters; |
| 10 | 11 | |
| 11 | 12 | /** |
| ... | ... | @@ -121,4 +122,14 @@ public class LocalDateTimeUtils { |
| 121 | 122 | return date.with(TemporalAdjusters.lastDayOfMonth()).with(LocalTime.MAX); |
| 122 | 123 | } |
| 123 | 124 | |
| 125 | + /** | |
| 126 | + * 获取指定日期到现在过了几天,如果指定日期在当前日期之后,获取结果为负 | |
| 127 | + * | |
| 128 | + * @param dateTime 日期 | |
| 129 | + * @return 相差天数 | |
| 130 | + */ | |
| 131 | + public static Long between(LocalDateTime dateTime) { | |
| 132 | + return LocalDateTimeUtil.between(dateTime, LocalDateTime.now(), ChronoUnit.DAYS); | |
| 133 | + } | |
| 134 | + | |
| 124 | 135 | } | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java
| ... | ... | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 6 | 6 | |
| 7 | 7 | import java.util.List; |
| 8 | +import java.util.function.Consumer; | |
| 8 | 9 | |
| 9 | 10 | /** |
| 10 | 11 | * Bean 工具类 |
| ... | ... | @@ -20,6 +21,14 @@ public class BeanUtils { |
| 20 | 21 | return BeanUtil.toBean(source, targetClass); |
| 21 | 22 | } |
| 22 | 23 | |
| 24 | + public static <T> T toBean(Object source, Class<T> targetClass, Consumer<T> peek) { | |
| 25 | + T target = toBean(source, targetClass); | |
| 26 | + if (target != null) { | |
| 27 | + peek.accept(target); | |
| 28 | + } | |
| 29 | + return target; | |
| 30 | + } | |
| 31 | + | |
| 23 | 32 | public static <S, T> List<T> toBean(List<S> source, Class<T> targetType) { |
| 24 | 33 | if (source == null) { |
| 25 | 34 | return null; |
| ... | ... | @@ -27,11 +36,27 @@ public class BeanUtils { |
| 27 | 36 | return CollectionUtils.convertList(source, s -> toBean(s, targetType)); |
| 28 | 37 | } |
| 29 | 38 | |
| 30 | - public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType) { | |
| 39 | + public static <S, T> List<T> toBean(List<S> source, Class<T> targetType, Consumer<T> peek) { | |
| 40 | + List<T> list = toBean(source, targetType); | |
| 41 | + if (list != null) { | |
| 42 | + list.forEach(peek); | |
| 43 | + } | |
| 44 | + return list; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType) { | |
| 48 | + return toBean(source, targetType, null); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType, Consumer<T> peek) { | |
| 31 | 52 | if (source == null) { |
| 32 | 53 | return null; |
| 33 | 54 | } |
| 34 | - return new PageResult<>(toBean(source.getList(), targetType), source.getTotal()); | |
| 55 | + List<T> list = toBean(source.getList(), targetType); | |
| 56 | + if (peek != null) { | |
| 57 | + list.forEach(peek); | |
| 58 | + } | |
| 59 | + return new PageResult<>(list, source.getTotal()); | |
| 35 | 60 | } |
| 36 | 61 | |
| 37 | 62 | } |
| 38 | 63 | \ No newline at end of file | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/PageUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.common.util.object; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.lang.func.Func1; | |
| 5 | +import cn.hutool.core.lang.func.LambdaUtil; | |
| 6 | +import cn.hutool.core.util.ArrayUtil; | |
| 3 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 8 | +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; | |
| 9 | +import cn.iocoder.yudao.framework.common.pojo.SortingField; | |
| 10 | +import org.springframework.util.Assert; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 4 | 13 | |
| 5 | 14 | /** |
| 6 | 15 | * {@link cn.iocoder.yudao.framework.common.pojo.PageParam} 工具类 |
| ... | ... | @@ -9,8 +18,50 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 9 | 18 | */ |
| 10 | 19 | public class PageUtils { |
| 11 | 20 | |
| 21 | + private static final Object[] ORDER_TYPES = new String[]{SortingField.ORDER_ASC, SortingField.ORDER_DESC}; | |
| 22 | + | |
| 12 | 23 | public static int getStart(PageParam pageParam) { |
| 13 | 24 | return (pageParam.getPageNo() - 1) * pageParam.getPageSize(); |
| 14 | 25 | } |
| 15 | 26 | |
| 27 | + /** | |
| 28 | + * 构建排序字段(默认倒序) | |
| 29 | + * | |
| 30 | + * @param func 排序字段的 Lambda 表达式 | |
| 31 | + * @param <T> 排序字段所属的类型 | |
| 32 | + * @return 排序字段 | |
| 33 | + */ | |
| 34 | + public static <T> SortingField buildSortingField(Func1<T, ?> func) { | |
| 35 | + return buildSortingField(func, SortingField.ORDER_DESC); | |
| 36 | + } | |
| 37 | + | |
| 38 | + /** | |
| 39 | + * 构建排序字段 | |
| 40 | + * | |
| 41 | + * @param func 排序字段的 Lambda 表达式 | |
| 42 | + * @param order 排序类型 {@link SortingField#ORDER_ASC} {@link SortingField#ORDER_DESC} | |
| 43 | + * @param <T> 排序字段所属的类型 | |
| 44 | + * @return 排序字段 | |
| 45 | + */ | |
| 46 | + public static <T> SortingField buildSortingField(Func1<T, ?> func, String order) { | |
| 47 | + Assert.isTrue(ArrayUtil.contains(ORDER_TYPES, order), String.format("字段的排序类型只能是 %s/%s", ORDER_TYPES)); | |
| 48 | + | |
| 49 | + String fieldName = LambdaUtil.getFieldName(func); | |
| 50 | + return new SortingField(fieldName, order); | |
| 51 | + } | |
| 52 | + | |
| 53 | + /** | |
| 54 | + * 构建默认的排序字段 | |
| 55 | + * 如果排序字段为空,则设置排序字段;否则忽略 | |
| 56 | + * | |
| 57 | + * @param sortablePageParam 排序分页查询参数 | |
| 58 | + * @param func 排序字段的 Lambda 表达式 | |
| 59 | + * @param <T> 排序字段所属的类型 | |
| 60 | + */ | |
| 61 | + public static <T> void buildDefaultSortingField(SortablePageParam sortablePageParam, Func1<T, ?> func) { | |
| 62 | + if (sortablePageParam != null && CollUtil.isEmpty(sortablePageParam.getSortingFields())) { | |
| 63 | + sortablePageParam.setSortingFields(List.of(buildSortingField(func))); | |
| 64 | + } | |
| 65 | + } | |
| 66 | + | |
| 16 | 67 | } | ... | ... |
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
| ... | ... | @@ -88,8 +88,6 @@ public class ServletUtils { |
| 88 | 88 | return JakartaServletUtil.getClientIP(request); |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | - // TODO @疯狂:terminal 还是从 ServletUtils 里拿,更容易全局治理; | |
| 92 | - | |
| 93 | 91 | public static boolean isJsonRequest(ServletRequest request) { |
| 94 | 92 | return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE); |
| 95 | 93 | } | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/db/DataPermissionDatabaseInterceptor.java
| ... | ... | @@ -496,7 +496,8 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme |
| 496 | 496 | Expression allExpression = null; |
| 497 | 497 | for (DataPermissionRule rule : ContextHolder.getRules()) { |
| 498 | 498 | // 判断表名是否匹配 |
| 499 | - if (!rule.getTableNames().contains(table.getName())) { | |
| 499 | + String tableName = MyBatisUtils.getTableName(table); | |
| 500 | + if (!rule.getTableNames().contains(tableName)) { | |
| 500 | 501 | continue; |
| 501 | 502 | } |
| 502 | 503 | // 如果有匹配的规则,说明可重写。 |
| ... | ... | @@ -505,7 +506,6 @@ public class DataPermissionDatabaseInterceptor extends JsqlParserSupport impleme |
| 505 | 506 | ContextHolder.setRewrite(true); |
| 506 | 507 | |
| 507 | 508 | // 单条规则的条件 |
| 508 | - String tableName = MyBatisUtils.getTableName(table); | |
| 509 | 509 | Expression oneExpress = rule.getExpression(tableName, table.getAlias()); |
| 510 | 510 | if (oneExpress == null){ |
| 511 | 511 | continue; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-operatelog/pom.xml
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java
| ... | ... | @@ -71,6 +71,7 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC |
| 71 | 71 | if (StrUtil.isNotEmpty(config.getPrivateCertContent())) { |
| 72 | 72 | payConfig.setPrivateCertPath(FileUtils.createTempFile(config.getPrivateCertContent()).getPath()); |
| 73 | 73 | } |
| 74 | +// payConfig.setCertSerialNo(); | |
| 74 | 75 | |
| 75 | 76 | // 创建 client 客户端 |
| 76 | 77 | client = new WxPayServiceImpl(); | ... | ... |
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/config/YudaoFlowableConfiguration.java
| ... | ... | @@ -17,8 +17,8 @@ public class YudaoFlowableConfiguration { |
| 17 | 17 | * |
| 18 | 18 | * 如果不创建,会导致项目启动时,Flowable 报错的问题 |
| 19 | 19 | */ |
| 20 | - @Bean | |
| 21 | - @ConditionalOnMissingBean | |
| 20 | + @Bean(name = "applicationTaskExecutor") | |
| 21 | + @ConditionalOnMissingBean(name = "applicationTaskExecutor") | |
| 22 | 22 | public AsyncListenableTaskExecutor taskExecutor() { |
| 23 | 23 | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| 24 | 24 | executor.setCorePoolSize(8); | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
| ... | ... | @@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.mybatis.core.mapper; |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.pojo.SortablePageParam; | |
| 7 | +import cn.iocoder.yudao.framework.common.pojo.SortingField; | |
| 6 | 8 | import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; |
| 7 | 9 | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| 8 | 10 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| ... | ... | @@ -13,6 +15,7 @@ import com.baomidou.mybatisplus.core.toolkit.support.SFunction; |
| 13 | 15 | import com.baomidou.mybatisplus.extension.toolkit.Db; |
| 14 | 16 | import com.github.yulichang.base.MPJBaseMapper; |
| 15 | 17 | import com.github.yulichang.interfaces.MPJBaseJoin; |
| 18 | +import com.github.yulichang.wrapper.MPJLambdaWrapper; | |
| 16 | 19 | import org.apache.ibatis.annotations.Param; |
| 17 | 20 | |
| 18 | 21 | import java.util.Collection; |
| ... | ... | @@ -26,7 +29,15 @@ import java.util.List; |
| 26 | 29 | */ |
| 27 | 30 | public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 28 | 31 | |
| 32 | + default PageResult<T> selectPage(SortablePageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) { | |
| 33 | + return selectPage(pageParam, pageParam.getSortingFields(), queryWrapper); | |
| 34 | + } | |
| 35 | + | |
| 29 | 36 | default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) { |
| 37 | + return selectPage(pageParam, null, queryWrapper); | |
| 38 | + } | |
| 39 | + | |
| 40 | + default PageResult<T> selectPage(PageParam pageParam, Collection<SortingField> sortingFields, @Param("ew") Wrapper<T> queryWrapper) { | |
| 30 | 41 | // 特殊:不分页,直接查询全部 |
| 31 | 42 | if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageSize())) { |
| 32 | 43 | List<T> list = selectList(queryWrapper); |
| ... | ... | @@ -34,12 +45,26 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> { |
| 34 | 45 | } |
| 35 | 46 | |
| 36 | 47 | // MyBatis Plus 查询 |
| 37 | - IPage<T> mpPage = MyBatisUtils.buildPage(pageParam); | |
| 48 | + IPage<T> mpPage = MyBatisUtils.buildPage(pageParam, sortingFields); | |
| 38 | 49 | selectPage(mpPage, queryWrapper); |
| 39 | 50 | // 转换返回 |
| 40 | 51 | return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); |
| 41 | 52 | } |
| 42 | 53 | |
| 54 | + default <D> PageResult<D> selectJoinPage(PageParam pageParam, Class<D> clazz, MPJLambdaWrapper<T> lambdaWrapper) { | |
| 55 | + // 特殊:不分页,直接查询全部 | |
| 56 | + if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageNo())) { | |
| 57 | + List<D> list = selectJoinList(clazz, lambdaWrapper); | |
| 58 | + return new PageResult<>(list, (long) list.size()); | |
| 59 | + } | |
| 60 | + | |
| 61 | + // MyBatis Plus Join 查询 | |
| 62 | + IPage<D> mpPage = MyBatisUtils.buildPage(pageParam); | |
| 63 | + mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper); | |
| 64 | + // 转换返回 | |
| 65 | + return new PageResult<>(mpPage.getRecords(), mpPage.getTotal()); | |
| 66 | + } | |
| 67 | + | |
| 43 | 68 | default <DTO> PageResult<DTO> selectJoinPage(PageParam pageParam, Class<DTO> resultTypeClass, MPJBaseJoin<T> joinQueryWrapper) { |
| 44 | 69 | IPage<DTO> mpPage = MyBatisUtils.buildPage(pageParam); |
| 45 | 70 | selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper); | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/MyBatisUtils.java
| ... | ... | @@ -45,8 +45,8 @@ public class MyBatisUtils { |
| 45 | 45 | * 由于 MybatisPlusInterceptor 不支持添加拦截器,所以只能全量设置 |
| 46 | 46 | * |
| 47 | 47 | * @param interceptor 链 |
| 48 | - * @param inner 拦截器 | |
| 49 | - * @param index 位置 | |
| 48 | + * @param inner 拦截器 | |
| 49 | + * @param index 位置 | |
| 50 | 50 | */ |
| 51 | 51 | public static void addInterceptor(MybatisPlusInterceptor interceptor, InnerInterceptor inner, int index) { |
| 52 | 52 | List<InnerInterceptor> inners = new ArrayList<>(interceptor.getInterceptors()); |
| ... | ... | @@ -73,9 +73,9 @@ public class MyBatisUtils { |
| 73 | 73 | /** |
| 74 | 74 | * 构建 Column 对象 |
| 75 | 75 | * |
| 76 | - * @param tableName 表名 | |
| 76 | + * @param tableName 表名 | |
| 77 | 77 | * @param tableAlias 别名 |
| 78 | - * @param column 字段名 | |
| 78 | + * @param column 字段名 | |
| 79 | 79 | * @return Column 对象 |
| 80 | 80 | */ |
| 81 | 81 | public static Column buildColumn(String tableName, Alias tableAlias, String column) { | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/pom.xml
| ... | ... | @@ -12,7 +12,10 @@ |
| 12 | 12 | <packaging>jar</packaging> |
| 13 | 13 | |
| 14 | 14 | <name>${project.artifactId}</name> |
| 15 | - <description>用户的认证、权限的校验</description> | |
| 15 | + <description> | |
| 16 | + 1. security:用户的认证、权限的校验,实现「谁」可以做「什么事」 | |
| 17 | + 2. operatelog:操作日志,实现「谁」在「什么时间」对「什么」做了「什么事」 | |
| 18 | + </description> | |
| 16 | 19 | <url>https://github.com/YunaiV/ruoyi-vue-pro</url> |
| 17 | 20 | |
| 18 | 21 | <dependencies> |
| ... | ... | @@ -50,6 +53,13 @@ |
| 50 | 53 | <artifactId>guava</artifactId> |
| 51 | 54 | </dependency> |
| 52 | 55 | |
| 56 | + <dependency> | |
| 57 | + <!-- Spring Boot 通用操作日志组件,基于注解实现 --> | |
| 58 | + <!-- 此组件解决的问题是:「谁」在「什么时间」对「什么」做了「什么事」 --> | |
| 59 | + <groupId>io.github.mouzt</groupId> | |
| 60 | + <artifactId>bizlog-sdk</artifactId> | |
| 61 | + </dependency> | |
| 62 | + | |
| 53 | 63 | <!-- 业务组件 --> |
| 54 | 64 | <dependency> |
| 55 | 65 | <groupId>cn.iocoder.boot</groupId> | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/config/YudaoOperateLogV2Configuration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.operatelog.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.operatelog.core.service.LogRecordServiceImpl; | |
| 4 | +import com.mzt.logapi.service.ILogRecordService; | |
| 5 | +import com.mzt.logapi.starter.annotation.EnableLogRecord; | |
| 6 | +import lombok.extern.slf4j.Slf4j; | |
| 7 | +import org.springframework.boot.autoconfigure.AutoConfiguration; | |
| 8 | +import org.springframework.context.annotation.Bean; | |
| 9 | +import org.springframework.context.annotation.Primary; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 操作日志配置类 | |
| 13 | + * | |
| 14 | + * @author HUIHUI | |
| 15 | + */ | |
| 16 | +@EnableLogRecord(tenant = "") // 貌似用不上 tenant 这玩意给个空好啦 | |
| 17 | +@AutoConfiguration | |
| 18 | +@Slf4j | |
| 19 | +public class YudaoOperateLogV2Configuration { | |
| 20 | + | |
| 21 | + @Bean | |
| 22 | + @Primary | |
| 23 | + public ILogRecordService iLogRecordServiceImpl() { | |
| 24 | + return new LogRecordServiceImpl(); | |
| 25 | + } | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/package-info.java renamed to yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/core/service/LogRecordServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.operatelog.core.service; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | |
| 5 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | |
| 6 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | |
| 7 | +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; | |
| 8 | +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2CreateReqDTO; | |
| 9 | +import com.mzt.logapi.beans.LogRecord; | |
| 10 | +import com.mzt.logapi.service.ILogRecordService; | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import jakarta.servlet.http.HttpServletRequest; | |
| 13 | +import lombok.extern.slf4j.Slf4j; | |
| 14 | + | |
| 15 | +import java.util.List; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * 操作日志 ILogRecordService 实现类 | |
| 19 | + * | |
| 20 | + * 基于 {@link OperateLogApi} 实现,记录操作日志 | |
| 21 | + * | |
| 22 | + * @author HUIHUI | |
| 23 | + */ | |
| 24 | +@Slf4j | |
| 25 | +public class LogRecordServiceImpl implements ILogRecordService { | |
| 26 | + | |
| 27 | + @Resource | |
| 28 | + private OperateLogApi operateLogApi; | |
| 29 | + | |
| 30 | + @Override | |
| 31 | + public void record(LogRecord logRecord) { | |
| 32 | + // 1. 补全通用字段 | |
| 33 | + OperateLogV2CreateReqDTO reqDTO = new OperateLogV2CreateReqDTO(); | |
| 34 | + reqDTO.setTraceId(TracerUtils.getTraceId()); | |
| 35 | + // 补充用户信息 | |
| 36 | + fillUserFields(reqDTO); | |
| 37 | + // 补全模块信息 | |
| 38 | + fillModuleFields(reqDTO, logRecord); | |
| 39 | + // 补全请求信息 | |
| 40 | + fillRequestFields(reqDTO); | |
| 41 | + | |
| 42 | + // 2. 异步记录日志 | |
| 43 | + operateLogApi.createOperateLogV2(reqDTO); | |
| 44 | + // TODO 测试结束删除或搞个开关 | |
| 45 | + log.info("操作日志 ===> {}", reqDTO); | |
| 46 | + } | |
| 47 | + | |
| 48 | + private static void fillUserFields(OperateLogV2CreateReqDTO reqDTO) { | |
| 49 | + // 使用 SecurityFrameworkUtils。因为要考虑,rpc、mq、job,它其实不是 web; | |
| 50 | + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); | |
| 51 | + if (loginUser == null) { | |
| 52 | + return; | |
| 53 | + } | |
| 54 | + reqDTO.setUserId(loginUser.getId()); | |
| 55 | + reqDTO.setUserType(loginUser.getUserType()); | |
| 56 | + } | |
| 57 | + | |
| 58 | + public static void fillModuleFields(OperateLogV2CreateReqDTO reqDTO, LogRecord logRecord) { | |
| 59 | + reqDTO.setType(logRecord.getType()); // 大模块类型,例如:CRM 客户 | |
| 60 | + reqDTO.setSubType(logRecord.getSubType());// 操作名称,例如:转移客户 | |
| 61 | + reqDTO.setBizId(Long.parseLong(logRecord.getBizNo())); // 业务编号,例如:客户编号 | |
| 62 | + reqDTO.setAction(logRecord.getAction());// 操作内容,例如:修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。 | |
| 63 | + reqDTO.setExtra(logRecord.getExtra()); // 拓展字段,有些复杂的业务,需要记录一些字段 ( JSON 格式 ),例如说,记录订单编号,{ orderId: "1"} | |
| 64 | + } | |
| 65 | + | |
| 66 | + private static void fillRequestFields(OperateLogV2CreateReqDTO reqDTO) { | |
| 67 | + // 获得 Request 对象 | |
| 68 | + HttpServletRequest request = ServletUtils.getRequest(); | |
| 69 | + if (request == null) { | |
| 70 | + return; | |
| 71 | + } | |
| 72 | + // 补全请求信息 | |
| 73 | + reqDTO.setRequestMethod(request.getMethod()); | |
| 74 | + reqDTO.setRequestUrl(request.getRequestURI()); | |
| 75 | + reqDTO.setUserIp(ServletUtils.getClientIP(request)); | |
| 76 | + reqDTO.setUserAgent(ServletUtils.getUserAgent(request)); | |
| 77 | + } | |
| 78 | + | |
| 79 | + @Override | |
| 80 | + public List<LogRecord> queryLog(String bizNo, String type) { | |
| 81 | + throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询"); | |
| 82 | + } | |
| 83 | + | |
| 84 | + @Override | |
| 85 | + public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) { | |
| 86 | + throw new UnsupportedOperationException("使用 OperateLogApi 进行操作日志的查询"); | |
| 87 | + } | |
| 88 | + | |
| 89 | +} | |
| 0 | 90 | \ No newline at end of file | ... | ... |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java
0 → 100644
yudao-framework/yudao-spring-boot-starter-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
| 1 | 1 | cn.iocoder.yudao.framework.security.config.YudaoSecurityAutoConfiguration |
| 2 | -cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter | |
| 3 | 2 | \ No newline at end of file |
| 3 | +cn.iocoder.yudao.framework.security.config.YudaoWebSecurityConfigurerAdapter | |
| 4 | +cn.iocoder.yudao.framework.operatelog.config.YudaoOperateLogV2Configuration | |
| 4 | 5 | \ No newline at end of file | ... | ... |
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/util/WebFrameworkUtils.java
| 1 | 1 | package cn.iocoder.yudao.framework.web.core.util; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.util.NumberUtil; |
| 4 | +import cn.hutool.extra.servlet.ServletUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.enums.TerminalEnum; | |
| 4 | 6 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | +import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; | |
| 6 | 9 | import cn.iocoder.yudao.framework.web.config.WebProperties; |
| 7 | 10 | import org.springframework.web.context.request.RequestAttributes; |
| 8 | 11 | import org.springframework.web.context.request.RequestContextHolder; |
| ... | ... | @@ -25,6 +28,13 @@ public class WebFrameworkUtils { |
| 25 | 28 | |
| 26 | 29 | public static final String HEADER_TENANT_ID = "tenant-id"; |
| 27 | 30 | |
| 31 | + /** | |
| 32 | + * 终端的 Header | |
| 33 | + * | |
| 34 | + * @see cn.iocoder.yudao.framework.common.enums.TerminalEnum | |
| 35 | + */ | |
| 36 | + public static final String HEADER_TERMINAL = "terminal"; | |
| 37 | + | |
| 28 | 38 | private static WebProperties properties; |
| 29 | 39 | |
| 30 | 40 | public WebFrameworkUtils(WebProperties webProperties) { |
| ... | ... | @@ -107,6 +117,15 @@ public class WebFrameworkUtils { |
| 107 | 117 | return getLoginUserId(request); |
| 108 | 118 | } |
| 109 | 119 | |
| 120 | + public static Integer getTerminal() { | |
| 121 | + HttpServletRequest request = getRequest(); | |
| 122 | + if (request == null) { | |
| 123 | + return TerminalEnum.UNKNOWN.getTerminal(); | |
| 124 | + } | |
| 125 | + String terminalValue = request.getHeader(HEADER_TERMINAL); | |
| 126 | + return NumberUtil.parseInt(terminalValue, TerminalEnum.UNKNOWN.getTerminal()); | |
| 127 | + } | |
| 128 | + | |
| 110 | 129 | public static void setCommonResult(ServletRequest request, CommonResult<?> result) { |
| 111 | 130 | request.setAttribute(REQUEST_ATTRIBUTE_COMMON_RESULT, result); |
| 112 | 131 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/candidate/vo/BpmTaskCandidateRuleVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleBaseVO; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +import java.util.Set; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * 流程任务分配规则 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 12 | + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 13 | + * | |
| 14 | + * @see BpmTaskAssignRuleBaseVO | |
| 15 | + */ | |
| 16 | +@Data | |
| 17 | +public class BpmTaskCandidateRuleVO { | |
| 18 | + | |
| 19 | + @Schema(description = "规则类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "bpm_task_assign_rule_type") | |
| 20 | + @NotNull(message = "规则类型不能为空") | |
| 21 | + private Integer type; | |
| 22 | + | |
| 23 | + @Schema(description = "规则值数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3") | |
| 24 | + @NotNull(message = "规则值数组不能为空") | |
| 25 | + private Set<Long> options; | |
| 26 | + | |
| 27 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
| ... | ... | @@ -3,17 +3,17 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; |
| 6 | +import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyService; | |
| 6 | 7 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| 7 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 8 | -import io.swagger.v3.oas.annotations.Parameter; | |
| 9 | 8 | import io.swagger.v3.oas.annotations.Operation; |
| 9 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 10 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import jakarta.validation.Valid; | |
| 10 | 13 | import org.springframework.security.access.prepost.PreAuthorize; |
| 11 | 14 | import org.springframework.validation.annotation.Validated; |
| 12 | 15 | import org.springframework.web.bind.annotation.*; |
| 13 | 16 | |
| 14 | -import jakarta.annotation.Resource; | |
| 15 | -import jakarta.validation.Valid; | |
| 16 | - | |
| 17 | 17 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 18 | 18 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 19 | 19 | |
| ... | ... | @@ -26,6 +26,9 @@ public class BpmProcessInstanceController { |
| 26 | 26 | @Resource |
| 27 | 27 | private BpmProcessInstanceService processInstanceService; |
| 28 | 28 | |
| 29 | + @Resource | |
| 30 | + private BpmProcessInstanceCopyService processInstanceCopyService; | |
| 31 | + | |
| 29 | 32 | @GetMapping("/my-page") |
| 30 | 33 | @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") |
| 31 | 34 | @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") |
| ... | ... | @@ -56,4 +59,22 @@ public class BpmProcessInstanceController { |
| 56 | 59 | processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO); |
| 57 | 60 | return success(true); |
| 58 | 61 | } |
| 62 | + | |
| 63 | + // TODO @kyle:抄送要不单独 controller? | |
| 64 | + | |
| 65 | + @PostMapping("/cc/create") | |
| 66 | + @Operation(summary = "抄送流程") | |
| 67 | + @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')") | |
| 68 | + public CommonResult<Boolean> createProcessInstanceCC(@Valid @RequestBody BpmProcessInstanceCCReqVO createReqVO) { | |
| 69 | + return success(processInstanceCopyService.ccProcessInstance(getLoginUserId(), createReqVO)); | |
| 70 | + } | |
| 71 | + | |
| 72 | + @GetMapping("/cc/my-page") | |
| 73 | + @Operation(summary = "获得抄送流程分页列表") | |
| 74 | + @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')") | |
| 75 | + public CommonResult<PageResult<BpmProcessInstanceCCPageItemRespVO>> getProcessInstanceCCPage( | |
| 76 | + @Valid BpmProcessInstanceCCMyPageReqVO pageReqVO) { | |
| 77 | + return success(processInstanceCopyService.getMyProcessInstanceCCPage(getLoginUserId(), pageReqVO)); | |
| 78 | + } | |
| 79 | + | |
| 59 | 80 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCCMyPageReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | +import lombok.EqualsAndHashCode; | |
| 7 | +import lombok.ToString; | |
| 8 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | + | |
| 10 | +import java.time.LocalDateTime; | |
| 11 | + | |
| 12 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 13 | + | |
| 14 | +// TODO @kyle:建议改成 BpmProcessInstanceCopyMyPageReqVO;cc 缩写不容易理解,所以改成 copy,虽然会长一点,但是可读性更重要; | |
| 15 | +@Schema(description = "管理后台 - 流程实例抄送的分页 Request VO") | |
| 16 | +@Data | |
| 17 | +@EqualsAndHashCode(callSuper = true) | |
| 18 | +@ToString(callSuper = true) | |
| 19 | +public class BpmProcessInstanceCCMyPageReqVO extends PageParam { | |
| 20 | + | |
| 21 | + @Schema(description = "流程名称", example = "芋道") | |
| 22 | + private String processInstanceName; | |
| 23 | + | |
| 24 | + @Schema(description = "流程编号", example = "123456768") | |
| 25 | + private String processInstanceId; | |
| 26 | + | |
| 27 | + @Schema(description = "创建时间") | |
| 28 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 29 | + private LocalDateTime[] createTime; | |
| 30 | + | |
| 31 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCCPageItemRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO") | |
| 9 | +@Data | |
| 10 | +public class BpmProcessInstanceCCPageItemRespVO { | |
| 11 | + | |
| 12 | + // TODO @kyle:如果已经写了 swagger 注解,可以不用写 java 注释哈; | |
| 13 | + /** | |
| 14 | + * 编号 | |
| 15 | + */ | |
| 16 | + @Schema(description = "抄送主键") | |
| 17 | + private Long id; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 发起人Id | |
| 21 | + */ | |
| 22 | + @Schema(description = "发起人Id") | |
| 23 | + private Long startUserId; | |
| 24 | + | |
| 25 | + @Schema(description = "发起人别名") | |
| 26 | + private String startUserNickname; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 流程主键 | |
| 30 | + */ | |
| 31 | + @Schema(description = "流程实例的主键") | |
| 32 | + private String processInstanceId; | |
| 33 | + | |
| 34 | + @Schema(description = "流程实例的名称") | |
| 35 | + private String processInstanceName; | |
| 36 | + /** | |
| 37 | + * 任务主键 | |
| 38 | + */ | |
| 39 | + @Schema(description = "发起抄送的任务编号") | |
| 40 | + private String taskId; | |
| 41 | + | |
| 42 | + @Schema(description = "发起抄送的任务名称") | |
| 43 | + private String taskName; | |
| 44 | + | |
| 45 | + @Schema(description = "抄送原因") | |
| 46 | + private String reason; | |
| 47 | + | |
| 48 | + @Schema(description = "抄送人") | |
| 49 | + private String creator; | |
| 50 | + | |
| 51 | + @Schema(description = "抄送人别名") | |
| 52 | + private String creatorNickname; | |
| 53 | + | |
| 54 | + @Schema(description = "抄送时间") | |
| 55 | + private LocalDateTime createTime; | |
| 56 | + | |
| 57 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCCReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import jakarta.validation.constraints.NotBlank; | |
| 6 | +import jakarta.validation.constraints.NotEmpty; | |
| 7 | +import jakarta.validation.constraints.NotNull; | |
| 8 | +import lombok.Data; | |
| 9 | +import lombok.EqualsAndHashCode; | |
| 10 | +import lombok.ToString; | |
| 11 | + | |
| 12 | +// TODO @kyle:这个 VO 可以改成 BpmProcessInstanceCopyCreateReqVO | |
| 13 | +@Schema(description = "管理后台 - 流程实例的抄送 Request VO") | |
| 14 | +@Data | |
| 15 | +@EqualsAndHashCode(callSuper = true) | |
| 16 | +@ToString(callSuper = true) | |
| 17 | +public class BpmProcessInstanceCCReqVO extends BpmTaskCandidateRuleVO { | |
| 18 | + | |
| 19 | + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 20 | + @NotEmpty(message = "任务编号不能为空") | |
| 21 | + private String taskKey; | |
| 22 | + | |
| 23 | + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 24 | + @NotEmpty(message = "任务名称不能为空") | |
| 25 | + private String taskName; | |
| 26 | + | |
| 27 | + @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 28 | + @NotEmpty(message = "流程实例的编号不能为空") | |
| 29 | + private String processInstanceKey; | |
| 30 | + | |
| 31 | + @Schema(description = "发起流程的用户的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 32 | + @NotNull(message = "发起流程的用户的编号不能为空") | |
| 33 | + private Long startUserId; | |
| 34 | + | |
| 35 | + @Schema(description = "任务实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") | |
| 36 | + @NotEmpty(message = "任务实例名称不能为空") | |
| 37 | + private String processInstanceName; | |
| 38 | + | |
| 39 | + @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!") | |
| 40 | + @NotBlank(message = "抄送原因不能为空") | |
| 41 | + private String reason; | |
| 42 | + | |
| 43 | + // TODO @kyle:看了下字段有点多,尽量不传递可推导的字段; | |
| 44 | + // 需要传递:taskId(任务编号)、reason、userIds(被抄送的人) | |
| 45 | + // 不需要传递:taskKey、taskName、processInstanceKey、startUserId、processInstanceName 因为这些可以后端查询到 | |
| 46 | + | |
| 47 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.convert.cc; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO; | |
| 6 | +import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyVO; | |
| 8 | +import org.mapstruct.Mapper; | |
| 9 | +import org.mapstruct.factory.Mappers; | |
| 10 | + | |
| 11 | +import java.util.List; | |
| 12 | +import java.util.Map; | |
| 13 | + | |
| 14 | +// TODO kyle:类注释不太对 | |
| 15 | +/** | |
| 16 | + * 动态表单 Convert | |
| 17 | + * | |
| 18 | + * @author 芋艿 | |
| 19 | + */ | |
| 20 | +@Mapper | |
| 21 | +public interface BpmProcessInstanceCopyConvert { | |
| 22 | + | |
| 23 | + BpmProcessInstanceCopyConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceCopyConvert.class); | |
| 24 | + | |
| 25 | + // TODO @kyle:可以使用 BeanUtils copy 替代这些简单的哈; | |
| 26 | + BpmProcessInstanceCopyDO copy(BpmProcessInstanceCopyDO bean); | |
| 27 | + | |
| 28 | + BpmProcessInstanceCopyVO convert(BpmProcessInstanceCopyDO bean); | |
| 29 | + | |
| 30 | + List<BpmProcessInstanceCCPageItemRespVO> convertList(List<BpmProcessInstanceCopyDO> list); | |
| 31 | + | |
| 32 | + // TODO @kyle:/* taskId */ 这种注释一般不用写,可以一眼看明白的;避免变量看着略微不清晰哈 | |
| 33 | + default PageResult<BpmProcessInstanceCCPageItemRespVO> convertPage(PageResult<BpmProcessInstanceCopyDO> page | |
| 34 | + , Map<String/* taskId */, String/* taskName */> taskMap | |
| 35 | + , Map<String/* processInstaneId */, String/* processInstaneName */> processInstaneMap | |
| 36 | + , Map<Long/* userId */, String/* userName */> userMap | |
| 37 | + ) { | |
| 38 | + List<BpmProcessInstanceCCPageItemRespVO> list = convertList(page.getList()); | |
| 39 | + for (BpmProcessInstanceCCPageItemRespVO vo : list) { | |
| 40 | + MapUtils.findAndThen(userMap, Long.valueOf(vo.getCreator()), | |
| 41 | + vo::setCreatorNickname); | |
| 42 | + MapUtils.findAndThen(userMap, vo.getStartUserId(), | |
| 43 | + vo::setStartUserNickname); | |
| 44 | + MapUtils.findAndThen(taskMap, vo.getTaskId(), | |
| 45 | + vo::setTaskName); | |
| 46 | + MapUtils.findAndThen(processInstaneMap, vo.getProcessInstanceId(), | |
| 47 | + vo::setProcessInstanceName); | |
| 48 | + } | |
| 49 | + // TODO @kyle:可以精简成下面的哈; | |
| 50 | +// List<BpmProcessInstanceCCPageItemRespVO> list2 = BeanUtils.toBean(page.getList(), | |
| 51 | +// BpmProcessInstanceCCPageItemRespVO.class, | |
| 52 | +// copy -> { | |
| 53 | +// MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), copy::setCreatorNickname); | |
| 54 | +// MapUtils.findAndThen(userMap, copy.getStartUserId(), copy::setStartUserNickname); | |
| 55 | +// MapUtils.findAndThen(taskMap, copy.getTaskId(), copy::setTaskName); | |
| 56 | +// MapUtils.findAndThen(processInstaneMap, copy.getProcessInstanceId(), copy::setProcessInstanceName); | |
| 57 | +// }); | |
| 58 | + return new PageResult<>(list, page.getTotal()); | |
| 59 | + } | |
| 60 | + | |
| 61 | +} | ... | ... |
yudao-module-mall/yudao-module-statistics-biz/src/main/java/cn/iocoder/yudao/module/statistics/dal/dataobject/member/MemberStatisticsDO.java renamed to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java
| 1 | -package cn.iocoder.yudao.module.statistics.dal.dataobject.member; | |
| 1 | +package cn.iocoder.yudao.module.bpm.dal.dataobject.cc; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; |
| 4 | -import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 5 | 4 | import com.baomidou.mybatisplus.annotation.TableId; |
| 6 | 5 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | 6 | import lombok.*; |
| 8 | 7 | |
| 9 | -import java.time.LocalDateTime; | |
| 10 | - | |
| 11 | 8 | /** |
| 12 | - * 会员统计 DO | |
| 13 | - * <p> | |
| 14 | - * 以天为维度,统计全部的数据 | |
| 9 | + * 流程抄送 DO | |
| 15 | 10 | * |
| 16 | - * @author 芋道源码 | |
| 11 | + * @author kyle | |
| 12 | + * @date 2022-05-19 TODO @kyle:@date 不是标准 java doc,可以使用 @since 替代,然后日期是不是不对 | |
| 17 | 13 | */ |
| 18 | -@TableName("member_statistics") | |
| 19 | -@KeySequence("member_statistics_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 14 | +@TableName(value = "bpm_process_instance_copy", autoResultMap = true) | |
| 20 | 15 | @Data |
| 21 | 16 | @EqualsAndHashCode(callSuper = true) |
| 22 | 17 | @ToString(callSuper = true) |
| 23 | 18 | @Builder |
| 24 | 19 | @NoArgsConstructor |
| 25 | 20 | @AllArgsConstructor |
| 26 | -public class MemberStatisticsDO extends BaseDO { | |
| 21 | +public class BpmProcessInstanceCopyDO extends BaseDO { | |
| 27 | 22 | |
| 28 | 23 | /** |
| 29 | - * 编号,主键自增 | |
| 24 | + * 编号 | |
| 30 | 25 | */ |
| 31 | 26 | @TableId |
| 32 | 27 | private Long id; |
| 33 | 28 | |
| 29 | + // TODO @kyle:字段如果是关联或者冗余,要写下注释。以 processInstanceId 举例子。 | |
| 34 | 30 | /** |
| 35 | - * 统计日期 | |
| 31 | + * 发起人 Id | |
| 36 | 32 | */ |
| 37 | - private LocalDateTime time; | |
| 38 | - | |
| 33 | + private Long startUserId; | |
| 39 | 34 | /** |
| 40 | - * 注册用户数量 | |
| 35 | + * 流程名 | |
| 41 | 36 | */ |
| 42 | - private Integer userRegisterCount; | |
| 37 | + private String processInstanceName; | |
| 43 | 38 | /** |
| 44 | - * 访问用户数量(UV) | |
| 39 | + * 流程实例的编号 | |
| 40 | + * | |
| 41 | + * 关联 ProcessInstance 的 id 属性 | |
| 45 | 42 | */ |
| 46 | - private Integer userVisitCount; | |
| 43 | + private String processInstanceId; | |
| 44 | + | |
| 47 | 45 | /** |
| 48 | - * 访问页面数量(PV) | |
| 46 | + * 任务主键 | |
| 49 | 47 | */ |
| 50 | - private Integer pageVisitCount; | |
| 48 | + private String taskId; | |
| 51 | 49 | |
| 52 | 50 | /** |
| 53 | - * 充值用户数量 | |
| 51 | + * 任务名称 | |
| 54 | 52 | */ |
| 55 | - private Integer rechargeUserCount; | |
| 53 | + private String taskName; | |
| 56 | 54 | |
| 57 | 55 | /** |
| 58 | - * 创建订单用户数 | |
| 56 | + * 用户编号 | |
| 59 | 57 | */ |
| 60 | - private Integer orderCreateUserCount; | |
| 58 | + private Long userId; | |
| 59 | + | |
| 61 | 60 | /** |
| 62 | - * 支付订单用户数 | |
| 61 | + * 抄送原因 | |
| 63 | 62 | */ |
| 64 | - private Integer orderPayUserCount; | |
| 63 | + private String reason; | |
| 64 | + | |
| 65 | + // TODO @kyle:这个字段,可以用 category 简化点 | |
| 65 | 66 | /** |
| 66 | - * 总支付金额,单位:分 | |
| 67 | + * 流程分类 | |
| 67 | 68 | */ |
| 68 | - private Integer orderPayPrice; | |
| 69 | + private String processDefinitionCategory; | |
| 69 | 70 | |
| 70 | 71 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.dal.mysql.cc; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | |
| 5 | +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 6 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCMyPageReqVO; | |
| 7 | +import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; | |
| 8 | +import org.apache.ibatis.annotations.Mapper; | |
| 9 | + | |
| 10 | +@Mapper | |
| 11 | +public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> { // TODO @kyle:方法和类之间要空行下; | |
| 12 | + default PageResult<BpmProcessInstanceCopyDO> selectPage(Long loginUserId, BpmProcessInstanceCCMyPageReqVO reqVO){ | |
| 13 | + return selectPage(reqVO, new LambdaQueryWrapperX<BpmProcessInstanceCopyDO>() | |
| 14 | + .eqIfPresent(BpmProcessInstanceCopyDO::getUserId, loginUserId) | |
| 15 | + .eqIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceId, reqVO.getProcessInstanceId()) | |
| 16 | + .likeIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceName, reqVO.getProcessInstanceName()) | |
| 17 | + .betweenIfPresent(BpmProcessInstanceCopyDO::getCreateTime, reqVO.getCreateTime()) | |
| 18 | + .orderByDesc(BpmProcessInstanceCopyDO::getId)); | |
| 19 | + } | |
| 20 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.bpm.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | |
| 4 | +import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.*; | |
| 5 | +import org.springframework.beans.factory.ObjectProvider; | |
| 6 | +import org.springframework.context.annotation.Bean; | |
| 7 | +import org.springframework.context.annotation.Configuration; | |
| 8 | + | |
| 9 | +// TODO @芋艿:Candidate 相关还在完善中,用户可以暂时忽略,仅 yudao 开发的同学需要关注~计划是把 Candidate 和 Assign 融合成一套 | |
| 10 | +/** | |
| 11 | + * BPM 通用的 Configuration 配置类,提供给 Activiti 和 Flowable | |
| 12 | + * @author kyle | |
| 13 | + */ | |
| 14 | +@Configuration(proxyBeanMethods = false) | |
| 15 | +public class BpmCandidateProcessorConfiguration { | |
| 16 | + @Bean | |
| 17 | + public BpmCandidateAdminUserApiSourceInfoProcessor bpmCandidateAdminUserApiSourceInfoProcessor() { | |
| 18 | + return new BpmCandidateAdminUserApiSourceInfoProcessor(); | |
| 19 | + } | |
| 20 | + | |
| 21 | + @Bean | |
| 22 | + public BpmCandidateDeptApiSourceInfoProcessor bpmCandidateDeptApiSourceInfoProcessor() { | |
| 23 | + return new BpmCandidateDeptApiSourceInfoProcessor(); | |
| 24 | + } | |
| 25 | + | |
| 26 | + @Bean | |
| 27 | + public BpmCandidatePostApiSourceInfoProcessor bpmCandidatePostApiSourceInfoProcessor() { | |
| 28 | + return new BpmCandidatePostApiSourceInfoProcessor(); | |
| 29 | + } | |
| 30 | + | |
| 31 | + @Bean | |
| 32 | + public BpmCandidateRoleApiSourceInfoProcessor bpmCandidateRoleApiSourceInfoProcessor() { | |
| 33 | + return new BpmCandidateRoleApiSourceInfoProcessor(); | |
| 34 | + } | |
| 35 | + | |
| 36 | + @Bean | |
| 37 | + public BpmCandidateUserGroupApiSourceInfoProcessor bpmCandidateUserGroupApiSourceInfoProcessor() { | |
| 38 | + return new BpmCandidateUserGroupApiSourceInfoProcessor(); | |
| 39 | + } | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 可以自己定制脚本,然后通过这里设置到处理器里面去 | |
| 43 | + * @param scriptsOp 脚本包装对象 | |
| 44 | + * @return | |
| 45 | + */ | |
| 46 | + @Bean | |
| 47 | + public BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor(ObjectProvider<BpmTaskAssignScript> scriptsOp) { | |
| 48 | + BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor = new BpmCandidateScriptApiSourceInfoProcessor(); | |
| 49 | + bpmCandidateScriptApiSourceInfoProcessor.setScripts(scriptsOp); | |
| 50 | + return bpmCandidateScriptApiSourceInfoProcessor; | |
| 51 | + } | |
| 52 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.AllArgsConstructor; | |
| 6 | +import lombok.Data; | |
| 7 | +import lombok.NoArgsConstructor; | |
| 8 | + | |
| 9 | +import jakarta.validation.constraints.NotEmpty; | |
| 10 | +import jakarta.validation.constraints.NotNull; | |
| 11 | +import java.util.HashSet; | |
| 12 | +import java.util.Set; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 获取候选人信息 | |
| 16 | + */ | |
| 17 | +@AllArgsConstructor | |
| 18 | +@NoArgsConstructor | |
| 19 | +@Data | |
| 20 | +public class BpmCandidateSourceInfo { | |
| 21 | + | |
| 22 | + @Schema(description = "流程id") | |
| 23 | + @NotNull | |
| 24 | + private String processInstanceId; | |
| 25 | + | |
| 26 | + @Schema(description = "当前任务ID") | |
| 27 | + @NotNull | |
| 28 | + private String taskId; | |
| 29 | + /** | |
| 30 | + * 通过这些规则,生成最终需要生成的用户 | |
| 31 | + */ | |
| 32 | + @Schema(description = "当前任务预选规则") | |
| 33 | + @NotEmpty(message = "不允许空规则") | |
| 34 | + private Set<BpmTaskCandidateRuleVO> rules; | |
| 35 | + | |
| 36 | + @Schema(description = "发起抄送的用户") | |
| 37 | + private String creator; | |
| 38 | + | |
| 39 | + @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!") | |
| 40 | + @NotEmpty(message = "抄送原因不能为空") | |
| 41 | + private String reason; | |
| 42 | + | |
| 43 | + public void addRule(BpmTaskCandidateRuleVO vo) { | |
| 44 | + assert vo != null; | |
| 45 | + if (rules == null) { | |
| 46 | + rules = new HashSet<>(); | |
| 47 | + } | |
| 48 | + rules.add(vo); | |
| 49 | + } | |
| 50 | +} | |
| 0 | 51 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 6 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 7 | + | |
| 8 | +import java.util.Collections; | |
| 9 | +import java.util.HashSet; | |
| 10 | +import java.util.Set; | |
| 11 | + | |
| 12 | +public interface BpmCandidateSourceInfoProcessor { | |
| 13 | + /** | |
| 14 | + * 获取该处理器支持的类型 | |
| 15 | + * 来自 {@link BpmTaskAssignRuleTypeEnum} | |
| 16 | + * | |
| 17 | + * @return | |
| 18 | + */ | |
| 19 | + Set<Integer> getSupportedTypes(); | |
| 20 | + | |
| 21 | + /** | |
| 22 | + * 对规则和人员做校验 | |
| 23 | + * | |
| 24 | + * @param type 规则 | |
| 25 | + * @param options 人员id | |
| 26 | + */ | |
| 27 | + void validRuleOptions(Integer type, Set<Long> options); | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 默认的处理 | |
| 31 | + * 如果想去操作所有的规则,则可以覆盖此方法 | |
| 32 | + * | |
| 33 | + * @param request 原始请求 | |
| 34 | + * @param delegateExecution 审批过程中的对象 | |
| 35 | + * @return 必须包含的是用户ID,而不是其他的ID | |
| 36 | + * @throws Exception | |
| 37 | + */ | |
| 38 | + default Set<Long> process(BpmCandidateSourceInfo request, DelegateExecution delegateExecution) throws Exception { | |
| 39 | + Set<BpmTaskCandidateRuleVO> rules = request.getRules(); | |
| 40 | + Set<Long> results = new HashSet<>(); | |
| 41 | + for (BpmTaskCandidateRuleVO rule : rules) { | |
| 42 | + // 每个处理器都有机会处理自己支持的事件 | |
| 43 | + if (CollUtil.contains(getSupportedTypes(), rule.getType())) { | |
| 44 | + results.addAll(doProcess(request, rule, delegateExecution)); | |
| 45 | + } | |
| 46 | + } | |
| 47 | + return results; | |
| 48 | + } | |
| 49 | + | |
| 50 | + default Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 51 | + return Collections.emptySet(); | |
| 52 | + } | |
| 53 | +} | |
| 0 | 54 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.collection.ListUtil; | |
| 5 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 6 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 7 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 8 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 9 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 10 | +import org.springframework.beans.factory.ObjectProvider; | |
| 11 | +import org.springframework.stereotype.Service; | |
| 12 | + | |
| 13 | +import jakarta.annotation.Resource; | |
| 14 | +import java.util.*; | |
| 15 | + | |
| 16 | +@Service | |
| 17 | +public class BpmCandidateSourceInfoProcessorChain { | |
| 18 | + | |
| 19 | + // 保存处理节点 | |
| 20 | + | |
| 21 | + private List<BpmCandidateSourceInfoProcessor> processorList; | |
| 22 | + @Resource | |
| 23 | + private AdminUserApi adminUserApi; | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 可添加其他处理器 | |
| 27 | + * | |
| 28 | + * @param processorOp | |
| 29 | + * @return | |
| 30 | + */ | |
| 31 | + @Resource | |
| 32 | + // 动态扩展处理节点 | |
| 33 | + public BpmCandidateSourceInfoProcessorChain addProcessor(ObjectProvider<BpmCandidateSourceInfoProcessor> processorOp) { | |
| 34 | + List<BpmCandidateSourceInfoProcessor> processor = ListUtil.toList(processorOp.iterator()); | |
| 35 | + if (null == processorList) { | |
| 36 | + processorList = new ArrayList<>(processor.size()); | |
| 37 | + } | |
| 38 | + processorList.addAll(processor); | |
| 39 | + return this; | |
| 40 | + } | |
| 41 | + | |
| 42 | + // 获取处理器处理 | |
| 43 | + public Set<Long> process(BpmCandidateSourceInfo sourceInfo, DelegateExecution execution) throws Exception { | |
| 44 | + // Verify our parameters | |
| 45 | + if (sourceInfo == null) { | |
| 46 | + throw new IllegalArgumentException(); | |
| 47 | + } | |
| 48 | + for (BpmCandidateSourceInfoProcessor processor : processorList) { | |
| 49 | + try { | |
| 50 | + for (BpmTaskCandidateRuleVO vo : sourceInfo.getRules()) { | |
| 51 | + if (CollUtil.contains(processor.getSupportedTypes(), vo.getType())) { | |
| 52 | + processor.validRuleOptions(vo.getType(), vo.getOptions()); | |
| 53 | + } | |
| 54 | + } | |
| 55 | + } catch (Exception e) { | |
| 56 | + e.printStackTrace(); | |
| 57 | + throw e; | |
| 58 | + } | |
| 59 | + } | |
| 60 | + Set<Long> saveResult = Collections.emptySet(); | |
| 61 | + Exception saveException = null; | |
| 62 | + for (BpmCandidateSourceInfoProcessor processor : processorList) { | |
| 63 | + try { | |
| 64 | + saveResult = processor.process(sourceInfo, execution); | |
| 65 | + if (CollUtil.isNotEmpty(saveResult)) { | |
| 66 | + removeDisableUsers(saveResult); | |
| 67 | + break; | |
| 68 | + } | |
| 69 | + } catch (Exception e) { | |
| 70 | + saveException = e; | |
| 71 | + break; | |
| 72 | + } | |
| 73 | + } | |
| 74 | + // Return the exception or result state from the last execute() | |
| 75 | + if ((saveException != null)) { | |
| 76 | + throw saveException; | |
| 77 | + } else { | |
| 78 | + return (saveResult); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + | |
| 82 | + public Set<Long> calculateTaskCandidateUsers(DelegateExecution execution, BpmCandidateSourceInfo sourceInfo) { | |
| 83 | + Set<Long> results = Collections.emptySet(); | |
| 84 | + try { | |
| 85 | + results = process(sourceInfo, execution); | |
| 86 | + } catch (Exception e) { | |
| 87 | + e.printStackTrace(); | |
| 88 | + } | |
| 89 | + return results; | |
| 90 | + } | |
| 91 | + | |
| 92 | + /** | |
| 93 | + * 移除禁用用户 | |
| 94 | + * | |
| 95 | + * @param assigneeUserIds | |
| 96 | + */ | |
| 97 | + public void removeDisableUsers(Set<Long> assigneeUserIds) { | |
| 98 | + if (CollUtil.isEmpty(assigneeUserIds)) { | |
| 99 | + return; | |
| 100 | + } | |
| 101 | + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds); | |
| 102 | + assigneeUserIds.removeIf(id -> { | |
| 103 | + AdminUserRespDTO user = userMap.get(id); | |
| 104 | + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); | |
| 105 | + }); | |
| 106 | + } | |
| 107 | +} | |
| 0 | 108 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 8 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 9 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 10 | + | |
| 11 | +import jakarta.annotation.Resource; | |
| 12 | +import java.util.Set; | |
| 13 | + | |
| 14 | +public class BpmCandidateAdminUserApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 15 | + @Resource | |
| 16 | + private AdminUserApi api; | |
| 17 | + | |
| 18 | + @Override | |
| 19 | + public Set<Integer> getSupportedTypes() { | |
| 20 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER.getType()); | |
| 21 | + } | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 25 | + api.validateUserList(options); | |
| 26 | + } | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 30 | + return rule.getOptions(); | |
| 31 | + } | |
| 32 | +} | |
| 0 | 33 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 8 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | |
| 9 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | |
| 10 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 11 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 12 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 13 | + | |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import java.util.Collections; | |
| 16 | +import java.util.List; | |
| 17 | +import java.util.Objects; | |
| 18 | +import java.util.Set; | |
| 19 | + | |
| 20 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 21 | + | |
| 22 | +public class BpmCandidateDeptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 23 | + @Resource | |
| 24 | + private DeptApi api; | |
| 25 | + @Resource | |
| 26 | + private AdminUserApi adminUserApi; | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public Set<Integer> getSupportedTypes() { | |
| 30 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), | |
| 31 | + BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); | |
| 32 | + } | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 36 | + api.validateDeptList(options); | |
| 37 | + } | |
| 38 | + | |
| 39 | + @Override | |
| 40 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 41 | + if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { | |
| 42 | + List<AdminUserRespDTO> users = adminUserApi.getUserListByDeptIds(rule.getOptions()); | |
| 43 | + return convertSet(users, AdminUserRespDTO::getId); | |
| 44 | + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { | |
| 45 | + List<DeptRespDTO> depts = api.getDeptList(rule.getOptions()); | |
| 46 | + return convertSet(depts, DeptRespDTO::getLeaderUserId); | |
| 47 | + } | |
| 48 | + return Collections.emptySet(); | |
| 49 | + } | |
| 50 | +} | |
| 0 | 51 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 8 | +import cn.iocoder.yudao.module.system.api.dept.PostApi; | |
| 9 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 10 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 11 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 12 | + | |
| 13 | +import jakarta.annotation.Resource; | |
| 14 | +import java.util.List; | |
| 15 | +import java.util.Set; | |
| 16 | + | |
| 17 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 18 | + | |
| 19 | +public class BpmCandidatePostApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 20 | + @Resource | |
| 21 | + private PostApi api; | |
| 22 | + @Resource | |
| 23 | + private AdminUserApi adminUserApi; | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public Set<Integer> getSupportedTypes() { | |
| 27 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.POST.getType()); | |
| 28 | + } | |
| 29 | + | |
| 30 | + @Override | |
| 31 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 32 | + api.validPostList(options); | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 37 | + List<AdminUserRespDTO> users = adminUserApi.getUserListByPostIds(rule.getOptions()); | |
| 38 | + return convertSet(users, AdminUserRespDTO::getId); | |
| 39 | + } | |
| 40 | +} | |
| 0 | 41 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 8 | +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; | |
| 9 | +import cn.iocoder.yudao.module.system.api.permission.RoleApi; | |
| 10 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 11 | + | |
| 12 | +import jakarta.annotation.Resource; | |
| 13 | +import java.util.Set; | |
| 14 | + | |
| 15 | +public class BpmCandidateRoleApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 16 | + @Resource | |
| 17 | + private RoleApi api; | |
| 18 | + | |
| 19 | + @Resource | |
| 20 | + private PermissionApi permissionApi; | |
| 21 | + | |
| 22 | + @Override | |
| 23 | + public Set<Integer> getSupportedTypes() { | |
| 24 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.ROLE.getType()); | |
| 25 | + } | |
| 26 | + | |
| 27 | + @Override | |
| 28 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 29 | + api.validRoleList(options); | |
| 30 | + } | |
| 31 | + | |
| 32 | + @Override | |
| 33 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 34 | + return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); | |
| 35 | + } | |
| 36 | + | |
| 37 | +} | |
| 0 | 38 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 6 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 7 | +import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; | |
| 8 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 9 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | |
| 10 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 11 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 12 | +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; | |
| 13 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 14 | +import org.springframework.beans.factory.ObjectProvider; | |
| 15 | + | |
| 16 | +import jakarta.annotation.Resource; | |
| 17 | +import java.util.*; | |
| 18 | +import java.util.stream.Collectors; | |
| 19 | + | |
| 20 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 21 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | |
| 22 | +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS; | |
| 23 | + | |
| 24 | +public class BpmCandidateScriptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 25 | + @Resource | |
| 26 | + private DictDataApi dictDataApi; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 任务分配脚本 | |
| 30 | + */ | |
| 31 | + private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); | |
| 32 | + | |
| 33 | + public void setScripts(ObjectProvider<BpmTaskAssignScript> scriptsOp) { | |
| 34 | + List<BpmTaskAssignScript> scripts = scriptsOp.orderedStream().collect(Collectors.toList()); | |
| 35 | + setScripts(scripts); | |
| 36 | + } | |
| 37 | + | |
| 38 | + public void setScripts(List<BpmTaskAssignScript> scripts) { | |
| 39 | + this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); | |
| 40 | + } | |
| 41 | + | |
| 42 | + @Override | |
| 43 | + public Set<Integer> getSupportedTypes() { | |
| 44 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); | |
| 45 | + } | |
| 46 | + | |
| 47 | + @Override | |
| 48 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 49 | + dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, | |
| 50 | + CollectionUtils.convertSet(options, String::valueOf)); | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Override | |
| 54 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 55 | + return calculateTaskCandidateUsersByScript(delegateExecution, rule.getOptions()); | |
| 56 | + } | |
| 57 | + | |
| 58 | + private Set<Long> calculateTaskCandidateUsersByScript(DelegateExecution execution, Set<Long> options) { | |
| 59 | + // 获得对应的脚本 | |
| 60 | + List<BpmTaskAssignScript> scripts = new ArrayList<>(options.size()); | |
| 61 | + options.forEach(id -> { | |
| 62 | + BpmTaskAssignScript script = scriptMap.get(id); | |
| 63 | + if (script == null) { | |
| 64 | + throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); | |
| 65 | + } | |
| 66 | + scripts.add(script); | |
| 67 | + }); | |
| 68 | + // 逐个计算任务 | |
| 69 | + Set<Long> userIds = new HashSet<>(); | |
| 70 | + scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); | |
| 71 | + return userIds; | |
| 72 | + } | |
| 73 | +} | |
| 0 | 74 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; | |
| 6 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 8 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; | |
| 9 | +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; | |
| 10 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 11 | + | |
| 12 | +import jakarta.annotation.Resource; | |
| 13 | +import java.util.HashSet; | |
| 14 | +import java.util.List; | |
| 15 | +import java.util.Set; | |
| 16 | + | |
| 17 | +public class BpmCandidateUserGroupApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { | |
| 18 | + @Resource | |
| 19 | + private BpmUserGroupService api; | |
| 20 | + @Resource | |
| 21 | + private BpmUserGroupService userGroupService; | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public Set<Integer> getSupportedTypes() { | |
| 25 | + return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); | |
| 26 | + } | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public void validRuleOptions(Integer type, Set<Long> options) { | |
| 30 | + api.validUserGroups(options); | |
| 31 | + } | |
| 32 | + | |
| 33 | + @Override | |
| 34 | + public Set<Long> doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { | |
| 35 | + List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions()); | |
| 36 | + Set<Long> userIds = new HashSet<>(); | |
| 37 | + userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); | |
| 38 | + return userIds; | |
| 39 | + } | |
| 40 | + | |
| 41 | +} | |
| 0 | 42 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.cc; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 4 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCMyPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO; | |
| 6 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCReqVO; | |
| 7 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 8 | + | |
| 9 | +// TODO @kyle:这个 Service 要不挪到 task 包下;保持统一,task 下有流程、任务、抄送等; | |
| 10 | +// TODO @kyle:中文和英文之间,有个空格,会更清晰点;例如说;流程抄送 Service 接口;中文写作习惯~ | |
| 11 | +/** | |
| 12 | + * 流程抄送Service接口 | |
| 13 | + * | |
| 14 | + * 现在是在审批的时候进行流程抄送 | |
| 15 | + */ | |
| 16 | +public interface BpmProcessInstanceCopyService { | |
| 17 | + | |
| 18 | + // TODO @kyle:无用的方法,可以去掉哈;另外,考虑到避免过多的 VO,这里就可以返回 BpmProcessInstanceCopyDO | |
| 19 | + /** | |
| 20 | + * 查询流程抄送 | |
| 21 | + * | |
| 22 | + * @param copyId 流程抄送主键 | |
| 23 | + * @return 流程抄送 | |
| 24 | + */ | |
| 25 | + BpmProcessInstanceCopyVO queryById(Long copyId); | |
| 26 | + | |
| 27 | + // TODO 芋艿:这块要 review 下;思考下~~ | |
| 28 | + /** | |
| 29 | + * 抄送 | |
| 30 | + * @param sourceInfo 抄送源信息,方便抄送处理 | |
| 31 | + * @return | |
| 32 | + */ | |
| 33 | + boolean makeCopy(BpmCandidateSourceInfo sourceInfo); | |
| 34 | + | |
| 35 | + // TODO @kyle:可以方法名改成 createProcessInstanceCopy;现在项目一般新增都用 create 为主; | |
| 36 | + /** | |
| 37 | + * 流程实例的抄送 | |
| 38 | + * | |
| 39 | + * @param userId 当前登录用户 | |
| 40 | + * @param createReqVO 创建的抄送请求 | |
| 41 | + * @return 是否抄送成功,抄送成功则返回true TODO @kyle:这里可以不用返回哈;目前一般是失败,就抛出业务异常; | |
| 42 | + */ | |
| 43 | + boolean ccProcessInstance(Long userId, BpmProcessInstanceCCReqVO createReqVO); | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 抄送的流程 | |
| 47 | + * @param loginUserId 登录用户id | |
| 48 | + * @param pageReqVO 分页请求 | |
| 49 | + * @return 抄送的分页结果 | |
| 50 | + */ | |
| 51 | + PageResult<BpmProcessInstanceCCPageItemRespVO> getMyProcessInstanceCCPage(Long loginUserId, | |
| 52 | + BpmProcessInstanceCCMyPageReqVO pageReqVO); | |
| 53 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.cc; | |
| 2 | + | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCMyPageReqVO; | |
| 6 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO; | |
| 7 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCReqVO; | |
| 8 | +import cn.iocoder.yudao.module.bpm.convert.cc.BpmProcessInstanceCopyConvert; | |
| 9 | +import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; | |
| 10 | +import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; | |
| 11 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 12 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain; | |
| 13 | +import cn.iocoder.yudao.module.bpm.service.cc.dto.BpmDelegateExecutionDTO; | |
| 14 | +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | |
| 15 | +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; | |
| 16 | +import cn.iocoder.yudao.module.bpm.util.FlowableUtils; | |
| 17 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 18 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 19 | +import jakarta.annotation.Resource; | |
| 20 | +import lombok.extern.slf4j.Slf4j; | |
| 21 | +import org.flowable.engine.RuntimeService; | |
| 22 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 23 | +import org.flowable.engine.repository.ProcessDefinition; | |
| 24 | +import org.flowable.engine.runtime.ProcessInstance; | |
| 25 | +import org.springframework.context.annotation.Lazy; | |
| 26 | +import org.springframework.stereotype.Service; | |
| 27 | +import org.springframework.validation.annotation.Validated; | |
| 28 | + | |
| 29 | +import java.time.LocalDateTime; | |
| 30 | +import java.util.*; | |
| 31 | +import java.util.stream.Collectors; | |
| 32 | + | |
| 33 | +// TODO @kyle:类注释要写下 | |
| 34 | +@Slf4j // TODO @kyle:按照 @Service、@Validated、@Slf4j,从重要到不重要的顺序; | |
| 35 | +@Service | |
| 36 | +@Validated | |
| 37 | +public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService { | |
| 38 | + @Resource // TODO @kyle:第一个变量,和类之间要有空行; | |
| 39 | + private BpmProcessInstanceCopyMapper processInstanceCopyMapper; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 和flowable有关的,查询流程名用的 TODO @kyle:可以不写哈注释; | |
| 43 | + */ | |
| 44 | + @Resource | |
| 45 | + private RuntimeService runtimeService; | |
| 46 | + | |
| 47 | + /** | |
| 48 | + * 找抄送人用的 TODO @kyle:可以不写哈注释; | |
| 49 | + */ | |
| 50 | + @Resource | |
| 51 | + private BpmCandidateSourceInfoProcessorChain processorChain; | |
| 52 | + | |
| 53 | + // TODO @kyle:多余的变量,可以去掉哈 | |
| 54 | + @Resource | |
| 55 | + @Lazy // 解决循环依赖 | |
| 56 | + private BpmTaskService bpmTaskService; | |
| 57 | + @Resource | |
| 58 | + @Lazy // 解决循环依赖 | |
| 59 | + private BpmProcessInstanceService bpmProcessInstanceService; | |
| 60 | + @Resource | |
| 61 | + private AdminUserApi adminUserApi; | |
| 62 | + | |
| 63 | + @Override | |
| 64 | + public BpmProcessInstanceCopyVO queryById(Long copyId) { | |
| 65 | + BpmProcessInstanceCopyDO bpmProcessInstanceCopyDO = processInstanceCopyMapper.selectById(copyId); | |
| 66 | + return BpmProcessInstanceCopyConvert.INSTANCE.convert(bpmProcessInstanceCopyDO); | |
| 67 | + } | |
| 68 | + | |
| 69 | + // TODO @kyle:makeCopy 和 ccProcessInstance 的调用关系,感受上反了; | |
| 70 | + // makeCopy 有点像基于规则,查找抄送人,然后创建; | |
| 71 | + // ccProcessInstance 是已经有了抄送人,然后创建; | |
| 72 | + // 建议的改造:独立基于 processInstanceCopyMapper 做 insert | |
| 73 | + @Override | |
| 74 | + public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) { | |
| 75 | + if (null == sourceInfo) { | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + | |
| 79 | + DelegateExecution executionEntity = new BpmDelegateExecutionDTO(sourceInfo.getProcessInstanceId()); | |
| 80 | + Set<Long> ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo); | |
| 81 | + if (CollUtil.isEmpty(ccCandidates)) { | |
| 82 | + log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId()); | |
| 83 | + return false; | |
| 84 | + } else { | |
| 85 | + BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO(); | |
| 86 | + // 调用 | |
| 87 | + // 设置任务id | |
| 88 | + copyDO.setTaskId(sourceInfo.getTaskId()); | |
| 89 | + copyDO.setTaskName(FlowableUtils.getTaskNameByTaskId(sourceInfo.getTaskId())); | |
| 90 | + copyDO.setProcessInstanceId(sourceInfo.getProcessInstanceId()); | |
| 91 | + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() | |
| 92 | + .processInstanceId(sourceInfo.getProcessInstanceId()) | |
| 93 | + .singleResult(); | |
| 94 | + if (null == processInstance) { | |
| 95 | + log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId()); | |
| 96 | + return false; | |
| 97 | + } | |
| 98 | + copyDO.setStartUserId(FlowableUtils.getStartUserIdFromProcessInstance(processInstance)); | |
| 99 | + copyDO.setProcessInstanceName(processInstance.getName()); | |
| 100 | + ProcessDefinition processDefinition = FlowableUtils.getProcessDefinition(processInstance.getProcessDefinitionId()); | |
| 101 | + copyDO.setProcessDefinitionCategory(processDefinition.getCategory()); | |
| 102 | + copyDO.setReason(sourceInfo.getReason()); | |
| 103 | + copyDO.setCreator(sourceInfo.getCreator()); | |
| 104 | + copyDO.setCreateTime(LocalDateTime.now()); | |
| 105 | + List<BpmProcessInstanceCopyDO> copyList = new ArrayList<>(ccCandidates.size()); | |
| 106 | + for (Long userId : ccCandidates) { | |
| 107 | + BpmProcessInstanceCopyDO copy = BpmProcessInstanceCopyConvert.INSTANCE.copy(copyDO); | |
| 108 | + copy.setUserId(userId); | |
| 109 | + copyList.add(copy); | |
| 110 | + } | |
| 111 | + return processInstanceCopyMapper.insertBatch(copyList); | |
| 112 | + } | |
| 113 | + } | |
| 114 | + | |
| 115 | + @Override | |
| 116 | + public boolean ccProcessInstance(Long userId, BpmProcessInstanceCCReqVO reqVO) { | |
| 117 | + // 在能正常审批的情况下抄送流程 | |
| 118 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 119 | + sourceInfo.setTaskId(reqVO.getTaskKey()); | |
| 120 | + sourceInfo.setProcessInstanceId(reqVO.getProcessInstanceKey()); | |
| 121 | + sourceInfo.addRule(reqVO); | |
| 122 | + sourceInfo.setCreator(String.valueOf(userId)); | |
| 123 | + sourceInfo.setReason(reqVO.getReason()); | |
| 124 | + if (!makeCopy(sourceInfo)) { | |
| 125 | + throw new RuntimeException("抄送任务失败"); | |
| 126 | + } | |
| 127 | + return false; | |
| 128 | + } | |
| 129 | + | |
| 130 | + //获取流程抄送分页 TODO @kyle:接口已经注释,这里不用注释了哈; | |
| 131 | + @Override | |
| 132 | + public PageResult<BpmProcessInstanceCCPageItemRespVO> getMyProcessInstanceCCPage(Long loginUserId, BpmProcessInstanceCCMyPageReqVO pageReqVO) { | |
| 133 | + // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 | |
| 134 | + // TODO @kyle:一般读逻辑,Service 返回 PageResult<BpmProcessInstanceCopyDO> 即可。关联数据的查询和拼接,交给 Controller;目的是:保证 Service 聚焦写逻辑,清晰简洁; | |
| 135 | + PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyMapper.selectPage(loginUserId, pageReqVO); | |
| 136 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 137 | + return new PageResult<>(pageResult.getTotal()); | |
| 138 | + } | |
| 139 | + | |
| 140 | + // TODO @kyle:这种可以简洁点;参考如下 | |
| 141 | +// Map<String, ProcessInstance> processInstanceMap = bpmProcessInstanceService.getProcessInstanceMap( | |
| 142 | +// convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId)); | |
| 143 | + | |
| 144 | + Set<String/* taskId */> taskIds = new HashSet<>(); | |
| 145 | + Set<String/* processInstaneId */> processInstaneIds = new HashSet<>(); | |
| 146 | + Set<Long/* userId */> userIds = new HashSet<>(); | |
| 147 | + for (BpmProcessInstanceCopyDO doItem : pageResult.getList()) { | |
| 148 | + taskIds.add(doItem.getTaskId()); | |
| 149 | + processInstaneIds.add(doItem.getProcessInstanceId()); | |
| 150 | + userIds.add(doItem.getStartUserId()); | |
| 151 | + Long userId = Long.valueOf(doItem.getCreator()); | |
| 152 | + userIds.add(userId); | |
| 153 | + } | |
| 154 | + | |
| 155 | + Map<String, String> taskNameByTaskIds = FlowableUtils.getTaskNameByTaskIds(taskIds); | |
| 156 | + Map<String, String> processInstanceNameByTaskIds = FlowableUtils.getProcessInstanceNameByTaskIds(processInstaneIds); | |
| 157 | + | |
| 158 | + Map<Long, String> userMap = adminUserApi.getUserList(userIds).stream().collect(Collectors.toMap( | |
| 159 | + AdminUserRespDTO::getId, AdminUserRespDTO::getNickname)); | |
| 160 | + | |
| 161 | + // 转换返回 | |
| 162 | + return BpmProcessInstanceCopyConvert.INSTANCE.convertPage(pageResult, taskNameByTaskIds, processInstanceNameByTaskIds, userMap); | |
| 163 | + } | |
| 164 | + | |
| 165 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.cc; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.Data; | |
| 5 | + | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | + | |
| 8 | +// TODO @kyle:看看是不是要删除 | |
| 9 | +/** | |
| 10 | + * 流程抄送视图对象 wf_copy | |
| 11 | + * | |
| 12 | + * @author ruoyi | |
| 13 | + * @date 2022-05-19 | |
| 14 | + */ | |
| 15 | +@Data | |
| 16 | +public class BpmProcessInstanceCopyVO { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 编号 | |
| 20 | + */ | |
| 21 | + @Schema(description = "抄送主键") | |
| 22 | + private Long id; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 发起人Id | |
| 26 | + */ | |
| 27 | + @Schema(description = "发起人Id") | |
| 28 | + private Long startUserId; | |
| 29 | + | |
| 30 | + @Schema(description = "发起人别名") | |
| 31 | + private String startUserNickname; | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 流程主键 | |
| 35 | + */ | |
| 36 | + @Schema(description = "流程实例的主键") | |
| 37 | + private String processInstanceId; | |
| 38 | + | |
| 39 | + @Schema(description = "流程实例的名字") | |
| 40 | + private String processInstanceName; | |
| 41 | + | |
| 42 | + /** | |
| 43 | + * 任务主键 | |
| 44 | + */ | |
| 45 | + @Schema(description = "发起抄送的任务编号") | |
| 46 | + private String taskId; | |
| 47 | + | |
| 48 | + @Schema(description = "发起抄送的任务名称") | |
| 49 | + private String taskName; | |
| 50 | + /** | |
| 51 | + * 用户主键 | |
| 52 | + */ | |
| 53 | + @Schema(description = "用户编号") | |
| 54 | + private Long userId; | |
| 55 | + | |
| 56 | + @Schema(description = "用户别名") | |
| 57 | + private Long userNickname; | |
| 58 | + | |
| 59 | + @Schema(description = "抄送原因") | |
| 60 | + private String reason; | |
| 61 | + | |
| 62 | + @Schema(description = "抄送人") | |
| 63 | + private String creator; | |
| 64 | + | |
| 65 | + @Schema(description = "抄送时间") | |
| 66 | + private LocalDateTime createTime; | |
| 67 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/dto/BpmDelegateExecutionDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.cc.dto; | |
| 2 | + | |
| 3 | +import org.flowable.bpmn.model.FlowElement; | |
| 4 | +import org.flowable.bpmn.model.FlowableListener; | |
| 5 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 6 | +import org.flowable.engine.delegate.ReadOnlyDelegateExecution; | |
| 7 | +import org.flowable.variable.api.persistence.entity.VariableInstance; | |
| 8 | + | |
| 9 | +import java.util.Collection; | |
| 10 | +import java.util.List; | |
| 11 | +import java.util.Map; | |
| 12 | +import java.util.Set; | |
| 13 | + | |
| 14 | +/** | |
| 15 | + * 仅为了传输processInstanceId | |
| 16 | + */ | |
| 17 | +public class BpmDelegateExecutionDTO implements DelegateExecution { | |
| 18 | + | |
| 19 | + public BpmDelegateExecutionDTO(String getProcessInstanceId) { | |
| 20 | + this.getProcessInstanceId = getProcessInstanceId; | |
| 21 | + } | |
| 22 | + | |
| 23 | + private final String getProcessInstanceId; | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public String getId() { | |
| 27 | + return null; | |
| 28 | + } | |
| 29 | + | |
| 30 | + @Override | |
| 31 | + public String getProcessInstanceId() { | |
| 32 | + return null; | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public String getRootProcessInstanceId() { | |
| 37 | + return null; | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public String getEventName() { | |
| 42 | + return null; | |
| 43 | + } | |
| 44 | + | |
| 45 | + @Override | |
| 46 | + public void setEventName(String eventName) { | |
| 47 | + | |
| 48 | + } | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public String getProcessInstanceBusinessKey() { | |
| 52 | + return null; | |
| 53 | + } | |
| 54 | + | |
| 55 | + @Override | |
| 56 | + public String getProcessInstanceBusinessStatus() { | |
| 57 | + return null; | |
| 58 | + } | |
| 59 | + | |
| 60 | + @Override | |
| 61 | + public String getProcessDefinitionId() { | |
| 62 | + return null; | |
| 63 | + } | |
| 64 | + | |
| 65 | + @Override | |
| 66 | + public String getPropagatedStageInstanceId() { | |
| 67 | + return null; | |
| 68 | + } | |
| 69 | + | |
| 70 | + @Override | |
| 71 | + public String getParentId() { | |
| 72 | + return null; | |
| 73 | + } | |
| 74 | + | |
| 75 | + @Override | |
| 76 | + public String getSuperExecutionId() { | |
| 77 | + return null; | |
| 78 | + } | |
| 79 | + | |
| 80 | + @Override | |
| 81 | + public String getCurrentActivityId() { | |
| 82 | + return null; | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + public String getTenantId() { | |
| 87 | + return null; | |
| 88 | + } | |
| 89 | + | |
| 90 | + @Override | |
| 91 | + public FlowElement getCurrentFlowElement() { | |
| 92 | + return null; | |
| 93 | + } | |
| 94 | + | |
| 95 | + @Override | |
| 96 | + public void setCurrentFlowElement(FlowElement flowElement) { | |
| 97 | + | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Override | |
| 101 | + public FlowableListener getCurrentFlowableListener() { | |
| 102 | + return null; | |
| 103 | + } | |
| 104 | + | |
| 105 | + @Override | |
| 106 | + public void setCurrentFlowableListener(FlowableListener currentListener) { | |
| 107 | + | |
| 108 | + } | |
| 109 | + | |
| 110 | + @Override | |
| 111 | + public ReadOnlyDelegateExecution snapshotReadOnly() { | |
| 112 | + return null; | |
| 113 | + } | |
| 114 | + | |
| 115 | + @Override | |
| 116 | + public DelegateExecution getParent() { | |
| 117 | + return null; | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + public List<? extends DelegateExecution> getExecutions() { | |
| 122 | + return null; | |
| 123 | + } | |
| 124 | + | |
| 125 | + @Override | |
| 126 | + public void setActive(boolean isActive) { | |
| 127 | + | |
| 128 | + } | |
| 129 | + | |
| 130 | + @Override | |
| 131 | + public boolean isActive() { | |
| 132 | + return false; | |
| 133 | + } | |
| 134 | + | |
| 135 | + @Override | |
| 136 | + public boolean isEnded() { | |
| 137 | + return false; | |
| 138 | + } | |
| 139 | + | |
| 140 | + @Override | |
| 141 | + public void setConcurrent(boolean isConcurrent) { | |
| 142 | + | |
| 143 | + } | |
| 144 | + | |
| 145 | + @Override | |
| 146 | + public boolean isConcurrent() { | |
| 147 | + return false; | |
| 148 | + } | |
| 149 | + | |
| 150 | + @Override | |
| 151 | + public boolean isProcessInstanceType() { | |
| 152 | + return false; | |
| 153 | + } | |
| 154 | + | |
| 155 | + @Override | |
| 156 | + public void inactivate() { | |
| 157 | + | |
| 158 | + } | |
| 159 | + | |
| 160 | + @Override | |
| 161 | + public boolean isScope() { | |
| 162 | + return false; | |
| 163 | + } | |
| 164 | + | |
| 165 | + @Override | |
| 166 | + public void setScope(boolean isScope) { | |
| 167 | + | |
| 168 | + } | |
| 169 | + | |
| 170 | + @Override | |
| 171 | + public boolean isMultiInstanceRoot() { | |
| 172 | + return false; | |
| 173 | + } | |
| 174 | + | |
| 175 | + @Override | |
| 176 | + public void setMultiInstanceRoot(boolean isMultiInstanceRoot) { | |
| 177 | + | |
| 178 | + } | |
| 179 | + | |
| 180 | + @Override | |
| 181 | + public Map<String, Object> getVariables() { | |
| 182 | + return null; | |
| 183 | + } | |
| 184 | + | |
| 185 | + @Override | |
| 186 | + public Map<String, VariableInstance> getVariableInstances() { | |
| 187 | + return null; | |
| 188 | + } | |
| 189 | + | |
| 190 | + @Override | |
| 191 | + public Map<String, Object> getVariables(Collection<String> collection) { | |
| 192 | + return null; | |
| 193 | + } | |
| 194 | + | |
| 195 | + @Override | |
| 196 | + public Map<String, VariableInstance> getVariableInstances(Collection<String> collection) { | |
| 197 | + return null; | |
| 198 | + } | |
| 199 | + | |
| 200 | + @Override | |
| 201 | + public Map<String, Object> getVariables(Collection<String> collection, boolean b) { | |
| 202 | + return null; | |
| 203 | + } | |
| 204 | + | |
| 205 | + @Override | |
| 206 | + public Map<String, VariableInstance> getVariableInstances(Collection<String> collection, boolean b) { | |
| 207 | + return null; | |
| 208 | + } | |
| 209 | + | |
| 210 | + @Override | |
| 211 | + public Map<String, Object> getVariablesLocal() { | |
| 212 | + return null; | |
| 213 | + } | |
| 214 | + | |
| 215 | + @Override | |
| 216 | + public Map<String, VariableInstance> getVariableInstancesLocal() { | |
| 217 | + return null; | |
| 218 | + } | |
| 219 | + | |
| 220 | + @Override | |
| 221 | + public Map<String, Object> getVariablesLocal(Collection<String> collection) { | |
| 222 | + return null; | |
| 223 | + } | |
| 224 | + | |
| 225 | + @Override | |
| 226 | + public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection) { | |
| 227 | + return null; | |
| 228 | + } | |
| 229 | + | |
| 230 | + @Override | |
| 231 | + public Map<String, Object> getVariablesLocal(Collection<String> collection, boolean b) { | |
| 232 | + return null; | |
| 233 | + } | |
| 234 | + | |
| 235 | + @Override | |
| 236 | + public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection, boolean b) { | |
| 237 | + return null; | |
| 238 | + } | |
| 239 | + | |
| 240 | + @Override | |
| 241 | + public Object getVariable(String s) { | |
| 242 | + return null; | |
| 243 | + } | |
| 244 | + | |
| 245 | + @Override | |
| 246 | + public VariableInstance getVariableInstance(String s) { | |
| 247 | + return null; | |
| 248 | + } | |
| 249 | + | |
| 250 | + @Override | |
| 251 | + public Object getVariable(String s, boolean b) { | |
| 252 | + return null; | |
| 253 | + } | |
| 254 | + | |
| 255 | + @Override | |
| 256 | + public VariableInstance getVariableInstance(String s, boolean b) { | |
| 257 | + return null; | |
| 258 | + } | |
| 259 | + | |
| 260 | + @Override | |
| 261 | + public Object getVariableLocal(String s) { | |
| 262 | + return null; | |
| 263 | + } | |
| 264 | + | |
| 265 | + @Override | |
| 266 | + public VariableInstance getVariableInstanceLocal(String s) { | |
| 267 | + return null; | |
| 268 | + } | |
| 269 | + | |
| 270 | + @Override | |
| 271 | + public Object getVariableLocal(String s, boolean b) { | |
| 272 | + return null; | |
| 273 | + } | |
| 274 | + | |
| 275 | + @Override | |
| 276 | + public VariableInstance getVariableInstanceLocal(String s, boolean b) { | |
| 277 | + return null; | |
| 278 | + } | |
| 279 | + | |
| 280 | + @Override | |
| 281 | + public <T> T getVariable(String s, Class<T> aClass) { | |
| 282 | + return null; | |
| 283 | + } | |
| 284 | + | |
| 285 | + @Override | |
| 286 | + public <T> T getVariableLocal(String s, Class<T> aClass) { | |
| 287 | + return null; | |
| 288 | + } | |
| 289 | + | |
| 290 | + @Override | |
| 291 | + public Set<String> getVariableNames() { | |
| 292 | + return null; | |
| 293 | + } | |
| 294 | + | |
| 295 | + @Override | |
| 296 | + public Set<String> getVariableNamesLocal() { | |
| 297 | + return null; | |
| 298 | + } | |
| 299 | + | |
| 300 | + @Override | |
| 301 | + public void setVariable(String s, Object o) { | |
| 302 | + | |
| 303 | + } | |
| 304 | + | |
| 305 | + @Override | |
| 306 | + public void setVariable(String s, Object o, boolean b) { | |
| 307 | + | |
| 308 | + } | |
| 309 | + | |
| 310 | + @Override | |
| 311 | + public Object setVariableLocal(String s, Object o) { | |
| 312 | + return null; | |
| 313 | + } | |
| 314 | + | |
| 315 | + @Override | |
| 316 | + public Object setVariableLocal(String s, Object o, boolean b) { | |
| 317 | + return null; | |
| 318 | + } | |
| 319 | + | |
| 320 | + @Override | |
| 321 | + public void setVariables(Map<String, ?> map) { | |
| 322 | + | |
| 323 | + } | |
| 324 | + | |
| 325 | + @Override | |
| 326 | + public void setVariablesLocal(Map<String, ?> map) { | |
| 327 | + | |
| 328 | + } | |
| 329 | + | |
| 330 | + @Override | |
| 331 | + public boolean hasVariables() { | |
| 332 | + return false; | |
| 333 | + } | |
| 334 | + | |
| 335 | + @Override | |
| 336 | + public boolean hasVariablesLocal() { | |
| 337 | + return false; | |
| 338 | + } | |
| 339 | + | |
| 340 | + @Override | |
| 341 | + public boolean hasVariable(String s) { | |
| 342 | + return false; | |
| 343 | + } | |
| 344 | + | |
| 345 | + @Override | |
| 346 | + public boolean hasVariableLocal(String s) { | |
| 347 | + return false; | |
| 348 | + } | |
| 349 | + | |
| 350 | + @Override | |
| 351 | + public void removeVariable(String s) { | |
| 352 | + | |
| 353 | + } | |
| 354 | + | |
| 355 | + @Override | |
| 356 | + public void removeVariableLocal(String s) { | |
| 357 | + | |
| 358 | + } | |
| 359 | + | |
| 360 | + @Override | |
| 361 | + public void removeVariables(Collection<String> collection) { | |
| 362 | + | |
| 363 | + } | |
| 364 | + | |
| 365 | + @Override | |
| 366 | + public void removeVariablesLocal(Collection<String> collection) { | |
| 367 | + | |
| 368 | + } | |
| 369 | + | |
| 370 | + @Override | |
| 371 | + public void removeVariables() { | |
| 372 | + | |
| 373 | + } | |
| 374 | + | |
| 375 | + @Override | |
| 376 | + public void removeVariablesLocal() { | |
| 377 | + | |
| 378 | + } | |
| 379 | + | |
| 380 | + @Override | |
| 381 | + public void setTransientVariable(String s, Object o) { | |
| 382 | + | |
| 383 | + } | |
| 384 | + | |
| 385 | + @Override | |
| 386 | + public void setTransientVariableLocal(String s, Object o) { | |
| 387 | + | |
| 388 | + } | |
| 389 | + | |
| 390 | + @Override | |
| 391 | + public void setTransientVariables(Map<String, Object> map) { | |
| 392 | + | |
| 393 | + } | |
| 394 | + | |
| 395 | + @Override | |
| 396 | + public Object getTransientVariable(String s) { | |
| 397 | + return null; | |
| 398 | + } | |
| 399 | + | |
| 400 | + @Override | |
| 401 | + public Map<String, Object> getTransientVariables() { | |
| 402 | + return null; | |
| 403 | + } | |
| 404 | + | |
| 405 | + @Override | |
| 406 | + public void setTransientVariablesLocal(Map<String, Object> map) { | |
| 407 | + | |
| 408 | + } | |
| 409 | + | |
| 410 | + @Override | |
| 411 | + public Object getTransientVariableLocal(String s) { | |
| 412 | + return null; | |
| 413 | + } | |
| 414 | + | |
| 415 | + @Override | |
| 416 | + public Map<String, Object> getTransientVariablesLocal() { | |
| 417 | + return null; | |
| 418 | + } | |
| 419 | + | |
| 420 | + @Override | |
| 421 | + public void removeTransientVariableLocal(String s) { | |
| 422 | + | |
| 423 | + } | |
| 424 | + | |
| 425 | + @Override | |
| 426 | + public void removeTransientVariable(String s) { | |
| 427 | + | |
| 428 | + } | |
| 429 | + | |
| 430 | + @Override | |
| 431 | + public void removeTransientVariables() { | |
| 432 | + | |
| 433 | + } | |
| 434 | + | |
| 435 | + @Override | |
| 436 | + public void removeTransientVariablesLocal() { | |
| 437 | + | |
| 438 | + } | |
| 439 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -19,6 +19,8 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; |
| 19 | 19 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; |
| 20 | 20 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; |
| 21 | 21 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum; |
| 22 | +import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; | |
| 23 | +import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyService; | |
| 22 | 24 | import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; |
| 23 | 25 | import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; |
| 24 | 26 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| ... | ... | @@ -94,6 +96,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 94 | 96 | @Resource |
| 95 | 97 | private ManagementService managementService; |
| 96 | 98 | |
| 99 | + @Resource | |
| 100 | + private BpmProcessInstanceCopyService processInstanceCopyService; | |
| 101 | + | |
| 97 | 102 | @Override |
| 98 | 103 | public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) { |
| 99 | 104 | // 查询待办任务 | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/util/FlowableUtils.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.util; | |
| 2 | + | |
| 3 | + | |
| 4 | +import cn.hutool.core.collection.CollUtil; | |
| 5 | +import cn.hutool.extra.spring.SpringUtil; | |
| 6 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | |
| 7 | +import org.flowable.bpmn.model.BpmnModel; | |
| 8 | +import org.flowable.bpmn.model.ExtensionElement; | |
| 9 | +import org.flowable.bpmn.model.FlowElement; | |
| 10 | +import org.flowable.bpmn.model.FlowNode; | |
| 11 | +import org.flowable.engine.RepositoryService; | |
| 12 | +import org.flowable.engine.RuntimeService; | |
| 13 | +import org.flowable.engine.TaskService; | |
| 14 | +import org.flowable.engine.repository.ProcessDefinition; | |
| 15 | +import org.flowable.engine.runtime.ProcessInstance; | |
| 16 | +import org.flowable.task.api.Task; | |
| 17 | + | |
| 18 | +import java.util.*; | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * 流程引擎工具类封装 | |
| 22 | + * | |
| 23 | + * @author: linjinp | |
| 24 | + * @create: 2019-12-24 13:51 | |
| 25 | + **/ | |
| 26 | +public class FlowableUtils { | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 获取流程名称 | |
| 30 | + * | |
| 31 | + * @param processDefinitionId | |
| 32 | + * @return | |
| 33 | + */ | |
| 34 | + public static String getProcessDefinitionName(String processDefinitionId) { | |
| 35 | + RepositoryService repositoryService = SpringUtil.getBean(RepositoryService.class); | |
| 36 | + ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId); | |
| 37 | + return processDefinition.getName(); | |
| 38 | + } | |
| 39 | + | |
| 40 | + public static ProcessDefinition getProcessDefinition(String processDefinitionId) { | |
| 41 | + RepositoryService repositoryService = SpringUtil.getBean(RepositoryService.class); | |
| 42 | + return repositoryService.getProcessDefinition(processDefinitionId); | |
| 43 | + } | |
| 44 | + | |
| 45 | + /** | |
| 46 | + * 获取节点数据 | |
| 47 | + * | |
| 48 | + * @param processInstanceId | |
| 49 | + * @param nodeId | |
| 50 | + * @return | |
| 51 | + */ | |
| 52 | + public static FlowNode getFlowNode(String processInstanceId, String nodeId) { | |
| 53 | + | |
| 54 | + RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class); | |
| 55 | + RepositoryService repositoryService = SpringUtil.getBean(RepositoryService.class); | |
| 56 | + | |
| 57 | + String definitionld = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId(); // 获取bpm(模型)对象 | |
| 58 | + BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionld); | |
| 59 | + // 传节点定义key获取当前节点 | |
| 60 | + FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(nodeId); | |
| 61 | + return flowNode; | |
| 62 | + } | |
| 63 | + | |
| 64 | + public static ExtensionElement generateFlowNodeIdExtension(String nodeId) { | |
| 65 | + ExtensionElement extensionElement = new ExtensionElement(); | |
| 66 | + extensionElement.setElementText(nodeId); | |
| 67 | + extensionElement.setName("nodeId"); | |
| 68 | + extensionElement.setNamespacePrefix("flowable"); | |
| 69 | + extensionElement.setNamespace("nodeId"); | |
| 70 | + return extensionElement; | |
| 71 | + } | |
| 72 | + | |
| 73 | + public static String getNodeIdFromExtension(FlowElement flowElement) { | |
| 74 | + Map<String, List<ExtensionElement>> extensionElements = flowElement.getExtensionElements(); | |
| 75 | + return extensionElements.get("nodeId").get(0).getElementText(); | |
| 76 | + } | |
| 77 | + | |
| 78 | + public static Long getStartUserIdFromProcessInstance(ProcessInstance instance) { | |
| 79 | + if (null == instance) { | |
| 80 | + return null; | |
| 81 | + } | |
| 82 | + return NumberUtils.parseLong(instance.getStartUserId()); | |
| 83 | + } | |
| 84 | + | |
| 85 | + public static String getTaskNameByTaskId(String taskId) { | |
| 86 | + TaskService taskService = SpringUtil.getBean(TaskService.class); | |
| 87 | + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); | |
| 88 | + return task.getName(); | |
| 89 | + } | |
| 90 | + | |
| 91 | + // TODO @kyle:Utils 里不做查询;可以封装到 bpmTaskService 里 | |
| 92 | + public static Map<String/* taskId */, String/* taskName */> getTaskNameByTaskIds(Collection<String> taskIds) { | |
| 93 | + TaskService taskService = SpringUtil.getBean(TaskService.class); | |
| 94 | + List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list(); | |
| 95 | + if (CollUtil.isNotEmpty(tasks)) { | |
| 96 | + Map<String/* taskId */, String/* taskName */> taskMap = new HashMap<>(tasks.size()); | |
| 97 | + for (Task task : tasks) { | |
| 98 | + taskMap.putIfAbsent(task.getId(), task.getName()); | |
| 99 | + } | |
| 100 | + return taskMap; | |
| 101 | + } | |
| 102 | + return Collections.emptyMap(); | |
| 103 | + } | |
| 104 | + | |
| 105 | + public static String getProcessInstanceNameByTaskId(String processInstanceId) { | |
| 106 | + RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class); | |
| 107 | + ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() | |
| 108 | + .processInstanceId(processInstanceId) | |
| 109 | + .singleResult(); | |
| 110 | + return processInstance.getName(); | |
| 111 | + } | |
| 112 | + | |
| 113 | + // TODO @kyle:Utils 里不做查询;可以封装到 bpmTaskService 里 | |
| 114 | + public static Map<String/* processInstaneId */, String/* processInstaneName */> getProcessInstanceNameByTaskIds(Set<String> taskIds) { | |
| 115 | + RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class); | |
| 116 | + List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().processInstanceIds(taskIds).list(); | |
| 117 | + if (CollUtil.isNotEmpty(processInstances)) { | |
| 118 | + Map<String/* processInstaneId */, String/* processInstaneName */> processInstaneMap = new HashMap<>(processInstances.size()); | |
| 119 | + for (ProcessInstance processInstance : processInstances) { | |
| 120 | + processInstaneMap.putIfAbsent(processInstance.getId(), processInstance.getName()); | |
| 121 | + } | |
| 122 | + return processInstaneMap; | |
| 123 | + } | |
| 124 | + return Collections.emptyMap(); | |
| 125 | + } | |
| 126 | + | |
| 127 | +} | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.candidate; | |
| 2 | + | |
| 3 | +import cn.hutool.core.map.MapUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | |
| 5 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 6 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | |
| 7 | +import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; | |
| 8 | +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; | |
| 9 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | |
| 10 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; | |
| 11 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | |
| 12 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX1Script; | |
| 13 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX2Script; | |
| 14 | +import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.BpmCandidateScriptApiSourceInfoProcessor; | |
| 15 | +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; | |
| 16 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | |
| 17 | +import cn.iocoder.yudao.module.system.api.dept.PostApi; | |
| 18 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | |
| 19 | +import cn.iocoder.yudao.module.system.api.dict.DictDataApi; | |
| 20 | +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; | |
| 21 | +import cn.iocoder.yudao.module.system.api.permission.RoleApi; | |
| 22 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | |
| 23 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | |
| 24 | +import jakarta.annotation.Resource; | |
| 25 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 26 | +import org.junit.jupiter.api.Test; | |
| 27 | +import org.springframework.boot.test.mock.mockito.MockBean; | |
| 28 | +import org.springframework.context.annotation.Import; | |
| 29 | + | |
| 30 | +import java.util.Arrays; | |
| 31 | +import java.util.List; | |
| 32 | +import java.util.Map; | |
| 33 | +import java.util.Set; | |
| 34 | + | |
| 35 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | |
| 36 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | |
| 37 | +import static java.util.Collections.singleton; | |
| 38 | +import static org.junit.jupiter.api.Assertions.assertEquals; | |
| 39 | +import static org.mockito.ArgumentMatchers.eq; | |
| 40 | +import static org.mockito.Mockito.when; | |
| 41 | + | |
| 42 | +@Import({BpmCandidateSourceInfoProcessorChain.class, | |
| 43 | + BpmCandidateScriptApiSourceInfoProcessor.class, BpmTaskAssignLeaderX1Script.class, | |
| 44 | + BpmTaskAssignLeaderX2Script.class}) | |
| 45 | +public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest { | |
| 46 | + @Resource | |
| 47 | + private BpmCandidateSourceInfoProcessorChain processorChain; | |
| 48 | + | |
| 49 | + @MockBean | |
| 50 | + private BpmUserGroupService userGroupService; | |
| 51 | + @MockBean | |
| 52 | + private DeptApi deptApi; | |
| 53 | + @MockBean | |
| 54 | + private AdminUserApi adminUserApi; | |
| 55 | + @MockBean | |
| 56 | + private PermissionApi permissionApi; | |
| 57 | + @MockBean | |
| 58 | + private RoleApi roleApi; | |
| 59 | + @MockBean | |
| 60 | + private PostApi postApi; | |
| 61 | + @MockBean | |
| 62 | + private DictDataApi dictDataApi; | |
| 63 | + @Resource | |
| 64 | + private BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor; | |
| 65 | + | |
| 66 | + @Test | |
| 67 | + public void testCalculateTaskCandidateUsers_Role() { | |
| 68 | + // 准备参数 | |
| 69 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 70 | + .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); | |
| 71 | + // mock 方法 | |
| 72 | + when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) | |
| 73 | + .thenReturn(asSet(11L, 22L)); | |
| 74 | + mockGetUserMap(asSet(11L, 22L)); | |
| 75 | + | |
| 76 | + // 调用 | |
| 77 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 78 | + sourceInfo.addRule(rule); | |
| 79 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 80 | + // 断言 | |
| 81 | + assertEquals(asSet(11L, 22L), results); | |
| 82 | + } | |
| 83 | + | |
| 84 | + @Test | |
| 85 | + public void testCalculateTaskCandidateUsers_DeptMember() { | |
| 86 | + // 准备参数 | |
| 87 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 88 | + .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); | |
| 89 | + // mock 方法 | |
| 90 | + List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), | |
| 91 | + id -> new AdminUserRespDTO().setId(id)); | |
| 92 | + when(adminUserApi.getUserListByDeptIds(eq(rule.getOptions()))).thenReturn(users); | |
| 93 | + mockGetUserMap(asSet(11L, 22L)); | |
| 94 | + | |
| 95 | + // 调用 | |
| 96 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 97 | + sourceInfo.addRule(rule); | |
| 98 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 99 | + // 断言 | |
| 100 | + assertEquals(asSet(11L, 22L), results); | |
| 101 | + } | |
| 102 | + | |
| 103 | + @Test | |
| 104 | + public void testCalculateTaskCandidateUsers_DeptLeader() { | |
| 105 | + // 准备参数 | |
| 106 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 107 | + .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); | |
| 108 | + // mock 方法 | |
| 109 | + DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); | |
| 110 | + DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); | |
| 111 | + when(deptApi.getDeptList(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); | |
| 112 | + mockGetUserMap(asSet(11L, 22L)); | |
| 113 | + | |
| 114 | + // 调用 | |
| 115 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 116 | + sourceInfo.addRule(rule); | |
| 117 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 118 | + // 断言 | |
| 119 | + assertEquals(asSet(11L, 22L), results); | |
| 120 | + } | |
| 121 | + | |
| 122 | + @Test | |
| 123 | + public void testCalculateTaskCandidateUsers_Post() { | |
| 124 | + // 准备参数 | |
| 125 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 126 | + .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); | |
| 127 | + // mock 方法 | |
| 128 | + List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), | |
| 129 | + id -> new AdminUserRespDTO().setId(id)); | |
| 130 | + when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users); | |
| 131 | + mockGetUserMap(asSet(11L, 22L)); | |
| 132 | + | |
| 133 | + // 调用 | |
| 134 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 135 | + sourceInfo.addRule(rule); | |
| 136 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 137 | + // 断言 | |
| 138 | + assertEquals(asSet(11L, 22L), results); | |
| 139 | + } | |
| 140 | + | |
| 141 | + @Test | |
| 142 | + public void testCalculateTaskCandidateUsers_User() { | |
| 143 | + // 准备参数 | |
| 144 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 145 | + .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); | |
| 146 | + // mock 方法 | |
| 147 | + mockGetUserMap(asSet(1L, 2L)); | |
| 148 | + | |
| 149 | + // 调用 | |
| 150 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 151 | + sourceInfo.addRule(rule); | |
| 152 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 153 | + // 断言 | |
| 154 | + assertEquals(asSet(1L, 2L), results); | |
| 155 | + } | |
| 156 | + | |
| 157 | + @Test | |
| 158 | + public void testCalculateTaskCandidateUsers_UserGroup() { | |
| 159 | + // 准备参数 | |
| 160 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) | |
| 161 | + .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); | |
| 162 | + // mock 方法 | |
| 163 | + BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); | |
| 164 | + BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); | |
| 165 | + when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2)); | |
| 166 | + mockGetUserMap(asSet(11L, 12L, 21L, 22L)); | |
| 167 | + | |
| 168 | + // 调用 | |
| 169 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 170 | + sourceInfo.addRule(rule); | |
| 171 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 172 | + // 断言 | |
| 173 | + assertEquals(asSet(11L, 12L, 21L, 22L), results); | |
| 174 | + } | |
| 175 | + | |
| 176 | + private void mockGetUserMap(Set<Long> assigneeUserIds) { | |
| 177 | + Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, | |
| 178 | + id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 179 | + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); | |
| 180 | + } | |
| 181 | + | |
| 182 | + @Test | |
| 183 | + public void testCalculateTaskCandidateUsers_Script() { | |
| 184 | + // 准备参数 | |
| 185 | + BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(20L, 21L)) | |
| 186 | + .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); | |
| 187 | + // mock 方法 | |
| 188 | + BpmTaskAssignScript script1 = new BpmTaskAssignScript() { | |
| 189 | + | |
| 190 | + @Override | |
| 191 | + public Set<Long> calculateTaskCandidateUsers(DelegateExecution task) { | |
| 192 | + return singleton(11L); | |
| 193 | + } | |
| 194 | + | |
| 195 | + @Override | |
| 196 | + public BpmTaskRuleScriptEnum getEnum() { | |
| 197 | + return BpmTaskRuleScriptEnum.LEADER_X1; | |
| 198 | + } | |
| 199 | + }; | |
| 200 | + BpmTaskAssignScript script2 = new BpmTaskAssignScript() { | |
| 201 | + | |
| 202 | + @Override | |
| 203 | + public Set<Long> calculateTaskCandidateUsers(DelegateExecution task) { | |
| 204 | + return singleton(22L); | |
| 205 | + } | |
| 206 | + | |
| 207 | + @Override | |
| 208 | + public BpmTaskRuleScriptEnum getEnum() { | |
| 209 | + return BpmTaskRuleScriptEnum.LEADER_X2; | |
| 210 | + } | |
| 211 | + }; | |
| 212 | + bpmCandidateScriptApiSourceInfoProcessor.setScripts(Arrays.asList(script1, script2)); | |
| 213 | + mockGetUserMap(asSet(11L, 22L)); | |
| 214 | + | |
| 215 | + // 调用 | |
| 216 | + BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); | |
| 217 | + sourceInfo.addRule(rule); | |
| 218 | + Set<Long> results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); | |
| 219 | + // 断言 | |
| 220 | + assertEquals(asSet(11L, 22L), results); | |
| 221 | + } | |
| 222 | + | |
| 223 | + @Test | |
| 224 | + public void testRemoveDisableUsers() { | |
| 225 | + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 | |
| 226 | + Set<Long> assigneeUserIds = asSet(1L, 2L, 3L); | |
| 227 | + // mock 方法 | |
| 228 | + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) | |
| 229 | + .setStatus(CommonStatusEnum.ENABLE.getStatus())); | |
| 230 | + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) | |
| 231 | + .setStatus(CommonStatusEnum.DISABLE.getStatus())); | |
| 232 | + Map<Long, AdminUserRespDTO> userMap = MapUtil.builder(user1.getId(), user1) | |
| 233 | + .put(user2.getId(), user2).build(); | |
| 234 | + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); | |
| 235 | + | |
| 236 | + // 调用 | |
| 237 | + processorChain.removeDisableUsers(assigneeUserIds); | |
| 238 | + // 断言 | |
| 239 | + assertEquals(asSet(1L), assigneeUserIds); | |
| 240 | + } | |
| 241 | + | |
| 242 | +} | |
| 0 | 243 | \ No newline at end of file | ... | ... |
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyServiceTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.service.cc; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | |
| 4 | +import jakarta.annotation.Resource; | |
| 5 | +import org.junit.jupiter.api.Test; | |
| 6 | +import org.springframework.context.annotation.Import; | |
| 7 | + | |
| 8 | +@Import({BpmProcessInstanceCopyServiceImpl.class}) | |
| 9 | +class BpmProcessInstanceCopyServiceTest extends BaseDbUnitTest { | |
| 10 | + @Resource | |
| 11 | + private BpmProcessInstanceCopyServiceImpl service; | |
| 12 | + | |
| 13 | + @Test | |
| 14 | + void queryById() { | |
| 15 | + } | |
| 16 | +} | |
| 0 | 17 | \ No newline at end of file | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/DictTypeConstants.java
| ... | ... | @@ -13,5 +13,6 @@ public interface DictTypeConstants { |
| 13 | 13 | String CRM_AUDIT_STATUS = "crm_audit_status"; // CRM 审批状态 |
| 14 | 14 | String CRM_PRODUCT_UNIT = "crm_product_unit"; // CRM 产品单位 |
| 15 | 15 | String CRM_PRODUCT_STATUS = "crm_product_status"; // CRM 产品状态 |
| 16 | + String CRM_FOLLOW_UP_TYPE = "crm_follow_up_type"; // CRM 跟进方式 | |
| 16 | 17 | |
| 17 | 18 | } | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
| ... | ... | @@ -14,9 +14,12 @@ public interface ErrorCodeConstants { |
| 14 | 14 | |
| 15 | 15 | // ========== 线索管理 1-020-001-000 ========== |
| 16 | 16 | ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在"); |
| 17 | + ErrorCode CLUE_ANY_CLUE_NOT_EXISTS = new ErrorCode(1_020_001_001, "线索【{}】不存在"); | |
| 18 | + ErrorCode CLUE_ANY_CLUE_ALREADY_TRANSLATED = new ErrorCode(1_020_001_002, "线索【{}】已经转化过了,请勿重复转化"); | |
| 17 | 19 | |
| 18 | 20 | // ========== 商机管理 1-020-002-000 ========== |
| 19 | 21 | ErrorCode BUSINESS_NOT_EXISTS = new ErrorCode(1_020_002_000, "商机不存在"); |
| 22 | + ErrorCode BUSINESS_CONTRACT_EXISTS = new ErrorCode(1_020_002_001, "商机已关联合同,不能删除"); | |
| 20 | 23 | |
| 21 | 24 | // TODO @lilleo:商机状态、商机类型,都单独错误码段 |
| 22 | 25 | |
| ... | ... | @@ -24,6 +27,7 @@ public interface ErrorCodeConstants { |
| 24 | 27 | // ========== 联系人管理 1-020-003-000 ========== |
| 25 | 28 | ErrorCode CONTACT_NOT_EXISTS = new ErrorCode(1_020_003_000, "联系人不存在"); |
| 26 | 29 | ErrorCode CONTACT_BUSINESS_LINK_NOT_EXISTS = new ErrorCode( 1_020_003_001, "联系人商机关联不存在"); |
| 30 | + ErrorCode CONTACT_DELETE_FAIL_CONTRACT_LINK_EXISTS = new ErrorCode( 1_020_003_002, "联系人已关联合同,不能删除"); | |
| 27 | 31 | |
| 28 | 32 | // ========== 回款 1-020-004-000 ========== |
| 29 | 33 | ErrorCode RECEIVABLE_NOT_EXISTS = new ErrorCode(1_020_004_000, "回款不存在"); |
| ... | ... | @@ -39,6 +43,11 @@ public interface ErrorCodeConstants { |
| 39 | 43 | ErrorCode CUSTOMER_IN_POOL = new ErrorCode(1_020_006_004, "客户【{}】放入公海失败,原因:已经是公海客户"); |
| 40 | 44 | ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定"); |
| 41 | 45 | ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常"); |
| 46 | + ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态"); | |
| 47 | + ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "解锁客户失败,它已经处于未锁定状态"); | |
| 48 | + ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限"); | |
| 49 | + ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限"); | |
| 50 | + ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}"); | |
| 42 | 51 | |
| 43 | 52 | // ========== 权限管理 1_020_007_000 ========== |
| 44 | 53 | ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在"); |
| ... | ... | @@ -49,6 +58,7 @@ public interface ErrorCodeConstants { |
| 49 | 58 | ErrorCode CRM_PERMISSION_DELETE_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_005, "删除数据权限失败,原因:存在负责人"); |
| 50 | 59 | ErrorCode CRM_PERMISSION_DELETE_DENIED = new ErrorCode(1_020_007_006, "删除数据权限失败,原因:没有权限"); |
| 51 | 60 | ErrorCode CRM_PERMISSION_DELETE_SELF_PERMISSION_FAIL_EXIST_OWNER = new ErrorCode(1_020_007_007, "删除数据权限失败,原因:不能删除负责人"); |
| 61 | + ErrorCode CRM_PERMISSION_CREATE_FAIL = new ErrorCode(1_020_007_008, "创建数据权限失败,原因:所加用户已有权限"); | |
| 52 | 62 | |
| 53 | 63 | // ========== 产品 1_020_008_000 ========== |
| 54 | 64 | ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); |
| ... | ... | @@ -72,4 +82,8 @@ public interface ErrorCodeConstants { |
| 72 | 82 | // ========== 客户公海规则设置 1_020_012_000 ========== |
| 73 | 83 | ErrorCode CUSTOMER_LIMIT_CONFIG_NOT_EXISTS = new ErrorCode(1_020_012_000, "客户限制配置不存在"); |
| 74 | 84 | |
| 85 | + // ========== 跟进记录 1_020_013_000 ========== | |
| 86 | + ErrorCode FOLLOW_UP_RECORD_NOT_EXISTS = new ErrorCode(1_020_013_000, "跟进记录不存在"); | |
| 87 | + ErrorCode FOLLOW_UP_RECORD_DELETE_DENIED = new ErrorCode(1_020_013_001, "删除跟进记录失败,原因:没有权限"); | |
| 88 | + | |
| 75 | 89 | } | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.enums; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * CRM 操作日志枚举 | |
| 5 | + * 目的:统一管理,也减少 Service 里各种“复杂”字符串 | |
| 6 | + * | |
| 7 | + * @author HUIHUI | |
| 8 | + */ | |
| 9 | +public interface LogRecordConstants { | |
| 10 | + | |
| 11 | + // ======================= CRM_LEADS 线索 ======================= | |
| 12 | + | |
| 13 | + String CRM_LEADS_TYPE = "CRM 线索"; | |
| 14 | + | |
| 15 | + // ======================= CRM_CUSTOMER 客户 ======================= | |
| 16 | + | |
| 17 | + String CRM_CUSTOMER_TYPE = "CRM 客户"; | |
| 18 | + String CRM_CUSTOMER_CREATE_SUB_TYPE = "创建客户"; | |
| 19 | + String CRM_CUSTOMER_CREATE_SUCCESS = "创建了客户{{#customer.name}}"; | |
| 20 | + String CRM_CUSTOMER_UPDATE_SUB_TYPE = "更新客户"; | |
| 21 | + String CRM_CUSTOMER_UPDATE_SUCCESS = "更新了客户【{{#customerName}}】: {_DIFF{#updateReqVO}}"; | |
| 22 | + String CRM_CUSTOMER_DELETE_SUB_TYPE = "删除客户"; | |
| 23 | + String CRM_CUSTOMER_DELETE_SUCCESS = "删除了客户【{{#customerName}}】"; | |
| 24 | + String CRM_CUSTOMER_TRANSFER_SUB_TYPE = "转移客户"; | |
| 25 | + String CRM_CUSTOMER_TRANSFER_SUCCESS = "将客户【{{#customer.name}}】的负责人从【{getAdminUserById{#customer.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | |
| 26 | + String CRM_CUSTOMER_LOCK_SUB_TYPE = "{{#customer.lockStatus ? '解锁客户' : '锁定客户'}}"; | |
| 27 | + String CRM_CUSTOMER_LOCK_SUCCESS = "{{#customer.lockStatus ? '将客户【' + #customer.name + '】解锁' : '将客户【' + #customer.name + '】锁定'}}"; | |
| 28 | + String CRM_CUSTOMER_POOL_SUB_TYPE = "客户放入公海"; | |
| 29 | + String CRM_CUSTOMER_POOL_SUCCESS = "将客户【{{#customerName}}】放入了公海"; | |
| 30 | + String CRM_CUSTOMER_RECEIVE_SUB_TYPE = "{{#ownerUserName != null ? '分配客户' : '领取客户'}}"; | |
| 31 | + String CRM_CUSTOMER_RECEIVE_SUCCESS = "{{#ownerUserName != null ? '将客户【' + #customer.name + '】分配给【' + #ownerUserName + '】' : '领取客户【' + #customer.name + '】'}}"; | |
| 32 | + | |
| 33 | + // ======================= CRM_CUSTOMER_LIMIT_CONFIG 客户限制配置 ======================= | |
| 34 | + | |
| 35 | + String CRM_CUSTOMER_LIMIT_CONFIG_TYPE = "CRM 客户限制配置"; | |
| 36 | + String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUB_TYPE = "创建客户限制配置"; | |
| 37 | + String CRM_CUSTOMER_LIMIT_CONFIG_CREATE_SUCCESS = "创建了【{{#limitType}}】类型的客户限制配置"; | |
| 38 | + String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUB_TYPE = "更新客户限制配置"; | |
| 39 | + String CRM_CUSTOMER_LIMIT_CONFIG_UPDATE_SUCCESS = "更新了客户限制配置: {_DIFF{#updateReqVO}}"; | |
| 40 | + String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUB_TYPE = "删除客户限制配置"; | |
| 41 | + String CRM_CUSTOMER_LIMIT_CONFIG_DELETE_SUCCESS = "删除了【{{#limitType}}】类型的客户限制配置"; | |
| 42 | + | |
| 43 | + // ======================= CRM_CUSTOMER_POOL_CONFIG 客户公海规则 ======================= | |
| 44 | + | |
| 45 | + String CRM_CUSTOMER_POOL_CONFIG_TYPE = "CRM 客户公海规则"; | |
| 46 | + String CRM_CUSTOMER_POOL_CONFIG_SUB_TYPE = "{{#isPoolConfigUpdate ? '更新客户公海规则' : '创建客户公海规则'}}"; | |
| 47 | + String CRM_CUSTOMER_POOL_CONFIG_SUCCESS = "{{#isPoolConfigUpdate ? '更新了客户公海规则' : '创建了客户公海规则'}}"; | |
| 48 | + | |
| 49 | + // ======================= CRM_CONTACT 联系人 ======================= | |
| 50 | + | |
| 51 | + String CRM_CONTACT_TYPE = "CRM 联系人"; | |
| 52 | + String CRM_CONTACT_CREATE_SUB_TYPE = "创建联系人"; | |
| 53 | + String CRM_CONTACT_CREATE_SUCCESS = "创建了联系人{{#contact.name}}"; | |
| 54 | + String CRM_CONTACT_UPDATE_SUB_TYPE = "更新联系人"; | |
| 55 | + String CRM_CONTACT_UPDATE_SUCCESS = "更新了联系人【{{#contactName}}】: {_DIFF{#updateReqVO}}"; | |
| 56 | + String CRM_CONTACT_DELETE_SUB_TYPE = "删除联系人"; | |
| 57 | + String CRM_CONTACT_DELETE_SUCCESS = "删除了联系人【{{#contactName}}】"; | |
| 58 | + String CRM_CONTACT_TRANSFER_SUB_TYPE = "转移联系人"; | |
| 59 | + String CRM_CONTACT_TRANSFER_SUCCESS = "将联系人【{{#contact.name}}】的负责人从【{getAdminUserById{#contact.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | |
| 60 | + | |
| 61 | + // ======================= CRM_BUSINESS 商机 ======================= | |
| 62 | + | |
| 63 | + String CRM_BUSINESS_TYPE = "CRM 商机"; | |
| 64 | + String CRM_BUSINESS_CREATE_SUB_TYPE = "创建商机"; | |
| 65 | + String CRM_BUSINESS_CREATE_SUCCESS = "创建了商机{{#business.name}}"; | |
| 66 | + String CRM_BUSINESS_UPDATE_SUB_TYPE = "更新商机"; | |
| 67 | + String CRM_BUSINESS_UPDATE_SUCCESS = "更新了商机【{{#businessName}}】: {_DIFF{#updateReqVO}}"; | |
| 68 | + String CRM_BUSINESS_DELETE_SUB_TYPE = "删除商机"; | |
| 69 | + String CRM_BUSINESS_DELETE_SUCCESS = "删除了商机【{{#businessName}}】"; | |
| 70 | + String CRM_BUSINESS_TRANSFER_SUB_TYPE = "转移商机"; | |
| 71 | + String CRM_BUSINESS_TRANSFER_SUCCESS = "将商机【{{#business.name}}】的负责人从【{getAdminUserById{#business.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | |
| 72 | + | |
| 73 | + // ======================= CRM_CONTRACT 合同 ======================= | |
| 74 | + | |
| 75 | + String CRM_CONTRACT_TYPE = "CRM 合同"; | |
| 76 | + String CRM_CONTRACT_CREATE_SUB_TYPE = "创建合同"; | |
| 77 | + String CRM_CONTRACT_CREATE_SUCCESS = "创建了合同{{#contract.name}}"; | |
| 78 | + String CRM_CONTRACT_UPDATE_SUB_TYPE = "更新合同"; | |
| 79 | + String CRM_CONTRACT_UPDATE_SUCCESS = "更新了合同【{{#contractName}}】: {_DIFF{#updateReqVO}}"; | |
| 80 | + String CRM_CONTRACT_DELETE_SUB_TYPE = "删除合同"; | |
| 81 | + String CRM_CONTRACT_DELETE_SUCCESS = "删除了合同【{{#contractName}}】"; | |
| 82 | + String CRM_CONTRACT_TRANSFER_SUB_TYPE = "转移合同"; | |
| 83 | + String CRM_CONTRACT_TRANSFER_SUCCESS = "将合同【{{#contract.name}}】的负责人从【{getAdminUserById{#contract.ownerUserId}}】变更为了【{getAdminUserById{#reqVO.newOwnerUserId}}】"; | |
| 84 | + | |
| 85 | + // ======================= CRM_PRODUCT 产品 ======================= | |
| 86 | + | |
| 87 | + String CRM_PRODUCT_TYPE = "CRM 产品"; | |
| 88 | + String CRM_PRODUCT_CREATE_SUB_TYPE = "创建产品"; | |
| 89 | + String CRM_PRODUCT_CREATE_SUCCESS = "创建了产品【{{#createReqVO.name}}】"; | |
| 90 | + String CRM_PRODUCT_UPDATE_SUB_TYPE = "更新产品"; | |
| 91 | + String CRM_PRODUCT_UPDATE_SUCCESS = "更新了产品【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; | |
| 92 | + String CRM_PRODUCT_DELETE_SUB_TYPE = "删除产品"; | |
| 93 | + String CRM_PRODUCT_DELETE_SUCCESS = "删除了产品【{{#product.name}}】"; | |
| 94 | + | |
| 95 | + // ======================= CRM_PRODUCT_CATEGORY 产品分类 ======================= | |
| 96 | + | |
| 97 | + String CRM_PRODUCT_CATEGORY_TYPE = "CRM 产品分类"; | |
| 98 | + String CRM_PRODUCT_CATEGORY_CREATE_SUB_TYPE = "创建产品分类"; | |
| 99 | + String CRM_PRODUCT_CATEGORY_CREATE_SUCCESS = "创建了产品分类【{{#createReqVO.name}}】"; | |
| 100 | + String CRM_PRODUCT_CATEGORY_UPDATE_SUB_TYPE = "更新产品分类"; | |
| 101 | + String CRM_PRODUCT_CATEGORY_UPDATE_SUCCESS = "更新了产品分类【{{#updateReqVO.name}}】: {_DIFF{#updateReqVO}}"; | |
| 102 | + String CRM_PRODUCT_CATEGORY_DELETE_SUB_TYPE = "删除产品分类"; | |
| 103 | + String CRM_PRODUCT_CATEGORY_DELETE_SUCCESS = "删除了产品分类【{{#productCategory.name}}】"; | |
| 104 | + | |
| 105 | + // ======================= CRM_RECEIVABLE 回款 ======================= | |
| 106 | + | |
| 107 | + String CRM_RECEIVABLE_TYPE = "CRM 回款"; | |
| 108 | + String CRM_RECEIVABLE_CREATE_SUB_TYPE = "创建回款"; | |
| 109 | + String CRM_RECEIVABLE_CREATE_SUCCESS = "创建了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; | |
| 110 | + String CRM_RECEIVABLE_UPDATE_SUB_TYPE = "更新回款"; | |
| 111 | + String CRM_RECEIVABLE_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款: {_DIFF{#updateReqVO}}"; | |
| 112 | + String CRM_RECEIVABLE_DELETE_SUB_TYPE = "删除回款"; | |
| 113 | + String CRM_RECEIVABLE_DELETE_SUCCESS = "删除了合同【{getContractById{#receivable.contractId}}】的第【{{#receivable.period}}】期回款"; | |
| 114 | + | |
| 115 | + // ======================= CRM_RECEIVABLE_PLAN 回款计划 ======================= | |
| 116 | + | |
| 117 | + String CRM_RECEIVABLE_PLAN_TYPE = "CRM 回款计划"; | |
| 118 | + String CRM_RECEIVABLE_PLAN_CREATE_SUB_TYPE = "创建回款计划"; | |
| 119 | + String CRM_RECEIVABLE_PLAN_CREATE_SUCCESS = "创建了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; | |
| 120 | + String CRM_RECEIVABLE_PLAN_UPDATE_SUB_TYPE = "更新回款计划"; | |
| 121 | + String CRM_RECEIVABLE_PLAN_UPDATE_SUCCESS = "更新了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划: {_DIFF{#updateReqVO}}"; | |
| 122 | + String CRM_RECEIVABLE_PLAN_DELETE_SUB_TYPE = "删除回款计划"; | |
| 123 | + String CRM_RECEIVABLE_PLAN_DELETE_SUCCESS = "删除了合同【{getContractById{#receivablePlan.contractId}}】的第【{{#receivablePlan.period}}】期回款计划"; | |
| 124 | + | |
| 125 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/business/CrmBizEndStatus.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.enums.business; | |
| 2 | + | |
| 3 | +import cn.hutool.core.util.ObjectUtil; | |
| 4 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 5 | +import lombok.Getter; | |
| 6 | +import lombok.RequiredArgsConstructor; | |
| 7 | + | |
| 8 | +import java.util.Arrays; | |
| 9 | + | |
| 10 | +// TODO @lzxhqs:1)title、description、create 可以删除,非标准的 javadoc 注释哈,然后可以在类上加下这个类的注释;2)CrmBizEndStatus 改成 CrmBusinessEndStatus,非必要不缩写哈,可阅读比较重要 | |
| 11 | +/** | |
| 12 | + * @author lzxhqs | |
| 13 | + * @version 1.0 | |
| 14 | + * @title CrmBizEndStatus | |
| 15 | + * @description | |
| 16 | + * @create 2024/1/12 | |
| 17 | + */ | |
| 18 | +@RequiredArgsConstructor | |
| 19 | +@Getter | |
| 20 | +public enum CrmBizEndStatus implements IntArrayValuable { | |
| 21 | + | |
| 22 | + WIN(1, "赢单"), | |
| 23 | + LOSE(2, "输单"), | |
| 24 | + INVALID(3, "无效"); | |
| 25 | + | |
| 26 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizEndStatus::getStatus).toArray(); | |
| 27 | + | |
| 28 | + // TODO @lzxhqs:这里的方法,建议放到 49 行之后;一般类里是,静态变量,普通变量;静态方法;普通方法 | |
| 29 | + public static boolean isWin(Integer status) { | |
| 30 | + return ObjectUtil.equal(WIN.getStatus(), status); | |
| 31 | + } | |
| 32 | + | |
| 33 | + public static boolean isLose(Integer status) { | |
| 34 | + return ObjectUtil.equal(LOSE.getStatus(), status); | |
| 35 | + } | |
| 36 | + | |
| 37 | + public static boolean isInvalid(Integer status) { | |
| 38 | + return ObjectUtil.equal(INVALID.getStatus(), status); | |
| 39 | + } | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 场景类型 | |
| 43 | + */ | |
| 44 | + private final Integer status; | |
| 45 | + /** | |
| 46 | + * 场景名称 | |
| 47 | + */ | |
| 48 | + private final String name; | |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public int[] array() { | |
| 52 | + return ARRAYS; | |
| 53 | + } | |
| 54 | + | |
| 55 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmBizTypeEnum.java
| ... | ... | @@ -22,7 +22,9 @@ public enum CrmBizTypeEnum implements IntArrayValuable { |
| 22 | 22 | CRM_CONTACT(3, "联系人"), |
| 23 | 23 | CRM_BUSINESS(4, "商机"), |
| 24 | 24 | CRM_CONTRACT(5, "合同"), |
| 25 | - CRM_PRODUCT(6, "产品") | |
| 25 | + CRM_PRODUCT(6, "产品"), | |
| 26 | + CRM_RECEIVABLE(7, "回款"), | |
| 27 | + CRM_RECEIVABLE_PLAN(8, "回款计划") | |
| 26 | 28 | ; |
| 27 | 29 | |
| 28 | 30 | public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmBizTypeEnum::getType).toArray(); | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneEnum.java renamed to yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/common/CrmSceneTypeEnum.java
| ... | ... | @@ -7,7 +7,6 @@ import lombok.Getter; |
| 7 | 7 | |
| 8 | 8 | import java.util.Arrays; |
| 9 | 9 | |
| 10 | -// TODO @puhui999:这个枚举,要不改成 CrmSceneTypeEnum | |
| 11 | 10 | /** |
| 12 | 11 | * CRM 列表检索场景 |
| 13 | 12 | * |
| ... | ... | @@ -15,14 +14,13 @@ import java.util.Arrays; |
| 15 | 14 | */ |
| 16 | 15 | @Getter |
| 17 | 16 | @AllArgsConstructor |
| 18 | -public enum CrmSceneEnum implements IntArrayValuable { | |
| 17 | +public enum CrmSceneTypeEnum implements IntArrayValuable { | |
| 19 | 18 | |
| 20 | 19 | OWNER(1, "我负责的"), |
| 21 | - FOLLOW(2, "我关注的"), | |
| 22 | - // TODO @puhui999:还有一个我参与的 | |
| 20 | + INVOLVED(2, "我参与的"), | |
| 23 | 21 | SUBORDINATE(3, "下属负责的"); |
| 24 | 22 | |
| 25 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneEnum::getType).toArray(); | |
| 23 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmSceneTypeEnum::getType).toArray(); | |
| 26 | 24 | |
| 27 | 25 | /** |
| 28 | 26 | * 场景类型 |
| ... | ... | @@ -37,8 +35,8 @@ public enum CrmSceneEnum implements IntArrayValuable { |
| 37 | 35 | return ObjUtil.equal(OWNER.getType(), type); |
| 38 | 36 | } |
| 39 | 37 | |
| 40 | - public static boolean isFollow(Integer type) { | |
| 41 | - return ObjUtil.equal(FOLLOW.getType(), type); | |
| 38 | + public static boolean isInvolved(Integer type) { | |
| 39 | + return ObjUtil.equal(INVOLVED.getType(), type); | |
| 42 | 40 | } |
| 43 | 41 | |
| 44 | 42 | public static boolean isSubordinate(Integer type) { | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.enums.customer; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 3 | 5 | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; |
| 4 | 6 | import lombok.AllArgsConstructor; |
| 5 | 7 | import lombok.Getter; |
| ... | ... | @@ -18,24 +20,30 @@ public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable { |
| 18 | 20 | /** |
| 19 | 21 | * 拥有客户数限制 |
| 20 | 22 | */ |
| 21 | - CUSTOMER_QUANTITY_LIMIT(1, "拥有客户数限制"), | |
| 23 | + CUSTOMER_OWNER_LIMIT(1, "拥有客户数限制"), | |
| 22 | 24 | /** |
| 23 | 25 | * 锁定客户数限制 |
| 24 | 26 | */ |
| 25 | 27 | CUSTOMER_LOCK_LIMIT(2, "锁定客户数限制"), |
| 26 | 28 | ; |
| 27 | 29 | |
| 28 | - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getCode).toArray(); | |
| 30 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getType).toArray(); | |
| 29 | 31 | |
| 30 | 32 | /** |
| 31 | 33 | * 状态 |
| 32 | 34 | */ |
| 33 | - private final Integer code; | |
| 35 | + private final Integer type; | |
| 34 | 36 | /** |
| 35 | 37 | * 状态名 |
| 36 | 38 | */ |
| 37 | 39 | private final String name; |
| 38 | 40 | |
| 41 | + public static String getNameByType(Integer type) { | |
| 42 | + CrmCustomerLimitConfigTypeEnum typeEnum = CollUtil.findOne(CollUtil.newArrayList(CrmCustomerLimitConfigTypeEnum.values()), | |
| 43 | + item -> ObjUtil.equal(item.type, type)); | |
| 44 | + return typeEnum == null ? null : typeEnum.getName(); | |
| 45 | + } | |
| 46 | + | |
| 39 | 47 | @Override |
| 40 | 48 | public int[] array() { |
| 41 | 49 | return ARRAYS; | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/message/CrmContactStatusEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.enums.message; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | |
| 4 | +import lombok.Getter; | |
| 5 | +import lombok.RequiredArgsConstructor; | |
| 6 | + | |
| 7 | +import java.util.Arrays; | |
| 8 | + | |
| 9 | +/** | |
| 10 | + * CRM 联系状态 | |
| 11 | + * | |
| 12 | + * @author dhb52 | |
| 13 | + */ | |
| 14 | +@RequiredArgsConstructor | |
| 15 | +@Getter | |
| 16 | +public enum CrmContactStatusEnum implements IntArrayValuable { | |
| 17 | + | |
| 18 | + NEEDED_TODAY(1, "今日需联系"), | |
| 19 | + EXPIRED(2, "已逾期"), | |
| 20 | + ALREADY_CONTACT(3, "已联系"), | |
| 21 | + ; | |
| 22 | + | |
| 23 | + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmContactStatusEnum::getType).toArray(); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 状态 | |
| 27 | + */ | |
| 28 | + private final Integer type; | |
| 29 | + /** | |
| 30 | + * 状态名 | |
| 31 | + */ | |
| 32 | + private final String name; | |
| 33 | + | |
| 34 | + @Override | |
| 35 | + public int[] array() { | |
| 36 | + return ARRAYS; | |
| 37 | + } | |
| 38 | + | |
| 39 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/permission/CrmPermissionRoleCodeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.enums.permission; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * Crm 数据权限角色枚举 | |
| 8 | + * | |
| 9 | + * @author HUIHUI | |
| 10 | + */ | |
| 11 | +@Getter | |
| 12 | +@AllArgsConstructor | |
| 13 | +public enum CrmPermissionRoleCodeEnum { | |
| 14 | + | |
| 15 | + CRM_ADMIN("crm_admin", "CRM 管理员"); | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 角色标识 | |
| 19 | + */ | |
| 20 | + private String code; | |
| 21 | + /** | |
| 22 | + * 角色名称 | |
| 23 | + */ | |
| 24 | + private String name; | |
| 25 | + | |
| 26 | +} | |
| 27 | + | ... | ... |
yudao-module-crm/yudao-module-crm-biz/pom.xml
| ... | ... | @@ -60,6 +60,10 @@ |
| 60 | 60 | <groupId>cn.iocoder.boot</groupId> |
| 61 | 61 | <artifactId>yudao-spring-boot-starter-excel</artifactId> |
| 62 | 62 | </dependency> |
| 63 | + <dependency> | |
| 64 | + <groupId>cn.iocoder.boot</groupId> | |
| 65 | + <artifactId>yudao-spring-boot-starter-biz-dict</artifactId> | |
| 66 | + </dependency> | |
| 63 | 67 | |
| 64 | 68 | <!-- Test 测试相关 --> |
| 65 | 69 | <dependency> | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | -import cn.hutool.core.lang.Assert; | |
| 5 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 7 | 7 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 8 | 8 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 9 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.*; | |
| 10 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusQueryVO; | |
| 11 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO; | |
| 12 | -import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO; | |
| 9 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessPageReqVO; | |
| 10 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; | |
| 11 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessSaveReqVO; | |
| 12 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO; | |
| 13 | 13 | import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert; |
| 14 | 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; |
| 15 | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO; |
| ... | ... | @@ -22,22 +22,24 @@ import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 22 | 22 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | 23 | import io.swagger.v3.oas.annotations.Parameter; |
| 24 | 24 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 25 | +import jakarta.annotation.Resource; | |
| 26 | +import jakarta.servlet.http.HttpServletResponse; | |
| 27 | +import jakarta.validation.Valid; | |
| 25 | 28 | import org.springframework.security.access.prepost.PreAuthorize; |
| 26 | 29 | import org.springframework.validation.annotation.Validated; |
| 27 | 30 | import org.springframework.web.bind.annotation.*; |
| 28 | 31 | |
| 29 | -import jakarta.annotation.Resource; | |
| 30 | -import jakarta.servlet.http.HttpServletResponse; | |
| 31 | -import jakarta.validation.Valid; | |
| 32 | 32 | import java.io.IOException; |
| 33 | 33 | import java.util.List; |
| 34 | -import java.util.Objects; | |
| 35 | -import java.util.Set; | |
| 36 | -import java.util.stream.Collectors; | |
| 37 | 34 | |
| 35 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 38 | 36 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 37 | +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | |
| 38 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; | |
| 39 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 39 | 40 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 40 | 41 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 42 | +import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; | |
| 41 | 43 | |
| 42 | 44 | @Tag(name = "管理后台 - 商机") |
| 43 | 45 | @RestController |
| ... | ... | @@ -47,27 +49,24 @@ public class CrmBusinessController { |
| 47 | 49 | |
| 48 | 50 | @Resource |
| 49 | 51 | private CrmBusinessService businessService; |
| 50 | - | |
| 51 | 52 | @Resource |
| 52 | 53 | private CrmCustomerService customerService; |
| 53 | - | |
| 54 | 54 | @Resource |
| 55 | 55 | private CrmBusinessStatusTypeService businessStatusTypeService; |
| 56 | - | |
| 57 | 56 | @Resource |
| 58 | 57 | private CrmBusinessStatusService businessStatusService; |
| 59 | 58 | |
| 60 | 59 | @PostMapping("/create") |
| 61 | 60 | @Operation(summary = "创建商机") |
| 62 | 61 | @PreAuthorize("@ss.hasPermission('crm:business:create')") |
| 63 | - public CommonResult<Long> createBusiness(@Valid @RequestBody CrmBusinessCreateReqVO createReqVO) { | |
| 62 | + public CommonResult<Long> createBusiness(@Valid @RequestBody CrmBusinessSaveReqVO createReqVO) { | |
| 64 | 63 | return success(businessService.createBusiness(createReqVO, getLoginUserId())); |
| 65 | 64 | } |
| 66 | 65 | |
| 67 | 66 | @PutMapping("/update") |
| 68 | 67 | @Operation(summary = "更新商机") |
| 69 | 68 | @PreAuthorize("@ss.hasPermission('crm:business:update')") |
| 70 | - public CommonResult<Boolean> updateBusiness(@Valid @RequestBody CrmBusinessUpdateReqVO updateReqVO) { | |
| 69 | + public CommonResult<Boolean> updateBusiness(@Valid @RequestBody CrmBusinessSaveReqVO updateReqVO) { | |
| 71 | 70 | businessService.updateBusiness(updateReqVO); |
| 72 | 71 | return success(true); |
| 73 | 72 | } |
| ... | ... | @@ -87,7 +86,26 @@ public class CrmBusinessController { |
| 87 | 86 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 88 | 87 | public CommonResult<CrmBusinessRespVO> getBusiness(@RequestParam("id") Long id) { |
| 89 | 88 | CrmBusinessDO business = businessService.getBusiness(id); |
| 90 | - return success(CrmBusinessConvert.INSTANCE.convert(business)); | |
| 89 | + return success(BeanUtils.toBean(business, CrmBusinessRespVO.class)); | |
| 90 | + } | |
| 91 | + | |
| 92 | + @GetMapping("/list-by-ids") | |
| 93 | + @Operation(summary = "获得商机列表") | |
| 94 | + @Parameter(name = "ids", description = "编号", required = true, example = "[1024]") | |
| 95 | + @PreAuthorize("@ss.hasPermission('crm:business:query')") | |
| 96 | + public CommonResult<List<CrmBusinessRespVO>> getContactListByIds(@RequestParam("ids") List<Long> ids) { | |
| 97 | + return success(BeanUtils.toBean(businessService.getBusinessList(ids, getLoginUserId()), CrmBusinessRespVO.class)); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @GetMapping("/simple-all-list") | |
| 101 | + @Operation(summary = "获得联系人的精简列表") | |
| 102 | + @PreAuthorize("@ss.hasPermission('crm:contact:query')") | |
| 103 | + public CommonResult<List<CrmBusinessRespVO>> getSimpleContactList() { | |
| 104 | + CrmBusinessPageReqVO reqVO = new CrmBusinessPageReqVO(); | |
| 105 | + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 | |
| 106 | + PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(reqVO, getLoginUserId()); | |
| 107 | + return success(convertList(pageResult.getList(), business -> // 只返回 id、name 字段 | |
| 108 | + new CrmBusinessRespVO().setId(business.getId()).setName(business.getName()))); | |
| 91 | 109 | } |
| 92 | 110 | |
| 93 | 111 | @GetMapping("/page") |
| ... | ... | @@ -95,60 +113,25 @@ public class CrmBusinessController { |
| 95 | 113 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 96 | 114 | public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { |
| 97 | 115 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); |
| 98 | - if (CollUtil.isEmpty(pageResult.getList())) { | |
| 99 | - return success(PageResult.empty(pageResult.getTotal())); | |
| 100 | - } | |
| 101 | - // 处理客户名称回显 | |
| 102 | - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; | |
| 103 | - Set<Long> customerIds = pageResult.getList().stream() | |
| 104 | - .map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 105 | - List<CrmCustomerDO> customerList = customerService.getCustomerList(customerIds); | |
| 106 | - // 处理商机状态类型名称回显 | |
| 107 | - Set<Long> statusTypeIds = pageResult.getList().stream() | |
| 108 | - .map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 109 | - CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO(); | |
| 110 | - queryStatusTypeVO.setIdList(statusTypeIds); | |
| 111 | - List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO); | |
| 112 | - // 处理商机状态名称回显 | |
| 113 | - Set<Long> statusIds = pageResult.getList().stream() | |
| 114 | - .map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 115 | - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); | |
| 116 | - queryVO.setIdList(statusIds); | |
| 117 | - List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO); | |
| 118 | - return success(CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList)); | |
| 116 | + return success(buildBusinessDetailPageResult(pageResult)); | |
| 119 | 117 | } |
| 120 | 118 | |
| 121 | 119 | @GetMapping("/page-by-customer") |
| 122 | 120 | @Operation(summary = "获得商机分页,基于指定客户") |
| 123 | - public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByCustomer(@Valid CrmContractPageReqVO pageReqVO) { | |
| 124 | - Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); | |
| 125 | - PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByCustomer(pageReqVO); | |
| 126 | - // 处理客户名称回显 | |
| 127 | - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; | |
| 128 | - Set<Long> customerIds = pageResult.getList().stream() | |
| 129 | - .map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 130 | - List<CrmCustomerDO> customerList = customerService.getCustomerList(customerIds); | |
| 131 | - // 处理商机状态类型名称回显 | |
| 132 | - Set<Long> statusTypeIds = pageResult.getList().stream() | |
| 133 | - .map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 134 | - CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO(); | |
| 135 | - queryStatusTypeVO.setIdList(statusTypeIds); | |
| 136 | - List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO); | |
| 137 | - // 处理商机状态名称回显 | |
| 138 | - Set<Long> statusIds = pageResult.getList().stream() | |
| 139 | - .map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet()); | |
| 140 | - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); | |
| 141 | - queryVO.setIdList(statusIds); | |
| 142 | - List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO); | |
| 143 | - return success(CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList)); | |
| 121 | + public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByCustomer(@Valid CrmBusinessPageReqVO pageReqVO) { | |
| 122 | + if (pageReqVO.getCustomerId() == null) { | |
| 123 | + throw exception(CUSTOMER_NOT_EXISTS); | |
| 124 | + } | |
| 125 | + PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); | |
| 126 | + return success(buildBusinessDetailPageResult(pageResult)); | |
| 144 | 127 | } |
| 145 | 128 | |
| 146 | - @GetMapping("/pool-page") | |
| 147 | - @Operation(summary = "获得商机公海分页") | |
| 129 | + @GetMapping("/page-by-contact") | |
| 130 | + @Operation(summary = "获得联系人的商机分页") | |
| 148 | 131 | @PreAuthorize("@ss.hasPermission('crm:business:query')") |
| 149 | - public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPoolPage(@Valid CrmBusinessPageReqVO pageVO) { | |
| 150 | - // TODO puhui999: 等数据权限完善后再实现 | |
| 151 | - return null; | |
| 132 | + public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { | |
| 133 | + PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByContact(pageReqVO); | |
| 134 | + return success(buildBusinessDetailPageResult(pageResult)); | |
| 152 | 135 | } |
| 153 | 136 | |
| 154 | 137 | @GetMapping("/export-excel") |
| ... | ... | @@ -157,10 +140,30 @@ public class CrmBusinessController { |
| 157 | 140 | @OperateLog(type = EXPORT) |
| 158 | 141 | public void exportBusinessExcel(@Valid CrmBusinessPageReqVO exportReqVO, |
| 159 | 142 | HttpServletResponse response) throws IOException { |
| 143 | + exportReqVO.setPageSize(PAGE_SIZE_NONE); | |
| 160 | 144 | PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(exportReqVO, getLoginUserId()); |
| 161 | 145 | // 导出 Excel |
| 162 | - ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessExcelVO.class, | |
| 163 | - CrmBusinessConvert.INSTANCE.convertList02(pageResult.getList())); | |
| 146 | + ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class, | |
| 147 | + buildBusinessDetailPageResult(pageResult).getList()); | |
| 148 | + } | |
| 149 | + | |
| 150 | + /** | |
| 151 | + * 构建详细的商机分页结果 | |
| 152 | + * | |
| 153 | + * @param pageResult 简单的商机分页结果 | |
| 154 | + * @return 详细的商机分页结果 | |
| 155 | + */ | |
| 156 | + private PageResult<CrmBusinessRespVO> buildBusinessDetailPageResult(PageResult<CrmBusinessDO> pageResult) { | |
| 157 | + if (CollUtil.isEmpty(pageResult.getList())) { | |
| 158 | + return PageResult.empty(pageResult.getTotal()); | |
| 159 | + } | |
| 160 | + List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.getBusinessStatusTypeList( | |
| 161 | + convertSet(pageResult.getList(), CrmBusinessDO::getStatusTypeId)); | |
| 162 | + List<CrmBusinessStatusDO> statusList = businessStatusService.getBusinessStatusList( | |
| 163 | + convertSet(pageResult.getList(), CrmBusinessDO::getStatusId)); | |
| 164 | + List<CrmCustomerDO> customerList = customerService.getCustomerList( | |
| 165 | + convertSet(pageResult.getList(), CrmBusinessDO::getCustomerId)); | |
| 166 | + return CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList); | |
| 164 | 167 | } |
| 165 | 168 | |
| 166 | 169 | @PutMapping("/transfer") | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessStatusTypeController.java
| ... | ... | @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | |
| 7 | 8 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 8 | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| ... | ... | @@ -24,19 +25,17 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 24 | 25 | import io.swagger.v3.oas.annotations.Operation; |
| 25 | 26 | import io.swagger.v3.oas.annotations.Parameter; |
| 26 | 27 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 28 | +import jakarta.annotation.Resource; | |
| 29 | +import jakarta.servlet.http.HttpServletResponse; | |
| 30 | +import jakarta.validation.Valid; | |
| 27 | 31 | import org.springframework.security.access.prepost.PreAuthorize; |
| 28 | 32 | import org.springframework.validation.annotation.Validated; |
| 29 | 33 | import org.springframework.web.bind.annotation.*; |
| 30 | 34 | |
| 31 | -import jakarta.annotation.Resource; | |
| 32 | -import jakarta.servlet.http.HttpServletResponse; | |
| 33 | -import jakarta.validation.Valid; | |
| 34 | 35 | import java.io.IOException; |
| 35 | 36 | import java.util.Collection; |
| 36 | 37 | import java.util.List; |
| 37 | -import java.util.Objects; | |
| 38 | 38 | import java.util.Set; |
| 39 | -import java.util.stream.Collectors; | |
| 40 | 39 | |
| 41 | 40 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 42 | 41 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| ... | ... | @@ -85,13 +84,13 @@ public class CrmBusinessStatusTypeController { |
| 85 | 84 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 86 | 85 | @PreAuthorize("@ss.hasPermission('crm:business-status-type:query')") |
| 87 | 86 | public CommonResult<CrmBusinessStatusTypeRespVO> getBusinessStatusType(@RequestParam("id") Long id) { |
| 88 | - CrmBusinessStatusTypeDO businessStatusType = businessStatusTypeService.getBusinessStatusType(id); | |
| 87 | + CrmBusinessStatusTypeDO statusType = businessStatusTypeService.getBusinessStatusType(id); | |
| 89 | 88 | // 处理状态回显 |
| 90 | - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; | |
| 89 | + // TODO @lzxhqs:可以在 businessStatusService 加个 getBusinessStatusListByTypeId 方法,直接返回 List<CrmBusinessStatusDO> 哈,常用的,尽量封装个简单易懂的方法,不用追求绝对通用哈; | |
| 91 | 90 | CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); |
| 92 | 91 | queryVO.setTypeId(id); |
| 93 | 92 | List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO); |
| 94 | - return success(CrmBusinessStatusTypeConvert.INSTANCE.convert(businessStatusType, statusList)); | |
| 93 | + return success(CrmBusinessStatusTypeConvert.INSTANCE.convert(statusType, statusList)); | |
| 95 | 94 | } |
| 96 | 95 | |
| 97 | 96 | @GetMapping("/page") |
| ... | ... | @@ -100,12 +99,7 @@ public class CrmBusinessStatusTypeController { |
| 100 | 99 | public CommonResult<PageResult<CrmBusinessStatusTypeRespVO>> getBusinessStatusTypePage(@Valid CrmBusinessStatusTypePageReqVO pageReqVO) { |
| 101 | 100 | PageResult<CrmBusinessStatusTypeDO> pageResult = businessStatusTypeService.getBusinessStatusTypePage(pageReqVO); |
| 102 | 101 | // 处理部门回显 |
| 103 | - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; | |
| 104 | - Set<Long> deptIds = pageResult.getList().stream() | |
| 105 | - .map(CrmBusinessStatusTypeDO::getDeptIds) | |
| 106 | - .filter(Objects::nonNull) | |
| 107 | - .flatMap(Collection::stream) | |
| 108 | - .collect(Collectors.toSet()); | |
| 102 | + Set<Long> deptIds = CollectionUtils.convertSetByFlatMap(pageResult.getList(), CrmBusinessStatusTypeDO::getDeptIds,Collection::stream); | |
| 109 | 103 | List<DeptRespDTO> deptList = deptApi.getDeptList(deptIds); |
| 110 | 104 | return success(CrmBusinessStatusTypeConvert.INSTANCE.convertPage(pageResult, deptList)); |
| 111 | 105 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessCreateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.EqualsAndHashCode; | |
| 6 | -import lombok.ToString; | |
| 7 | - | |
| 8 | -@Schema(description = "管理后台 - 商机创建 Request VO") | |
| 9 | -@Data | |
| 10 | -@EqualsAndHashCode(callSuper = true) | |
| 11 | -@ToString(callSuper = true) | |
| 12 | -public class CrmBusinessCreateReqVO extends CrmBusinessBaseVO { | |
| 13 | - | |
| 14 | - // TODO @ljileo:新建的时候,应该可以传递添加的产品; | |
| 15 | - | |
| 16 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; | |
| 4 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 7 | import lombok.Data; |
| 6 | 8 | import lombok.EqualsAndHashCode; |
| ... | ... | @@ -18,4 +20,11 @@ public class CrmBusinessPageReqVO extends PageParam { |
| 18 | 20 | @Schema(description = "客户编号", example = "10795") |
| 19 | 21 | private Long customerId; |
| 20 | 22 | |
| 23 | + @Schema(description = "联系人编号", example = "10795") | |
| 24 | + private Long contactId; | |
| 25 | + | |
| 26 | + @Schema(description = "场景类型", example = "1") | |
| 27 | + @InEnum(CrmSceneTypeEnum.class) | |
| 28 | + private Integer sceneType; // 场景类型,为 null 时则表示全部 | |
| 29 | + | |
| 21 | 30 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | |
| 3 | 3 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 7 | + | |
| 8 | +import java.math.BigDecimal; | |
| 5 | 9 | import java.time.LocalDateTime; |
| 6 | 10 | |
| 11 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 12 | + | |
| 7 | 13 | @Schema(description = "管理后台 - 商机 Response VO") |
| 8 | 14 | @Data |
| 9 | -@EqualsAndHashCode(callSuper = true) | |
| 10 | -@ToString(callSuper = true) | |
| 11 | -public class CrmBusinessRespVO extends CrmBusinessBaseVO { | |
| 15 | +public class CrmBusinessRespVO { | |
| 12 | 16 | |
| 13 | 17 | @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") |
| 14 | 18 | private Long id; |
| 15 | 19 | |
| 20 | + @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") | |
| 21 | + @NotNull(message = "商机名称不能为空") | |
| 22 | + private String name; | |
| 23 | + | |
| 24 | + @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") | |
| 25 | + @NotNull(message = "商机状态类型不能为空") | |
| 26 | + private Long statusTypeId; | |
| 27 | + | |
| 28 | + @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 29 | + @NotNull(message = "商机状态不能为空") | |
| 30 | + private Long statusId; | |
| 31 | + | |
| 32 | + @Schema(description = "下次联系时间") | |
| 33 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 34 | + private LocalDateTime contactNextTime; | |
| 35 | + | |
| 36 | + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") | |
| 37 | + @NotNull(message = "客户不能为空") | |
| 38 | + private Long customerId; | |
| 39 | + | |
| 40 | + @Schema(description = "预计成交日期") | |
| 41 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 42 | + private LocalDateTime dealTime; | |
| 43 | + | |
| 44 | + @Schema(description = "商机金额", example = "12371") | |
| 45 | + private Integer price; | |
| 46 | + | |
| 47 | + // TODO @ljileo:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 | |
| 48 | + @Schema(description = "整单折扣") | |
| 49 | + private Integer discountPercent; | |
| 50 | + | |
| 51 | + @Schema(description = "产品总金额", example = "12025") | |
| 52 | + private BigDecimal productPrice; | |
| 53 | + | |
| 54 | + @Schema(description = "备注", example = "随便") | |
| 55 | + private String remark; | |
| 56 | + | |
| 16 | 57 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 17 | 58 | private LocalDateTime createTime; |
| 18 | 59 | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessBaseVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessSaveReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 4 | +import cn.iocoder.yudao.module.crm.controller.admin.business.vo.product.CrmBusinessProductSaveReqVO; | |
| 5 | +import cn.iocoder.yudao.module.crm.enums.business.CrmBizEndStatus; | |
| 6 | +import cn.iocoder.yudao.module.crm.framework.operatelog.core.CrmCustomerParseFunction; | |
| 7 | +import com.mzt.logapi.starter.annotation.DiffLogField; | |
| 3 | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 9 | +import jakarta.validation.constraints.NotNull; | |
| 4 | 10 | import lombok.Data; |
| 5 | 11 | import org.springframework.format.annotation.DateTimeFormat; |
| 6 | 12 | |
| 7 | -import jakarta.validation.constraints.NotNull; | |
| 8 | 13 | import java.math.BigDecimal; |
| 9 | 14 | import java.time.LocalDateTime; |
| 15 | +import java.util.ArrayList; | |
| 16 | +import java.util.List; | |
| 10 | 17 | |
| 11 | 18 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 12 | 19 | |
| 13 | -/** | |
| 14 | - * 商机 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 15 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 16 | - */ | |
| 20 | +@Schema(description = "管理后台 - CRM 商机创建/更新 Request VO") | |
| 17 | 21 | @Data |
| 18 | -public class CrmBusinessBaseVO { | |
| 22 | +public class CrmBusinessSaveReqVO { | |
| 23 | + | |
| 24 | + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") | |
| 25 | + private Long id; | |
| 19 | 26 | |
| 20 | 27 | @Schema(description = "商机名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四") |
| 28 | + @DiffLogField(name = "商机名称") | |
| 21 | 29 | @NotNull(message = "商机名称不能为空") |
| 22 | 30 | private String name; |
| 23 | 31 | |
| 24 | 32 | @Schema(description = "商机状态类型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25714") |
| 33 | + @DiffLogField(name = "商机状态") | |
| 25 | 34 | @NotNull(message = "商机状态类型不能为空") |
| 26 | 35 | private Long statusTypeId; |
| 27 | 36 | |
| 28 | 37 | @Schema(description = "商机状态编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") |
| 38 | + @DiffLogField(name = "商机状态") | |
| 29 | 39 | @NotNull(message = "商机状态不能为空") |
| 30 | 40 | private Long statusId; |
| 31 | 41 | |
| 32 | 42 | @Schema(description = "下次联系时间") |
| 43 | + @DiffLogField(name = "下次联系时间") | |
| 33 | 44 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 34 | 45 | private LocalDateTime contactNextTime; |
| 35 | 46 | |
| 36 | 47 | @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10299") |
| 48 | + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | |
| 37 | 49 | @NotNull(message = "客户不能为空") |
| 38 | 50 | private Long customerId; |
| 39 | 51 | |
| 40 | 52 | @Schema(description = "预计成交日期") |
| 53 | + @DiffLogField(name = "预计成交日期") | |
| 41 | 54 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 42 | 55 | private LocalDateTime dealTime; |
| 43 | 56 | |
| 44 | 57 | @Schema(description = "商机金额", example = "12371") |
| 58 | + @DiffLogField(name = "商机金额") | |
| 45 | 59 | private Integer price; |
| 46 | 60 | |
| 47 | - // TODO @ljileo:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 | |
| 61 | + // TODO @lzxhqs:折扣使用 Integer 类型,存储时,默认 * 100;展示的时候,前端需要 / 100;避免精度丢失问题 | |
| 48 | 62 | @Schema(description = "整单折扣") |
| 63 | + @DiffLogField(name = "整单折扣") | |
| 49 | 64 | private Integer discountPercent; |
| 50 | 65 | |
| 51 | 66 | @Schema(description = "产品总金额", example = "12025") |
| 67 | + @DiffLogField(name = "产品总金额") | |
| 52 | 68 | private BigDecimal productPrice; |
| 53 | 69 | |
| 54 | 70 | @Schema(description = "备注", example = "随便") |
| 71 | + @DiffLogField(name = "备注") | |
| 55 | 72 | private String remark; |
| 56 | 73 | |
| 74 | + @Schema(description = "结束状态", example = "1") | |
| 75 | + @InEnum(CrmBizEndStatus.class) | |
| 76 | + private Integer endStatus; | |
| 77 | + | |
| 78 | + // TODO @lzxhqs:不设置默认 new ArrayList<>();一般 pojo 不设置默认值哈 | |
| 79 | + @Schema(description = "商机产品列表") | |
| 80 | + private List<CrmBusinessProductSaveReqVO> products = new ArrayList<>(); | |
| 81 | + | |
| 82 | + @Schema(description = "联系人编号", example = "110") | |
| 83 | + private Long contactId; // 使用场景,在【联系人详情】添加商机时,如果需要关联两者,需要传递 contactId 字段 | |
| 84 | + | |
| 57 | 85 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessTransferReqVO.java
| ... | ... | @@ -2,16 +2,15 @@ package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; |
| 4 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | -import lombok.Data; | |
| 6 | - | |
| 7 | 5 | import jakarta.validation.constraints.NotNull; |
| 6 | +import lombok.Data; | |
| 8 | 7 | |
| 9 | 8 | @Schema(description = "管理后台 - 商机转移 Request VO") |
| 10 | 9 | @Data |
| 11 | 10 | public class CrmBusinessTransferReqVO { |
| 12 | 11 | |
| 13 | 12 | @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") |
| 14 | - @NotNull(message = "联系人编号不能为空") | |
| 13 | + @NotNull(message = "商机编号不能为空") | |
| 15 | 14 | private Long id; |
| 16 | 15 | |
| 17 | 16 | /** | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessUpdateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.business.vo.business; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessBaseVO; | |
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | -import lombok.Data; | |
| 6 | -import lombok.EqualsAndHashCode; | |
| 7 | -import lombok.ToString; | |
| 8 | - | |
| 9 | -import jakarta.validation.constraints.NotNull; | |
| 10 | - | |
| 11 | -@Schema(description = "管理后台 - 商机更新 Request VO") | |
| 12 | -@Data | |
| 13 | -@EqualsAndHashCode(callSuper = true) | |
| 14 | -@ToString(callSuper = true) | |
| 15 | -public class CrmBusinessUpdateReqVO extends CrmBusinessBaseVO { | |
| 16 | - | |
| 17 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") | |
| 18 | - @NotNull(message = "主键不能为空") | |
| 19 | - private Long id; | |
| 20 | - | |
| 21 | - // TODO @ljileo:修改的时候,应该可以传递添加的产品; | |
| 22 | - | |
| 23 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactCreateReqVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/product/CrmBusinessProductPageReqVO.java
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; | |
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product; | |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 3 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 5 | import lombok.Data; |
| 5 | 6 | import lombok.EqualsAndHashCode; |
| 6 | 7 | import lombok.ToString; |
| 7 | 8 | |
| 8 | -@Schema(description = "管理后台 - CRM 联系人创建 Request VO") | |
| 9 | +// TODO @lzxhqs:这个类,如果没用到,可以考虑删除哈 | |
| 10 | +@Schema(description = "管理后台 - 商机产品分页 Request VO") | |
| 9 | 11 | @Data |
| 10 | 12 | @EqualsAndHashCode(callSuper = true) |
| 11 | 13 | @ToString(callSuper = true) |
| 12 | -public class CrmContactCreateReqVO extends CrmContactBaseVO { | |
| 13 | - | |
| 14 | +public class CrmBusinessProductPageReqVO extends PageParam { | |
| 14 | 15 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/product/CrmBusinessProductRespVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product; | |
| 2 | + | |
| 3 | +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +@Schema(description = "管理后台 - 商机产品关联 Response VO") | |
| 8 | +@Data | |
| 9 | +@ExcelIgnoreUnannotated | |
| 10 | +public class CrmBusinessProductRespVO { | |
| 11 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/product/CrmBusinessProductSaveReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.business.vo.product; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotNull; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.math.BigDecimal; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - CRM 商机产品关联表 创建/更新 Request VO") | |
| 10 | +@Data | |
| 11 | +public class CrmBusinessProductSaveReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "32129") | |
| 14 | + private Long id; | |
| 15 | + | |
| 16 | + // TODO @lzxhqs:这个字段,应该是 Long 类型 | |
| 17 | + @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 18 | + @NotNull(message = "商机编号不能为空") | |
| 19 | + private Integer businessId; | |
| 20 | + | |
| 21 | + // TODO @lzxhqs:这个字段,应该是 Long 类型 | |
| 22 | + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 23 | + @NotNull(message = "产品编号不能为空") | |
| 24 | + private Integer productId; | |
| 25 | + | |
| 26 | + @Schema(description = "产品单价", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 27 | + @NotNull(message = "产品单价不能为空") | |
| 28 | + private BigDecimal price; | |
| 29 | + | |
| 30 | + @Schema(description = "销售价格", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 31 | + @NotNull(message = "销售价格不能为空") | |
| 32 | + private BigDecimal salesPrice; | |
| 33 | + | |
| 34 | + @Schema(description = "数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 35 | + @NotNull(message = "数量不能为空") | |
| 36 | + private BigDecimal num; | |
| 37 | + | |
| 38 | + @Schema(description = "折扣", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 39 | + @NotNull(message = "折扣不能为空") | |
| 40 | + private BigDecimal discount; | |
| 41 | + | |
| 42 | + @Schema(description = "小计(折扣后价格)", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 43 | + @NotNull(message = "小计(折扣后价格)不能为空") | |
| 44 | + private BigDecimal subtotal; | |
| 45 | + | |
| 46 | + // TODO @lzxhqs:字符串,用 @NotEmpty,因为要考虑 "" 前端搞了这个玩意 | |
| 47 | + @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "30320") | |
| 48 | + @NotNull(message = "单位不能为空") | |
| 49 | + private String unit; | |
| 50 | + | |
| 51 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/status/CrmBusinessStatusSaveReqVO.java
| ... | ... | @@ -21,11 +21,11 @@ public class CrmBusinessStatusSaveReqVO { |
| 21 | 21 | @NotEmpty(message = "状态名不能为空") |
| 22 | 22 | private String name; |
| 23 | 23 | |
| 24 | - // TODO @lilleo:percent 应该是 Integer; | |
| 24 | + // TODO @lzxhqs::percent 应该是 Integer; | |
| 25 | 25 | @Schema(description = "赢单率") |
| 26 | 26 | private String percent; |
| 27 | 27 | |
| 28 | - // TODO @lilleo:这个是不是不用前端新增和修改的时候传递,交给顺序计算出来,存储起来就好了; | |
| 28 | + // TODO @lzxhqs:这个是不是不用前端新增和修改的时候传递,交给顺序计算出来,存储起来就好了; | |
| 29 | 29 | @Schema(description = "排序") |
| 30 | 30 | private Integer sort; |
| 31 | 31 | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/type/CrmBusinessStatusTypeSaveReqVO.java
| ... | ... | @@ -19,11 +19,11 @@ public class CrmBusinessStatusTypeSaveReqVO { |
| 19 | 19 | @NotEmpty(message = "状态类型名不能为空") |
| 20 | 20 | private String name; |
| 21 | 21 | |
| 22 | + // TODO @lzxhqs: VO 里面,我们不使用默认值哈。这里 Lists.newArrayList() 看看怎么去掉。上面 deptIds 也是类似噢 | |
| 22 | 23 | @Schema(description = "使用的部门编号", requiredMode = Schema.RequiredMode.REQUIRED) |
| 23 | 24 | private List<Long> deptIds = Lists.newArrayList(); |
| 24 | 25 | |
| 25 | - // TODO @ljlleo VO 里面,我们不使用默认值哈。这里 Lists.newArrayList() 看看怎么去掉。上面 deptIds 也是类似噢 | |
| 26 | 26 | @Schema(description = "商机状态集合", requiredMode = Schema.RequiredMode.REQUIRED) |
| 27 | - private List<CrmBusinessStatusSaveReqVO> statusList = Lists.newArrayList(); | |
| 27 | + private List<CrmBusinessStatusSaveReqVO> statusList; | |
| 28 | 28 | |
| 29 | 29 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/CrmClueController.java
| ... | ... | @@ -2,27 +2,29 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 5 | 6 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 6 | 7 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 7 | 8 | import cn.iocoder.yudao.module.crm.controller.admin.clue.vo.*; |
| 8 | -import cn.iocoder.yudao.module.crm.convert.clue.CrmClueConvert; | |
| 9 | 9 | import cn.iocoder.yudao.module.crm.dal.dataobject.clue.CrmClueDO; |
| 10 | 10 | import cn.iocoder.yudao.module.crm.service.clue.CrmClueService; |
| 11 | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 13 | 13 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 14 | +import jakarta.annotation.Resource; | |
| 15 | +import jakarta.servlet.http.HttpServletResponse; | |
| 16 | +import jakarta.validation.Valid; | |
| 14 | 17 | import org.springframework.security.access.prepost.PreAuthorize; |
| 15 | 18 | import org.springframework.validation.annotation.Validated; |
| 16 | 19 | import org.springframework.web.bind.annotation.*; |
| 17 | 20 | |
| 18 | -import jakarta.annotation.Resource; | |
| 19 | -import jakarta.servlet.http.HttpServletResponse; | |
| 20 | -import jakarta.validation.Valid; | |
| 21 | 21 | import java.io.IOException; |
| 22 | 22 | import java.util.List; |
| 23 | 23 | |
| 24 | 24 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 25 | +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | |
| 25 | 26 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 27 | +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | |
| 26 | 28 | |
| 27 | 29 | @Tag(name = "管理后台 - 线索") |
| 28 | 30 | @RestController |
| ... | ... | @@ -36,14 +38,14 @@ public class CrmClueController { |
| 36 | 38 | @PostMapping("/create") |
| 37 | 39 | @Operation(summary = "创建线索") |
| 38 | 40 | @PreAuthorize("@ss.hasPermission('crm:clue:create')") |
| 39 | - public CommonResult<Long> createClue(@Valid @RequestBody CrmClueCreateReqVO createReqVO) { | |
| 41 | + public CommonResult<Long> createClue(@Valid @RequestBody CrmClueSaveReqVO createReqVO) { | |
| 40 | 42 | return success(clueService.createClue(createReqVO)); |
| 41 | 43 | } |
| 42 | 44 | |
| 43 | 45 | @PutMapping("/update") |
| 44 | 46 | @Operation(summary = "更新线索") |
| 45 | 47 | @PreAuthorize("@ss.hasPermission('crm:clue:update')") |
| 46 | - public CommonResult<Boolean> updateClue(@Valid @RequestBody CrmClueUpdateReqVO updateReqVO) { | |
| 48 | + public CommonResult<Boolean> updateClue(@Valid @RequestBody CrmClueSaveReqVO updateReqVO) { | |
| 47 | 49 | clueService.updateClue(updateReqVO); |
| 48 | 50 | return success(true); |
| 49 | 51 | } |
| ... | ... | @@ -63,27 +65,43 @@ public class CrmClueController { |
| 63 | 65 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") |
| 64 | 66 | public CommonResult<CrmClueRespVO> getClue(@RequestParam("id") Long id) { |
| 65 | 67 | CrmClueDO clue = clueService.getClue(id); |
| 66 | - return success(CrmClueConvert.INSTANCE.convert(clue)); | |
| 68 | + return success(BeanUtils.toBean(clue, CrmClueRespVO.class)); | |
| 67 | 69 | } |
| 68 | 70 | |
| 69 | 71 | @GetMapping("/page") |
| 70 | 72 | @Operation(summary = "获得线索分页") |
| 71 | 73 | @PreAuthorize("@ss.hasPermission('crm:clue:query')") |
| 72 | 74 | public CommonResult<PageResult<CrmClueRespVO>> getCluePage(@Valid CrmCluePageReqVO pageVO) { |
| 73 | - PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO); | |
| 74 | - return success(CrmClueConvert.INSTANCE.convertPage(pageResult)); | |
| 75 | + PageResult<CrmClueDO> pageResult = clueService.getCluePage(pageVO, getLoginUserId()); | |
| 76 | + return success(BeanUtils.toBean(pageResult, CrmClueRespVO.class)); | |
| 75 | 77 | } |
| 76 | 78 | |
| 77 | 79 | @GetMapping("/export-excel") |
| 78 | 80 | @Operation(summary = "导出线索 Excel") |
| 79 | 81 | @PreAuthorize("@ss.hasPermission('crm:clue:export')") |
| 80 | 82 | @OperateLog(type = EXPORT) |
| 81 | - public void exportClueExcel(@Valid CrmClueExportReqVO exportReqVO, | |
| 82 | - HttpServletResponse response) throws IOException { | |
| 83 | - List<CrmClueDO> list = clueService.getClueList(exportReqVO); | |
| 83 | + public void exportClueExcel(@Valid CrmCluePageReqVO pageReqVO, HttpServletResponse response) throws IOException { | |
| 84 | + pageReqVO.setPageSize(PAGE_SIZE_NONE); | |
| 85 | + List<CrmClueDO> list = clueService.getCluePage(pageReqVO, getLoginUserId()).getList(); | |
| 84 | 86 | // 导出 Excel |
| 85 | - List<CrmClueExcelVO> datas = CrmClueConvert.INSTANCE.convertList02(list); | |
| 86 | - ExcelUtils.write(response, "线索.xls", "数据", CrmClueExcelVO.class, datas); | |
| 87 | + List<CrmClueRespVO> datas = BeanUtils.toBean(list, CrmClueRespVO.class); | |
| 88 | + ExcelUtils.write(response, "线索.xls", "数据", CrmClueRespVO.class, datas); | |
| 89 | + } | |
| 90 | + | |
| 91 | + @PutMapping("/transfer") | |
| 92 | + @Operation(summary = "线索转移") | |
| 93 | + @PreAuthorize("@ss.hasPermission('crm:clue:update')") | |
| 94 | + public CommonResult<Boolean> transfer(@Valid @RequestBody CrmClueTransferReqVO reqVO) { | |
| 95 | + clueService.transferClue(reqVO, getLoginUserId()); | |
| 96 | + return success(true); | |
| 97 | + } | |
| 98 | + | |
| 99 | + @PostMapping("/transform") | |
| 100 | + @Operation(summary = "线索转化为客户") | |
| 101 | + @PreAuthorize("@ss.hasPermission('crm:clue:update')") | |
| 102 | + public CommonResult<Boolean> translateCustomer(@Valid @RequestBody CrmClueTransformReqVO reqVO) { | |
| 103 | + clueService.translateCustomer(reqVO, getLoginUserId()); | |
| 104 | + return success(Boolean.TRUE); | |
| 87 | 105 | } |
| 88 | 106 | |
| 89 | 107 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueCreateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | - | |
| 3 | -import lombok.*; | |
| 4 | -import java.util.*; | |
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | -import jakarta.validation.constraints.*; | |
| 7 | - | |
| 8 | -@Schema(description = "管理后台 - 线索创建 Request VO") | |
| 9 | -@Data | |
| 10 | -@EqualsAndHashCode(callSuper = true) | |
| 11 | -@ToString(callSuper = true) | |
| 12 | -public class CrmClueCreateReqVO extends CrmClueBaseVO { | |
| 13 | - | |
| 14 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueExcelVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; | |
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | -import lombok.*; | |
| 6 | -import java.util.*; | |
| 7 | -import java.time.LocalDateTime; | |
| 8 | -import java.time.LocalDateTime; | |
| 9 | -import java.time.LocalDateTime; | |
| 10 | -import java.time.LocalDateTime; | |
| 11 | - | |
| 12 | -import com.alibaba.excel.annotation.ExcelProperty; | |
| 13 | -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 14 | -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 15 | - | |
| 16 | -/** | |
| 17 | - * 线索 Excel VO | |
| 18 | - * | |
| 19 | - * @author Wanwan | |
| 20 | - */ | |
| 21 | -@Data | |
| 22 | -public class CrmClueExcelVO { | |
| 23 | - | |
| 24 | - @ExcelProperty("编号") | |
| 25 | - private Long id; | |
| 26 | - | |
| 27 | - @ExcelProperty(value = "转化状态", converter = DictConvert.class) | |
| 28 | - @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 29 | - private Boolean transformStatus; | |
| 30 | - | |
| 31 | - @ExcelProperty(value = "跟进状态", converter = DictConvert.class) | |
| 32 | - @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 33 | - private Boolean followUpStatus; | |
| 34 | - | |
| 35 | - @ExcelProperty("线索名称") | |
| 36 | - private String name; | |
| 37 | - | |
| 38 | - // TODO 这里需要导出成客户名称 | |
| 39 | - @ExcelProperty("客户id") | |
| 40 | - private Long customerId; | |
| 41 | - | |
| 42 | - @ExcelProperty("下次联系时间") | |
| 43 | - private LocalDateTime contactNextTime; | |
| 44 | - | |
| 45 | - @ExcelProperty("电话") | |
| 46 | - private String telephone; | |
| 47 | - | |
| 48 | - @ExcelProperty("手机号") | |
| 49 | - private String mobile; | |
| 50 | - | |
| 51 | - @ExcelProperty("地址") | |
| 52 | - private String address; | |
| 53 | - | |
| 54 | - @ExcelProperty("负责人的用户编号") | |
| 55 | - private Long ownerUserId; | |
| 56 | - | |
| 57 | - @ExcelProperty("最后跟进时间") | |
| 58 | - private LocalDateTime contactLastTime; | |
| 59 | - | |
| 60 | - @ExcelProperty("备注") | |
| 61 | - private String remark; | |
| 62 | - | |
| 63 | - @ExcelProperty("创建时间") | |
| 64 | - private LocalDateTime createTime; | |
| 65 | - | |
| 66 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueExportReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | - | |
| 3 | -import lombok.*; | |
| 4 | -import java.util.*; | |
| 5 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 7 | -import java.time.LocalDateTime; | |
| 8 | -import org.springframework.format.annotation.DateTimeFormat; | |
| 9 | - | |
| 10 | -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 11 | - | |
| 12 | -@Schema(description = "管理后台 - 线索 Excel 导出 Request VO,参数和 CrmCluePageReqVO 是一致的") | |
| 13 | -@Data | |
| 14 | -public class CrmClueExportReqVO { | |
| 15 | - | |
| 16 | - @Schema(description = "转化状态", example = "true") | |
| 17 | - private Boolean transformStatus; | |
| 18 | - | |
| 19 | - @Schema(description = "跟进状态", example = "true") | |
| 20 | - private Boolean followUpStatus; | |
| 21 | - | |
| 22 | - @Schema(description = "线索名称", example = "线索xxx") | |
| 23 | - private String name; | |
| 24 | - | |
| 25 | - @Schema(description = "客户id", example = "520") | |
| 26 | - private Long customerId; | |
| 27 | - | |
| 28 | - @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") | |
| 29 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 30 | - private LocalDateTime[] contactNextTime; | |
| 31 | - | |
| 32 | - @Schema(description = "电话", example = "18000000000") | |
| 33 | - private String telephone; | |
| 34 | - | |
| 35 | - @Schema(description = "手机号", example = "18000000000") | |
| 36 | - private String mobile; | |
| 37 | - | |
| 38 | - @Schema(description = "地址", example = "北京市海淀区") | |
| 39 | - private String address; | |
| 40 | - | |
| 41 | - @Schema(description = "负责人的用户编号", example = "27199") | |
| 42 | - private Long ownerUserId; | |
| 43 | - | |
| 44 | - @Schema(description = "最后跟进时间") | |
| 45 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 46 | - private LocalDateTime[] contactLastTime; | |
| 47 | - | |
| 48 | - @Schema(description = "创建时间") | |
| 49 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 50 | - private LocalDateTime[] createTime; | |
| 51 | - | |
| 52 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmCluePageReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; | |
| 4 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 7 | import lombok.Data; |
| 6 | 8 | import lombok.EqualsAndHashCode; |
| ... | ... | @@ -21,4 +23,11 @@ public class CrmCluePageReqVO extends PageParam { |
| 21 | 23 | @Schema(description = "手机号", example = "18000000000") |
| 22 | 24 | private String mobile; |
| 23 | 25 | |
| 26 | + @Schema(description = "场景类型", example = "1") | |
| 27 | + @InEnum(CrmSceneTypeEnum.class) | |
| 28 | + private Integer sceneType; // 场景类型,为 null 时则表示全部 | |
| 29 | + | |
| 30 | + @Schema(description = "是否为公海数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") | |
| 31 | + private Boolean pool; // null 则表示为不是公海数据 | |
| 32 | + | |
| 24 | 33 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 4 | +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 5 | +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; | |
| 6 | +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | |
| 7 | +import com.alibaba.excel.annotation.ExcelProperty; | |
| 3 | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | |
| 9 | +import lombok.Data; | |
| 10 | +import lombok.ToString; | |
| 11 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 5 | 12 | |
| 6 | -import jakarta.validation.constraints.NotNull; | |
| 7 | 13 | import java.time.LocalDateTime; |
| 8 | 14 | |
| 15 | +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 16 | + | |
| 9 | 17 | @Schema(description = "管理后台 - 线索 Response VO") |
| 10 | 18 | @Data |
| 11 | -@EqualsAndHashCode(callSuper = true) | |
| 12 | 19 | @ToString(callSuper = true) |
| 13 | -public class CrmClueRespVO extends CrmClueBaseVO { | |
| 20 | +@ExcelIgnoreUnannotated | |
| 21 | +public class CrmClueRespVO { | |
| 14 | 22 | |
| 15 | 23 | @Schema(description = "编号,主键自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969") |
| 24 | + @ExcelProperty("编号") | |
| 16 | 25 | private Long id; |
| 17 | 26 | |
| 18 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 19 | - private LocalDateTime createTime; | |
| 20 | - | |
| 21 | 27 | @Schema(description = "转化状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") |
| 28 | + @ExcelProperty(value = "转化状态", converter = DictConvert.class) | |
| 29 | + @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 22 | 30 | private Boolean transformStatus; |
| 23 | 31 | |
| 24 | 32 | @Schema(description = "跟进状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") |
| 33 | + @ExcelProperty(value = "跟进状态", converter = DictConvert.class) | |
| 34 | + @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 25 | 35 | private Boolean followUpStatus; |
| 26 | 36 | |
| 37 | + @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") | |
| 38 | + @ExcelProperty("线索名称") | |
| 39 | + private String name; | |
| 40 | + | |
| 41 | + @Schema(description = "客户 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") | |
| 42 | + // TODO 这里需要导出成客户名称 | |
| 43 | + @ExcelProperty("客户id") | |
| 44 | + private Long customerId; | |
| 45 | + | |
| 46 | + @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") | |
| 47 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 48 | + @ExcelProperty("下次联系时间") | |
| 49 | + private LocalDateTime contactNextTime; | |
| 50 | + | |
| 51 | + @Schema(description = "电话", example = "18000000000") | |
| 52 | + @ExcelProperty("电话") | |
| 53 | + private String telephone; | |
| 54 | + | |
| 55 | + @Schema(description = "手机号", example = "18000000000") | |
| 56 | + @ExcelProperty("手机号") | |
| 57 | + private String mobile; | |
| 58 | + | |
| 59 | + @Schema(description = "地址", example = "北京市海淀区") | |
| 60 | + @ExcelProperty("地址") | |
| 61 | + private String address; | |
| 62 | + | |
| 63 | + @Schema(description = "负责人编号") | |
| 64 | + @ExcelProperty("负责人的用户编号") | |
| 65 | + private Long ownerUserId; | |
| 66 | + | |
| 67 | + @Schema(description = "最后跟进时间") | |
| 68 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 69 | + @ExcelProperty("最后跟进时间") | |
| 70 | + private LocalDateTime contactLastTime; | |
| 71 | + | |
| 72 | + @Schema(description = "备注", example = "随便") | |
| 73 | + @ExcelProperty("备注") | |
| 74 | + private String remark; | |
| 75 | + | |
| 76 | + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 77 | + @ExcelProperty("创建时间") | |
| 78 | + private LocalDateTime createTime; | |
| 79 | + | |
| 27 | 80 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueBaseVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueSaveReqVO.java
| ... | ... | @@ -3,30 +3,25 @@ package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; |
| 3 | 3 | import cn.iocoder.yudao.framework.common.validation.Mobile; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.validation.Telephone; |
| 5 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | +import jakarta.validation.constraints.NotEmpty; | |
| 6 | 7 | import lombok.Data; |
| 7 | 8 | import org.springframework.format.annotation.DateTimeFormat; |
| 8 | 9 | |
| 9 | -import jakarta.validation.constraints.NotEmpty; | |
| 10 | -import jakarta.validation.constraints.NotNull; | |
| 11 | 10 | import java.time.LocalDateTime; |
| 12 | 11 | |
| 13 | 12 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 14 | 13 | |
| 15 | -/** | |
| 16 | - * 线索 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 17 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 18 | - */ | |
| 14 | +@Schema(description = "管理后台 - CRM 线索 创建/更新 Request VO") | |
| 19 | 15 | @Data |
| 20 | -public class CrmClueBaseVO { | |
| 16 | +public class CrmClueSaveReqVO { | |
| 17 | + | |
| 18 | + @Schema(description = "编号", example = "10969") | |
| 19 | + private Long id; | |
| 21 | 20 | |
| 22 | 21 | @Schema(description = "线索名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "线索xxx") |
| 23 | 22 | @NotEmpty(message = "线索名称不能为空") |
| 24 | 23 | private String name; |
| 25 | 24 | |
| 26 | - @Schema(description = "客户 id", requiredMode = Schema.RequiredMode.REQUIRED, example = "520") | |
| 27 | - @NotNull(message = "客户不能为空") | |
| 28 | - private Long customerId; | |
| 29 | - | |
| 30 | 25 | @Schema(description = "下次联系时间", example = "2023-10-18 01:00:00") |
| 31 | 26 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 32 | 27 | private LocalDateTime contactNextTime; |
| ... | ... | @@ -46,6 +41,9 @@ public class CrmClueBaseVO { |
| 46 | 41 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 47 | 42 | private LocalDateTime contactLastTime; |
| 48 | 43 | |
| 44 | + @Schema(description = "负责人编号", example = "2048") | |
| 45 | + private Long ownerUserId; | |
| 46 | + | |
| 49 | 47 | @Schema(description = "备注", example = "随便") |
| 50 | 48 | private String remark; |
| 51 | 49 | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransferReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 4 | +import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import jakarta.validation.constraints.NotNull; | |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - 线索转移 Request VO") | |
| 10 | +@Data | |
| 11 | +public class CrmClueTransferReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | |
| 14 | + @NotNull(message = "线索编号不能为空") | |
| 15 | + private Long id; | |
| 16 | + | |
| 17 | + @Schema(description = "新负责人的用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | |
| 18 | + @NotNull(message = "新负责人的用户编号不能为空") | |
| 19 | + private Long newOwnerUserId; | |
| 20 | + | |
| 21 | + @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 22 | + @InEnum(value = CrmPermissionLevelEnum.class) | |
| 23 | + private Integer oldOwnerPermissionLevel; // 老负责人加入团队后的权限级别。如果 null 说明移除 | |
| 24 | + | |
| 25 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueTransformReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import lombok.Data; | |
| 6 | + | |
| 7 | +import java.util.Set; | |
| 8 | + | |
| 9 | +@Schema(description = "管理后台 - 线索转化为客户 Request VO") | |
| 10 | +@Data | |
| 11 | +public class CrmClueTransformReqVO { | |
| 12 | + | |
| 13 | + @Schema(description = "线索编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1024, 1025]") | |
| 14 | + @NotEmpty(message = "线索编号不能为空") | |
| 15 | + private Set<Long> ids; | |
| 16 | + | |
| 17 | +} | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/clue/vo/CrmClueUpdateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.clue.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.EqualsAndHashCode; | |
| 6 | -import lombok.ToString; | |
| 7 | - | |
| 8 | -import jakarta.validation.constraints.NotNull; | |
| 9 | - | |
| 10 | -@Schema(description = "管理后台 - 线索更新 Request VO") | |
| 11 | -@Data | |
| 12 | -@EqualsAndHashCode(callSuper = true) | |
| 13 | -@ToString(callSuper = true) | |
| 14 | -public class CrmClueUpdateReqVO extends CrmClueBaseVO { | |
| 15 | - | |
| 16 | - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10969") | |
| 17 | - @NotNull(message = "编号不能为空") | |
| 18 | - private Long id; | |
| 19 | - | |
| 20 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java
| ... | ... | @@ -4,32 +4,36 @@ import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.lang.Assert; |
| 5 | 5 | import cn.hutool.core.util.NumberUtil; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 7 | -import cn.iocoder.yudao.framework.common.pojo.PageParam; | |
| 8 | 7 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 9 | 8 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 9 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 10 | 10 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 12 | 12 | import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*; |
| 13 | -import cn.iocoder.yudao.module.crm.convert.contact.ContactConvert; | |
| 13 | +import cn.iocoder.yudao.module.crm.convert.contact.CrmContactConvert; | |
| 14 | 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO; |
| 15 | 15 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 16 | 16 | import cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants; |
| 17 | +import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService; | |
| 17 | 18 | import cn.iocoder.yudao.module.crm.service.contact.CrmContactService; |
| 18 | 19 | import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService; |
| 20 | +import cn.iocoder.yudao.module.system.api.logger.OperateLogApi; | |
| 21 | +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2PageReqDTO; | |
| 22 | +import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogV2RespDTO; | |
| 19 | 23 | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| 20 | 24 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 21 | 25 | import com.google.common.collect.Lists; |
| 22 | 26 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | 27 | import io.swagger.v3.oas.annotations.Parameter; |
| 24 | 28 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 29 | +import jakarta.annotation.Resource; | |
| 30 | +import jakarta.servlet.http.HttpServletResponse; | |
| 31 | +import jakarta.validation.Valid; | |
| 25 | 32 | import lombok.extern.slf4j.Slf4j; |
| 26 | 33 | import org.springframework.security.access.prepost.PreAuthorize; |
| 27 | 34 | import org.springframework.validation.annotation.Validated; |
| 28 | 35 | import org.springframework.web.bind.annotation.*; |
| 29 | 36 | |
| 30 | -import jakarta.annotation.Resource; | |
| 31 | -import jakarta.servlet.http.HttpServletResponse; | |
| 32 | -import jakarta.validation.Valid; | |
| 33 | 37 | import java.io.IOException; |
| 34 | 38 | import java.util.Collections; |
| 35 | 39 | import java.util.List; |
| ... | ... | @@ -38,10 +42,11 @@ import java.util.stream.Stream; |
| 38 | 42 | |
| 39 | 43 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 40 | 44 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 41 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap; | |
| 42 | -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 45 | +import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE; | |
| 46 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; | |
| 43 | 47 | import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; |
| 44 | 48 | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; |
| 49 | +import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CONTACT_TYPE; | |
| 45 | 50 | |
| 46 | 51 | @Tag(name = "管理后台 - CRM 联系人") |
| 47 | 52 | @RestController |
| ... | ... | @@ -54,21 +59,26 @@ public class CrmContactController { |
| 54 | 59 | private CrmContactService contactService; |
| 55 | 60 | @Resource |
| 56 | 61 | private CrmCustomerService customerService; |
| 62 | + @Resource | |
| 63 | + private CrmContactBusinessService contactBusinessLinkService; | |
| 57 | 64 | |
| 58 | 65 | @Resource |
| 59 | 66 | private AdminUserApi adminUserApi; |
| 67 | + @Resource | |
| 68 | + private OperateLogApi operateLogApi; | |
| 60 | 69 | |
| 61 | 70 | @PostMapping("/create") |
| 62 | 71 | @Operation(summary = "创建联系人") |
| 63 | 72 | @PreAuthorize("@ss.hasPermission('crm:contact:create')") |
| 64 | - public CommonResult<Long> createContact(@Valid @RequestBody CrmContactCreateReqVO createReqVO) { | |
| 73 | + public CommonResult<Long> createContact(@Valid @RequestBody CrmContactSaveReqVO createReqVO) { | |
| 65 | 74 | return success(contactService.createContact(createReqVO, getLoginUserId())); |
| 66 | 75 | } |
| 67 | 76 | |
| 68 | 77 | @PutMapping("/update") |
| 69 | 78 | @Operation(summary = "更新联系人") |
| 79 | + @OperateLog(enable = false) | |
| 70 | 80 | @PreAuthorize("@ss.hasPermission('crm:contact:update')") |
| 71 | - public CommonResult<Boolean> updateContact(@Valid @RequestBody CrmContactUpdateReqVO updateReqVO) { | |
| 81 | + public CommonResult<Boolean> updateContact(@Valid @RequestBody CrmContactSaveReqVO updateReqVO) { | |
| 72 | 82 | contactService.updateContact(updateReqVO); |
| 73 | 83 | return success(true); |
| 74 | 84 | } |
| ... | ... | @@ -95,34 +105,45 @@ public class CrmContactController { |
| 95 | 105 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(CollUtil.removeNull(Lists.newArrayList( |
| 96 | 106 | NumberUtil.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 97 | 107 | // 2. 获取客户信息 |
| 98 | - List<CrmCustomerDO> customerList = customerService.getCustomerList(Collections.singletonList(contact.getCustomerId())); | |
| 108 | + List<CrmCustomerDO> customerList = customerService.getCustomerList( | |
| 109 | + Collections.singletonList(contact.getCustomerId())); | |
| 99 | 110 | // 3. 直属上级 |
| 100 | - List<CrmContactDO> parentContactList = contactService.getContactList(Collections.singletonList(contact.getParentId())); | |
| 101 | - return success(ContactConvert.INSTANCE.convert(contact, userMap, customerList, parentContactList)); | |
| 111 | + List<CrmContactDO> parentContactList = contactService.getContactList( | |
| 112 | + Collections.singletonList(contact.getParentId()), getLoginUserId()); | |
| 113 | + return success(CrmContactConvert.INSTANCE.convert(contact, userMap, customerList, parentContactList)); | |
| 102 | 114 | } |
| 103 | 115 | |
| 104 | - @GetMapping("/simple-all-list") | |
| 116 | + @GetMapping("/list-by-ids") | |
| 105 | 117 | @Operation(summary = "获得联系人列表") |
| 118 | + @Parameter(name = "ids", description = "编号", required = true, example = "[1024]") | |
| 119 | + @PreAuthorize("@ss.hasPermission('crm:contact:query')") | |
| 120 | + public CommonResult<List<CrmContactRespVO>> getContactListByIds(@RequestParam("ids") List<Long> ids) { | |
| 121 | + return success(BeanUtils.toBean(contactService.getContactList(ids, getLoginUserId()), CrmContactRespVO.class)); | |
| 122 | + } | |
| 123 | + | |
| 124 | + @GetMapping("/simple-all-list") | |
| 125 | + @Operation(summary = "获得联系人的精简列表") | |
| 106 | 126 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") |
| 107 | - public CommonResult<List<CrmContactSimpleRespVO>> getSimpleContactList() { | |
| 108 | - List<CrmContactDO> list = contactService.getContactList(); | |
| 109 | - return success(ContactConvert.INSTANCE.convertAllList(list)); | |
| 127 | + public CommonResult<List<CrmContactRespVO>> getSimpleContactList() { | |
| 128 | + List<CrmContactDO> list = contactService.getSimpleContactList(getLoginUserId()); | |
| 129 | + return success(convertList(list, contact -> // 只返回 id、name 字段 | |
| 130 | + new CrmContactRespVO().setId(contact.getId()).setName(contact.getName()))); | |
| 110 | 131 | } |
| 111 | 132 | |
| 112 | 133 | @GetMapping("/page") |
| 113 | 134 | @Operation(summary = "获得联系人分页") |
| 114 | 135 | @PreAuthorize("@ss.hasPermission('crm:contact:query')") |
| 115 | 136 | public CommonResult<PageResult<CrmContactRespVO>> getContactPage(@Valid CrmContactPageReqVO pageVO) { |
| 116 | - PageResult<CrmContactDO> pageResult = contactService.getContactPage(pageVO); | |
| 117 | - return success(convertDetailContactPage(pageResult)); | |
| 137 | + PageResult<CrmContactDO> pageResult = contactService.getContactPage(pageVO, getLoginUserId()); | |
| 138 | + return success(buildContactDetailPage(pageResult)); | |
| 118 | 139 | } |
| 119 | 140 | |
| 120 | 141 | @GetMapping("/page-by-customer") |
| 121 | 142 | @Operation(summary = "获得联系人分页,基于指定客户") |
| 122 | 143 | public CommonResult<PageResult<CrmContactRespVO>> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { |
| 123 | 144 | Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); |
| 124 | - PageResult<CrmContactDO> pageResult = contactService.getContactPageByCustomer(pageVO); | |
| 125 | - return success(convertDetailContactPage(pageResult)); | |
| 145 | + PageResult<CrmContactDO> pageResult = contactService.getContactPageByCustomerId(pageVO); | |
| 146 | + return success(buildContactDetailPage(pageResult)); | |
| 126 | 147 | } |
| 127 | 148 | |
| 128 | 149 | @GetMapping("/export-excel") |
| ... | ... | @@ -131,19 +152,30 @@ public class CrmContactController { |
| 131 | 152 | @OperateLog(type = EXPORT) |
| 132 | 153 | public void exportContactExcel(@Valid CrmContactPageReqVO exportReqVO, |
| 133 | 154 | HttpServletResponse response) throws IOException { |
| 134 | - exportReqVO.setPageNo(PageParam.PAGE_SIZE_NONE); | |
| 135 | - PageResult<CrmContactDO> pageResult = contactService.getContactPage(exportReqVO); | |
| 155 | + exportReqVO.setPageNo(PAGE_SIZE_NONE); | |
| 156 | + PageResult<CrmContactDO> pageResult = contactService.getContactPage(exportReqVO, getLoginUserId()); | |
| 136 | 157 | ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class, |
| 137 | - convertDetailContactPage(pageResult).getList()); | |
| 158 | + buildContactDetailPage(pageResult).getList()); | |
| 159 | + } | |
| 160 | + | |
| 161 | + @GetMapping("/operate-log-page") | |
| 162 | + @Operation(summary = "获得客户操作日志") | |
| 163 | + @PreAuthorize("@ss.hasPermission('crm:customer:query')") | |
| 164 | + public CommonResult<PageResult<OperateLogV2RespDTO>> getCustomerOperateLog(@RequestParam("bizId") Long bizId) { | |
| 165 | + OperateLogV2PageReqDTO reqVO = new OperateLogV2PageReqDTO(); | |
| 166 | + reqVO.setPageSize(PAGE_SIZE_NONE); // 不分页 | |
| 167 | + reqVO.setBizType(CRM_CONTACT_TYPE); | |
| 168 | + reqVO.setBizId(bizId); | |
| 169 | + return success(operateLogApi.getOperateLogPage(BeanUtils.toBean(reqVO, OperateLogV2PageReqDTO.class))); | |
| 138 | 170 | } |
| 139 | 171 | |
| 140 | 172 | /** |
| 141 | - * 转换成详细的联系人分页,即读取关联信息 | |
| 173 | + * 构建详细的联系人分页结果 | |
| 142 | 174 | * |
| 143 | - * @param pageResult 联系人分页 | |
| 144 | - * @return 详细的联系人分页 | |
| 175 | + * @param pageResult 简单的联系人分页结果 | |
| 176 | + * @return 详细的联系人分页结果 | |
| 145 | 177 | */ |
| 146 | - private PageResult<CrmContactRespVO> convertDetailContactPage(PageResult<CrmContactDO> pageResult) { | |
| 178 | + private PageResult<CrmContactRespVO> buildContactDetailPage(PageResult<CrmContactDO> pageResult) { | |
| 147 | 179 | List<CrmContactDO> contactList = pageResult.getList(); |
| 148 | 180 | if (CollUtil.isEmpty(contactList)) { |
| 149 | 181 | return PageResult.empty(pageResult.getTotal()); |
| ... | ... | @@ -156,8 +188,34 @@ public class CrmContactController { |
| 156 | 188 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 157 | 189 | // 3. 直属上级 |
| 158 | 190 | List<CrmContactDO> parentContactList = contactService.getContactList( |
| 159 | - convertSet(contactList, CrmContactDO::getParentId)); | |
| 160 | - return ContactConvert.INSTANCE.convertPage(pageResult, userMap, crmCustomerDOList, parentContactList); | |
| 191 | + convertSet(contactList, CrmContactDO::getParentId), getLoginUserId()); | |
| 192 | + return CrmContactConvert.INSTANCE.convertPage(pageResult, userMap, crmCustomerDOList, parentContactList); | |
| 193 | + } | |
| 194 | + | |
| 195 | + @PutMapping("/transfer") | |
| 196 | + @Operation(summary = "联系人转移") | |
| 197 | + @PreAuthorize("@ss.hasPermission('crm:contact:update')") | |
| 198 | + public CommonResult<Boolean> transfer(@Valid @RequestBody CrmContactTransferReqVO reqVO) { | |
| 199 | + contactService.transferContact(reqVO, getLoginUserId()); | |
| 200 | + return success(true); | |
| 201 | + } | |
| 202 | + | |
| 203 | + // ================== 关联/取关联系人 =================== | |
| 204 | + | |
| 205 | + @PostMapping("/create-business-list") | |
| 206 | + @Operation(summary = "创建联系人与商机的关联") | |
| 207 | + @PreAuthorize("@ss.hasPermission('crm:contact:create-business')") | |
| 208 | + public CommonResult<Boolean> createContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO createReqVO) { | |
| 209 | + contactBusinessLinkService.createContactBusinessList(createReqVO); | |
| 210 | + return success(true); | |
| 211 | + } | |
| 212 | + | |
| 213 | + @DeleteMapping("/delete-business-list") | |
| 214 | + @Operation(summary = "删除联系人与联系人的关联") | |
| 215 | + @PreAuthorize("@ss.hasPermission('crm:contact:delete-business')") | |
| 216 | + public CommonResult<Boolean> deleteContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO deleteReqVO) { | |
| 217 | + contactBusinessLinkService.deleteContactBusinessList(deleteReqVO); | |
| 218 | + return success(true); | |
| 161 | 219 | } |
| 162 | 220 | |
| 163 | 221 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import jakarta.validation.constraints.NotEmpty; | |
| 5 | +import jakarta.validation.constraints.NotNull; | |
| 6 | +import lombok.Data; | |
| 7 | + | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 用于关联,取消关联的操作 | |
| 11 | +@Data | |
| 12 | +public class CrmContactBusinessReqVO { | |
| 13 | + | |
| 14 | + @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") | |
| 15 | + @NotNull(message="联系人不能为空") | |
| 16 | + private Long contactId; | |
| 17 | + | |
| 18 | + @Schema(description = "商机编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") | |
| 19 | + @NotEmpty(message="商机不能为空") | |
| 20 | + private List<Long> businessIds; | |
| 21 | + | |
| 22 | +} | |
| 0 | 23 | \ No newline at end of file | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactPageReqVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageParam; |
| 4 | +import cn.iocoder.yudao.framework.common.validation.InEnum; | |
| 5 | +import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; | |
| 4 | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 7 | import lombok.Data; |
| 6 | 8 | import lombok.EqualsAndHashCode; |
| ... | ... | @@ -33,4 +35,8 @@ public class CrmContactPageReqVO extends PageParam { |
| 33 | 35 | @Schema(description = "微信", example = "zzZ98373") |
| 34 | 36 | private String wechat; |
| 35 | 37 | |
| 38 | + @Schema(description = "场景类型", example = "1") | |
| 39 | + @InEnum(CrmSceneTypeEnum.class) | |
| 40 | + private Integer sceneType; // 场景类型,为 null 时则表示全部 | |
| 41 | + | |
| 36 | 42 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactRespVO.java
| 1 | 1 | package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; |
| 2 | 2 | |
| 3 | +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 4 | +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 5 | +import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; | |
| 3 | 6 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| 4 | 7 | import com.alibaba.excel.annotation.ExcelProperty; |
| 5 | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| 6 | -import lombok.*; | |
| 9 | +import lombok.Data; | |
| 10 | +import lombok.ToString; | |
| 11 | + | |
| 7 | 12 | import java.time.LocalDateTime; |
| 8 | 13 | |
| 9 | 14 | @Schema(description = "管理后台 - CRM 联系人 Response VO") |
| 10 | 15 | @Data |
| 11 | -@EqualsAndHashCode(callSuper = true) | |
| 12 | 16 | @ToString(callSuper = true) |
| 13 | 17 | @ExcelIgnoreUnannotated |
| 14 | -public class CrmContactRespVO extends CrmContactBaseVO { | |
| 18 | +public class CrmContactRespVO { | |
| 15 | 19 | |
| 16 | 20 | @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") |
| 17 | 21 | private Long id; |
| 18 | 22 | |
| 19 | - @Schema(description = "创建时间") | |
| 20 | - @ExcelProperty(value = "创建时间", order = 8) | |
| 21 | - private LocalDateTime createTime; | |
| 23 | + @Schema(description = "姓名", example = "芋艿") | |
| 24 | + @ExcelProperty(value = "姓名", order = 1) | |
| 25 | + private String name; | |
| 26 | + | |
| 27 | + @Schema(description = "客户编号", example = "10795") | |
| 28 | + private Long customerId; | |
| 29 | + | |
| 30 | + @Schema(description = "性别") | |
| 31 | + @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) | |
| 32 | + @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) | |
| 33 | + private Integer sex; | |
| 34 | + | |
| 35 | + @Schema(description = "职位") | |
| 36 | + @ExcelProperty(value = "职位", order = 3) | |
| 37 | + private String post; | |
| 38 | + | |
| 39 | + @Schema(description = "是否关键决策人") | |
| 40 | + @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) | |
| 41 | + @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 42 | + private Boolean master; | |
| 43 | + | |
| 44 | + @Schema(description = "直属上级", example = "23457") | |
| 45 | + private Long parentId; | |
| 46 | + | |
| 47 | + @Schema(description = "手机号", example = "1387171766") | |
| 48 | + @ExcelProperty(value = "手机号", order = 4) | |
| 49 | + private String mobile; | |
| 50 | + | |
| 51 | + @Schema(description = "电话", example = "021-0029922") | |
| 52 | + @ExcelProperty(value = "电话", order = 4) | |
| 53 | + private String telephone; | |
| 54 | + | |
| 55 | + @Schema(description = "QQ", example = "197272662") | |
| 56 | + @ExcelProperty(value = "QQ", order = 4) | |
| 57 | + private Long qq; | |
| 58 | + | |
| 59 | + @Schema(description = "微信", example = "zzz3883") | |
| 60 | + @ExcelProperty(value = "微信", order = 4) | |
| 61 | + private String wechat; | |
| 62 | + | |
| 63 | + @Schema(description = "电子邮箱", example = "1111@22.com") | |
| 64 | + @ExcelProperty(value = "邮箱", order = 4) | |
| 65 | + private String email; | |
| 66 | + | |
| 67 | + @Schema(description = "地区编号", example = "20158") | |
| 68 | + private Integer areaId; | |
| 69 | + | |
| 70 | + @Schema(description = "地址") | |
| 71 | + @ExcelProperty(value = "地址", order = 5) | |
| 72 | + private String detailAddress; | |
| 73 | + | |
| 74 | + @Schema(description = "备注", example = "你说的对") | |
| 75 | + @ExcelProperty(value = "备注", order = 6) | |
| 76 | + private String remark; | |
| 77 | + | |
| 78 | + @Schema(description = "负责人用户编号", example = "14334") | |
| 79 | + private Long ownerUserId; | |
| 80 | + | |
| 81 | + @Schema(description = "最后跟进时间") | |
| 82 | + @ExcelProperty(value = "最后跟进时间", order = 6) | |
| 83 | + private LocalDateTime contactLastTime; | |
| 22 | 84 | |
| 23 | - @Schema(description = "更新时间") | |
| 24 | - @ExcelProperty(value = "更新时间", order = 8) | |
| 25 | - private LocalDateTime updateTime; | |
| 85 | + @Schema(description = "下次联系时间") | |
| 86 | + @ExcelProperty(value = "下次联系时间", order = 6) | |
| 87 | + private LocalDateTime contactNextTime; | |
| 26 | 88 | |
| 27 | 89 | @Schema(description = "创建人", example = "25682") |
| 28 | 90 | private String creator; |
| ... | ... | @@ -31,7 +93,7 @@ public class CrmContactRespVO extends CrmContactBaseVO { |
| 31 | 93 | @ExcelProperty(value = "创建人", order = 8) |
| 32 | 94 | private String creatorName; |
| 33 | 95 | |
| 34 | - @ExcelProperty(value = "客户名称",order = 2) | |
| 96 | + @ExcelProperty(value = "客户名称", order = 2) | |
| 35 | 97 | @Schema(description = "客户名字", example = "test") |
| 36 | 98 | private String customerName; |
| 37 | 99 | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBaseVO.java renamed to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSaveReqVO.java
| ... | ... | @@ -2,102 +2,102 @@ package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.validation.Mobile; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.validation.Telephone; |
| 5 | -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; | |
| 6 | -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; | |
| 7 | -import cn.iocoder.yudao.module.infra.enums.DictTypeConstants; | |
| 8 | -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | |
| 9 | -import com.alibaba.excel.annotation.ExcelProperty; | |
| 5 | +import cn.iocoder.yudao.module.crm.framework.operatelog.core.*; | |
| 6 | +import com.mzt.logapi.starter.annotation.DiffLogField; | |
| 10 | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | +import jakarta.validation.constraints.Email; | |
| 9 | +import jakarta.validation.constraints.NotNull; | |
| 11 | 10 | import lombok.Data; |
| 12 | 11 | import org.springframework.format.annotation.DateTimeFormat; |
| 13 | 12 | |
| 14 | -import jakarta.validation.constraints.Email; | |
| 15 | -import jakarta.validation.constraints.NotNull; | |
| 16 | 13 | import java.time.LocalDateTime; |
| 17 | 14 | |
| 18 | 15 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; |
| 19 | 16 | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; |
| 20 | 17 | |
| 21 | -// TODO zyna:要不按照新的,干掉这个 basevo,都放子类里 | |
| 22 | -/** | |
| 23 | - * CRM 联系人 Base VO,提供给添加、修改、详细的子 VO 使用 | |
| 24 | - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 | |
| 25 | - */ | |
| 18 | +@Schema(description = "管理后台 - CRM 联系人创建/更新 Request VO") | |
| 26 | 19 | @Data |
| 27 | -@ExcelIgnoreUnannotated | |
| 28 | -public class CrmContactBaseVO { | |
| 20 | +public class CrmContactSaveReqVO { | |
| 21 | + | |
| 22 | + @Schema(description = "主键", example = "3167") | |
| 23 | + private Long id; | |
| 29 | 24 | |
| 30 | - @ExcelProperty(value = "姓名",order = 1) | |
| 31 | 25 | @Schema(description = "姓名", example = "芋艿") |
| 32 | 26 | @NotNull(message = "姓名不能为空") |
| 27 | + @DiffLogField(name = "姓名") | |
| 33 | 28 | private String name; |
| 34 | 29 | |
| 35 | 30 | @Schema(description = "客户编号", example = "10795") |
| 31 | + @DiffLogField(name = "客户", function = CrmCustomerParseFunction.NAME) | |
| 36 | 32 | private Long customerId; |
| 37 | 33 | |
| 38 | - @ExcelProperty(value = "性别", converter = DictConvert.class, order = 3) | |
| 39 | - @DictFormat(cn.iocoder.yudao.module.system.enums.DictTypeConstants.USER_SEX) | |
| 40 | 34 | @Schema(description = "性别") |
| 35 | + @DiffLogField(name = "性别", function = SysSexParseFunction.NAME) | |
| 41 | 36 | private Integer sex; |
| 42 | 37 | |
| 43 | 38 | @Schema(description = "职位") |
| 44 | - @ExcelProperty(value = "职位", order = 3) | |
| 39 | + @DiffLogField(name = "职位") | |
| 45 | 40 | private String post; |
| 46 | 41 | |
| 47 | 42 | @Schema(description = "是否关键决策人") |
| 48 | - @ExcelProperty(value = "是否关键决策人", converter = DictConvert.class, order = 3) | |
| 49 | - @DictFormat(DictTypeConstants.BOOLEAN_STRING) | |
| 43 | + @DiffLogField(name = "关键决策人", function = SysBooleanParseFunction.NAME) | |
| 50 | 44 | private Boolean master; |
| 51 | 45 | |
| 52 | 46 | @Schema(description = "直属上级", example = "23457") |
| 47 | + @DiffLogField(name = "直属上级", function = CrmContactParseFunction.NAME) | |
| 53 | 48 | private Long parentId; |
| 54 | 49 | |
| 55 | - @Schema(description = "手机号",example = "1387171766") | |
| 50 | + @Schema(description = "手机号", example = "1387171766") | |
| 56 | 51 | @Mobile |
| 57 | - @ExcelProperty(value = "手机号",order = 4) | |
| 52 | + @DiffLogField(name = "手机号") | |
| 58 | 53 | private String mobile; |
| 59 | 54 | |
| 60 | - @Schema(description = "座机",example = "021-0029922") | |
| 55 | + @Schema(description = "电话", example = "021-0029922") | |
| 61 | 56 | @Telephone |
| 62 | - @ExcelProperty(value = "座机",order = 4) | |
| 57 | + @DiffLogField(name = "电话") | |
| 63 | 58 | private String telephone; |
| 64 | 59 | |
| 65 | - @ExcelProperty(value = "QQ",order = 4) | |
| 66 | - @Schema(description = "QQ",example = "197272662") | |
| 60 | + @Schema(description = "QQ", example = "197272662") | |
| 61 | + @DiffLogField(name = "QQ") | |
| 67 | 62 | private Long qq; |
| 68 | 63 | |
| 69 | - @ExcelProperty(value = "微信",order = 4) | |
| 70 | - @Schema(description = "微信",example = "zzz3883") | |
| 64 | + @Schema(description = "微信", example = "zzz3883") | |
| 65 | + @DiffLogField(name = "微信") | |
| 71 | 66 | private String wechat; |
| 72 | 67 | |
| 73 | - @Schema(description = "电子邮箱",example = "1111@22.com") | |
| 68 | + @Schema(description = "电子邮箱", example = "1111@22.com") | |
| 69 | + @DiffLogField(name = "邮箱") | |
| 74 | 70 | |
| 75 | - @ExcelProperty(value = "邮箱",order = 4) | |
| 76 | 71 | private String email; |
| 77 | 72 | |
| 78 | - @ExcelProperty(value = "地址",order = 5) | |
| 79 | - @Schema(description = "地址") | |
| 80 | - private String address; | |
| 73 | + @Schema(description = "地区编号", example = "20158") | |
| 74 | + @DiffLogField(name = "所在地", function = SysAreaParseFunction.NAME) | |
| 75 | + private Integer areaId; | |
| 81 | 76 | |
| 82 | - @Schema(description = "下次联系时间") | |
| 83 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) | |
| 84 | - @ExcelProperty(value = "下次联系时间",order = 6) | |
| 85 | - private LocalDateTime nextTime; | |
| 77 | + @Schema(description = "地址") | |
| 78 | + @DiffLogField(name = "地址") | |
| 79 | + private String detailAddress; | |
| 86 | 80 | |
| 87 | 81 | @Schema(description = "备注", example = "你说的对") |
| 88 | - @ExcelProperty(value = "备注",order = 6) | |
| 82 | + @DiffLogField(name = "备注") | |
| 89 | 83 | private String remark; |
| 90 | 84 | |
| 91 | - @Schema(description = "最后跟进时间") | |
| 92 | - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 93 | - @ExcelProperty(value = "最后跟进时间",order = 6) | |
| 94 | - private LocalDateTime lastTime; | |
| 95 | - | |
| 96 | 85 | @Schema(description = "负责人用户编号", example = "14334") |
| 97 | 86 | @NotNull(message = "负责人不能为空") |
| 87 | + @DiffLogField(name = "负责人", function = SysAdminUserParseFunction.NAME) | |
| 98 | 88 | private Long ownerUserId; |
| 99 | 89 | |
| 100 | - @Schema(description = "地区编号", example = "20158") | |
| 101 | - private Integer areaId; | |
| 90 | + @Schema(description = "最后跟进时间") | |
| 91 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 92 | + @DiffLogField(name = "最后跟进时间") | |
| 93 | + private LocalDateTime contactLastTime; | |
| 94 | + | |
| 95 | + @Schema(description = "下次联系时间") | |
| 96 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) | |
| 97 | + @DiffLogField(name = "下次联系时间") | |
| 98 | + private LocalDateTime contactNextTime; | |
| 99 | + | |
| 100 | + @Schema(description = "关联商机 ID", example = "122233") | |
| 101 | + private Long businessId; // 注意:该字段用于在【商机】详情界面「新建联系人」时,自动进行关联 | |
| 102 | 102 | |
| 103 | 103 | } | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactSimpleRespVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.ToString; | |
| 6 | - | |
| 7 | -@Schema(description = "管理后台 - CRM 联系人的精简 Response VO") | |
| 8 | -@Data | |
| 9 | -@ToString(callSuper = true) | |
| 10 | -public class CrmContactSimpleRespVO { | |
| 11 | - | |
| 12 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") | |
| 13 | - private Long id; | |
| 14 | - | |
| 15 | - @Schema(description = "姓名", example = "芋艿") | |
| 16 | - private String name; | |
| 17 | - | |
| 18 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactUpdateReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contact.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.EqualsAndHashCode; | |
| 6 | -import lombok.ToString; | |
| 7 | - | |
| 8 | -import jakarta.validation.constraints.NotNull; | |
| 9 | - | |
| 10 | -@Schema(description = "管理后台 - CRM 联系人更新 Request VO") | |
| 11 | -@Data | |
| 12 | -@EqualsAndHashCode(callSuper = true) | |
| 13 | -@ToString(callSuper = true) | |
| 14 | -public class CrmContactUpdateReqVO extends CrmContactBaseVO { | |
| 15 | - | |
| 16 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "3167") | |
| 17 | - @NotNull(message = "主键不能为空") | |
| 18 | - private Long id; | |
| 19 | - | |
| 20 | -} |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/CrmContactBusinessLinkController.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | |
| 4 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | |
| 5 | -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 6 | -import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO; | |
| 7 | -import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkPageReqVO; | |
| 8 | -import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkRespVO; | |
| 9 | -import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkSaveReqVO; | |
| 10 | -import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO; | |
| 11 | -import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO; | |
| 12 | -import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService; | |
| 13 | -import cn.iocoder.yudao.module.crm.service.contactbusinesslink.CrmContactBusinessLinkService; | |
| 14 | -import io.swagger.v3.oas.annotations.Operation; | |
| 15 | -import io.swagger.v3.oas.annotations.Parameter; | |
| 16 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 17 | -import org.springframework.security.access.prepost.PreAuthorize; | |
| 18 | -import org.springframework.transaction.annotation.Transactional; | |
| 19 | -import org.springframework.validation.annotation.Validated; | |
| 20 | -import org.springframework.web.bind.annotation.*; | |
| 21 | - | |
| 22 | -import jakarta.annotation.Resource; | |
| 23 | -import jakarta.validation.Valid; | |
| 24 | -import java.util.List; | |
| 25 | - | |
| 26 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 27 | -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | |
| 28 | -import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS; | |
| 29 | - | |
| 30 | -@Tag(name = "管理后台 - CRM 联系人商机关联") | |
| 31 | -@RestController | |
| 32 | -@RequestMapping("/crm/contact-business-link") | |
| 33 | -@Validated | |
| 34 | -public class CrmContactBusinessLinkController { | |
| 35 | - | |
| 36 | - @Resource | |
| 37 | - private CrmContactBusinessLinkService contactBusinessLinkService; | |
| 38 | - @Resource | |
| 39 | - private CrmBusinessService crmBusinessService; | |
| 40 | - | |
| 41 | - // TODO @zyna:createContactBusinessLink 和 createContactBusinessLinkBatch 是不是合并成一个接口?contactId、List<businessId> | |
| 42 | - @PostMapping("/create") | |
| 43 | - @Operation(summary = "创建联系人商机关联") | |
| 44 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:create')") | |
| 45 | - public CommonResult<Long> createContactBusinessLink(@Valid @RequestBody CrmContactBusinessLinkSaveReqVO createReqVO) { | |
| 46 | - return success(contactBusinessLinkService.createContactBusinessLink(createReqVO)); | |
| 47 | - } | |
| 48 | - | |
| 49 | - @PostMapping("/create-batch") | |
| 50 | - @Operation(summary = "创建联系人商机关联") | |
| 51 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:create')") | |
| 52 | - @Transactional(rollbackFor = Exception.class) | |
| 53 | - public CommonResult<Boolean> createContactBusinessLinkBatch( | |
| 54 | - @Valid @RequestBody List<CrmContactBusinessLinkSaveReqVO> createReqVO) { | |
| 55 | - createReqVO.stream().forEach(item -> { | |
| 56 | - CrmBusinessDO crmBusinessDO = crmBusinessService.getBusiness(item.getBusinessId()); | |
| 57 | - if(crmBusinessDO == null){ | |
| 58 | - throw exception(BUSINESS_NOT_EXISTS); | |
| 59 | - } | |
| 60 | - }); | |
| 61 | - contactBusinessLinkService.createContactBusinessLinkBatch(createReqVO); | |
| 62 | - return success(true); | |
| 63 | - } | |
| 64 | - | |
| 65 | - // TODO @zyna:这个接口是不是可以删除掉了哈?应该不存在更新。 | |
| 66 | - @PutMapping("/update") | |
| 67 | - @Operation(summary = "更新联系人商机关联") | |
| 68 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:update')") | |
| 69 | - public CommonResult<Boolean> updateContactBusinessLink(@Valid @RequestBody CrmContactBusinessLinkSaveReqVO updateReqVO) { | |
| 70 | - contactBusinessLinkService.updateContactBusinessLink(updateReqVO); | |
| 71 | - return success(true); | |
| 72 | - } | |
| 73 | - | |
| 74 | - // TODO @zyna:删除,是不是传递 ids? | |
| 75 | - @DeleteMapping("/delete-batch") | |
| 76 | - @Operation(summary = "批量删除联系人商机关联") | |
| 77 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:delete')") | |
| 78 | - public CommonResult<Boolean> deleteContactBusinessLinkBatch(@Valid @RequestBody List<CrmContactBusinessLinkSaveReqVO> deleteList) { | |
| 79 | - contactBusinessLinkService.deleteContactBusinessLink(deleteList); | |
| 80 | - return success(true); | |
| 81 | - } | |
| 82 | - | |
| 83 | - // TODO @zyna:这个接口是不是可以删除掉了哈?应该不存在单个读取; | |
| 84 | - @GetMapping("/get") | |
| 85 | - @Operation(summary = "获得联系人商机关联") | |
| 86 | - @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 87 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')") | |
| 88 | - public CommonResult<CrmContactBusinessLinkRespVO> getContactBusinessLink(@RequestParam("id") Long id) { | |
| 89 | - CrmContactBusinessLinkDO contactBusinessLink = contactBusinessLinkService.getContactBusinessLink(id); | |
| 90 | - return success(BeanUtils.toBean(contactBusinessLink, CrmContactBusinessLinkRespVO.class)); | |
| 91 | - } | |
| 92 | - | |
| 93 | - // TODO @zyna:这个可以转化下,使用客户编号去查询,就是使用 CrmBusinessController 的 getBusinessPageByCustomer 接口;目的是:复用 | |
| 94 | - @GetMapping("/page-by-contact") | |
| 95 | - @Operation(summary = "获得联系人商机关联") | |
| 96 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')") | |
| 97 | - public CommonResult<PageResult<CrmBusinessRespVO>> getContactBusinessLinkByContact( | |
| 98 | - @Valid CrmContactBusinessLinkPageReqVO pageReqVO) { | |
| 99 | - PageResult<CrmBusinessRespVO> contactBusinessLink = contactBusinessLinkService.getContactBusinessLinkPageByContact(pageReqVO); | |
| 100 | - return success(contactBusinessLink); | |
| 101 | - } | |
| 102 | - | |
| 103 | - // TODO @zyna:这个优化下,搞到 CrmBusinessController 里去,加一个 CrmBusinessController 的 getBusinessPageByContact 接口;目的是: | |
| 104 | - @GetMapping("/page") | |
| 105 | - @Operation(summary = "获得联系人商机关联分页") | |
| 106 | - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')") | |
| 107 | - public CommonResult<PageResult<CrmContactBusinessLinkRespVO>> getContactBusinessLinkPage( | |
| 108 | - @Valid CrmContactBusinessLinkPageReqVO pageReqVO) { | |
| 109 | - PageResult<CrmContactBusinessLinkDO> pageResult = contactBusinessLinkService.getContactBusinessLinkPage(pageReqVO); | |
| 110 | - return success(BeanUtils.toBean(pageResult, CrmContactBusinessLinkRespVO.class)); | |
| 111 | - } | |
| 112 | - | |
| 113 | - // TODO @zyna:最终梳理完后,应该就 2 个接口,要不直接合并到 CrmContactController 中,不作为独立模块,就关联、接触关联。其实和 user 设置它有哪些岗位、部门是类似的。 | |
| 114 | - | |
| 115 | -} | |
| 116 | 0 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkRespVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo; | |
| 2 | - | |
| 3 | -import com.alibaba.excel.annotation.ExcelProperty; | |
| 4 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 5 | -import lombok.Data; | |
| 6 | - | |
| 7 | -import java.time.LocalDateTime; | |
| 8 | - | |
| 9 | -@Schema(description = "管理后台 - CRM 联系人商机关联 Response VO") | |
| 10 | -@Data | |
| 11 | -public class CrmContactBusinessLinkRespVO { | |
| 12 | - | |
| 13 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "17220") | |
| 14 | - @ExcelProperty("主键") | |
| 15 | - private Long id; | |
| 16 | - | |
| 17 | - @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") | |
| 18 | - private Long contactId; | |
| 19 | - | |
| 20 | - @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") | |
| 21 | - private Long businessId; | |
| 22 | - | |
| 23 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 24 | - private LocalDateTime createTime; | |
| 25 | - | |
| 26 | -} | |
| 27 | 0 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkSaveReqVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | - | |
| 6 | -import jakarta.validation.constraints.NotNull; | |
| 7 | - | |
| 8 | -@Schema(description = "管理后台 - CRM 联系人商机关联新增/修改 Request VO") | |
| 9 | -@Data | |
| 10 | -public class CrmContactBusinessLinkSaveReqVO { | |
| 11 | - | |
| 12 | - @Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "17220") | |
| 13 | - private Long id; | |
| 14 | - | |
| 15 | - @Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878") | |
| 16 | - @NotNull(message="联系人不能为空") | |
| 17 | - private Long contactId; | |
| 18 | - | |
| 19 | - @Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638") | |
| 20 | - @NotNull(message="商机不能为空") | |
| 21 | - private Long businessId; | |
| 22 | - | |
| 23 | -} | |
| 24 | 0 | \ No newline at end of file |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java
| ... | ... | @@ -5,10 +5,11 @@ import cn.hutool.core.lang.Assert; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 8 | +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | |
| 8 | 9 | import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; |
| 9 | 10 | import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; |
| 10 | 11 | import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.*; |
| 11 | -import cn.iocoder.yudao.module.crm.convert.contract.ContractConvert; | |
| 12 | +import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert; | |
| 12 | 13 | import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO; |
| 13 | 14 | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| 14 | 15 | import cn.iocoder.yudao.module.crm.service.contract.CrmContractService; |
| ... | ... | @@ -18,13 +19,13 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 18 | 19 | import io.swagger.v3.oas.annotations.Operation; |
| 19 | 20 | import io.swagger.v3.oas.annotations.Parameter; |
| 20 | 21 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 22 | +import jakarta.annotation.Resource; | |
| 23 | +import jakarta.servlet.http.HttpServletResponse; | |
| 24 | +import jakarta.validation.Valid; | |
| 21 | 25 | import org.springframework.security.access.prepost.PreAuthorize; |
| 22 | 26 | import org.springframework.validation.annotation.Validated; |
| 23 | 27 | import org.springframework.web.bind.annotation.*; |
| 24 | 28 | |
| 25 | -import jakarta.annotation.Resource; | |
| 26 | -import jakarta.servlet.http.HttpServletResponse; | |
| 27 | -import jakarta.validation.Valid; | |
| 28 | 29 | import java.io.IOException; |
| 29 | 30 | import java.util.List; |
| 30 | 31 | import java.util.Map; |
| ... | ... | @@ -53,14 +54,14 @@ public class CrmContractController { |
| 53 | 54 | @PostMapping("/create") |
| 54 | 55 | @Operation(summary = "创建合同") |
| 55 | 56 | @PreAuthorize("@ss.hasPermission('crm:contract:create')") |
| 56 | - public CommonResult<Long> createContract(@Valid @RequestBody CrmContractCreateReqVO createReqVO) { | |
| 57 | + public CommonResult<Long> createContract(@Valid @RequestBody CrmContractSaveReqVO createReqVO) { | |
| 57 | 58 | return success(contractService.createContract(createReqVO, getLoginUserId())); |
| 58 | 59 | } |
| 59 | 60 | |
| 60 | 61 | @PutMapping("/update") |
| 61 | 62 | @Operation(summary = "更新合同") |
| 62 | 63 | @PreAuthorize("@ss.hasPermission('crm:contract:update')") |
| 63 | - public CommonResult<Boolean> updateContract(@Valid @RequestBody CrmContractUpdateReqVO updateReqVO) { | |
| 64 | + public CommonResult<Boolean> updateContract(@Valid @RequestBody CrmContractSaveReqVO updateReqVO) { | |
| 64 | 65 | contractService.updateContract(updateReqVO); |
| 65 | 66 | return success(true); |
| 66 | 67 | } |
| ... | ... | @@ -78,25 +79,25 @@ public class CrmContractController { |
| 78 | 79 | @Operation(summary = "获得合同") |
| 79 | 80 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 80 | 81 | @PreAuthorize("@ss.hasPermission('crm:contract:query')") |
| 81 | - public CommonResult<ContractRespVO> getContract(@RequestParam("id") Long id) { | |
| 82 | + public CommonResult<CrmContractRespVO> getContract(@RequestParam("id") Long id) { | |
| 82 | 83 | CrmContractDO contract = contractService.getContract(id); |
| 83 | - return success(ContractConvert.INSTANCE.convert(contract)); | |
| 84 | + return success(BeanUtils.toBean(contract, CrmContractRespVO.class)); | |
| 84 | 85 | } |
| 85 | 86 | |
| 86 | 87 | @GetMapping("/page") |
| 87 | 88 | @Operation(summary = "获得合同分页") |
| 88 | 89 | @PreAuthorize("@ss.hasPermission('crm:contract:query')") |
| 89 | - public CommonResult<PageResult<ContractRespVO>> getContractPage(@Valid CrmContractPageReqVO pageVO) { | |
| 90 | - PageResult<CrmContractDO> pageResult = contractService.getContractPage(pageVO); | |
| 91 | - return success(convertDetailContractPage(pageResult)); | |
| 90 | + public CommonResult<PageResult<CrmContractRespVO>> getContractPage(@Valid CrmContractPageReqVO pageVO) { | |
| 91 | + PageResult<CrmContractDO> pageResult = contractService.getContractPage(pageVO, getLoginUserId()); | |
| 92 | + return success(buildContractDetailPage(pageResult)); | |
| 92 | 93 | } |
| 93 | 94 | |
| 94 | 95 | @GetMapping("/page-by-customer") |
| 95 | 96 | @Operation(summary = "获得联系人分页,基于指定客户") |
| 96 | - public CommonResult<PageResult<ContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { | |
| 97 | + public CommonResult<PageResult<CrmContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { | |
| 97 | 98 | Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); |
| 98 | - PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomer(pageVO); | |
| 99 | - return success(convertDetailContractPage(pageResult)); | |
| 99 | + PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageVO); | |
| 100 | + return success(buildContractDetailPage(pageResult)); | |
| 100 | 101 | } |
| 101 | 102 | |
| 102 | 103 | @GetMapping("/export-excel") |
| ... | ... | @@ -105,19 +106,19 @@ public class CrmContractController { |
| 105 | 106 | @OperateLog(type = EXPORT) |
| 106 | 107 | public void exportContractExcel(@Valid CrmContractPageReqVO exportReqVO, |
| 107 | 108 | HttpServletResponse response) throws IOException { |
| 108 | - PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO); | |
| 109 | + PageResult<CrmContractDO> pageResult = contractService.getContractPage(exportReqVO, getLoginUserId()); | |
| 109 | 110 | // 导出 Excel |
| 110 | 111 | ExcelUtils.write(response, "合同.xls", "数据", CrmContractExcelVO.class, |
| 111 | - ContractConvert.INSTANCE.convertList02(pageResult.getList())); | |
| 112 | + BeanUtils.toBean(pageResult.getList(), CrmContractExcelVO.class)); | |
| 112 | 113 | } |
| 113 | 114 | |
| 114 | 115 | /** |
| 115 | - * 转换成详细的合同分页,即读取关联信息 | |
| 116 | + * 构建详细的合同分页结果 | |
| 116 | 117 | * |
| 117 | - * @param pageResult 合同分页 | |
| 118 | - * @return 详细的合同分页 | |
| 118 | + * @param pageResult 简单的合同分页结果 | |
| 119 | + * @return 详细的合同分页结果 | |
| 119 | 120 | */ |
| 120 | - private PageResult<ContractRespVO> convertDetailContractPage(PageResult<CrmContractDO> pageResult) { | |
| 121 | + private PageResult<CrmContractRespVO> buildContractDetailPage(PageResult<CrmContractDO> pageResult) { | |
| 121 | 122 | List<CrmContractDO> contactList = pageResult.getList(); |
| 122 | 123 | if (CollUtil.isEmpty(contactList)) { |
| 123 | 124 | return PageResult.empty(pageResult.getTotal()); |
| ... | ... | @@ -128,7 +129,7 @@ public class CrmContractController { |
| 128 | 129 | // 2. 获取创建人、负责人列表 |
| 129 | 130 | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, |
| 130 | 131 | contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); |
| 131 | - return ContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList); | |
| 132 | + return CrmContractConvert.INSTANCE.convertPage(pageResult, userMap, customerList); | |
| 132 | 133 | } |
| 133 | 134 | |
| 134 | 135 | @PutMapping("/transfer") | ... | ... |
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/vo/ContractRespVO.java deleted
| 1 | -package cn.iocoder.yudao.module.crm.controller.admin.contract.vo; | |
| 2 | - | |
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | -import lombok.Data; | |
| 5 | -import lombok.EqualsAndHashCode; | |
| 6 | -import lombok.ToString; | |
| 7 | - | |
| 8 | -import java.time.LocalDateTime; | |
| 9 | - | |
| 10 | -@Schema(description = "管理后台 - CRM 合同 Response VO") | |
| 11 | -@Data | |
| 12 | -@EqualsAndHashCode(callSuper = true) | |
| 13 | -@ToString(callSuper = true) | |
| 14 | -public class ContractRespVO extends CrmContractBaseVO { | |
| 15 | - | |
| 16 | - @Schema(description = "合同编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10430") | |
| 17 | - private Long id; | |
| 18 | - | |
| 19 | - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 20 | - private LocalDateTime createTime; | |
| 21 | - | |
| 22 | - @Schema(description = "创建人", example = "25682") | |
| 23 | - private String creator; | |
| 24 | - | |
| 25 | - @Schema(description = "创建人名字", example = "test") | |
| 26 | - private String creatorName; | |
| 27 | - | |
| 28 | - @Schema(description = "客户名字", example = "test") | |
| 29 | - private String customerName; | |
| 30 | - | |
| 31 | - @Schema(description = "负责人", example = "test") | |
| 32 | - private String ownerUserName; | |
| 33 | - | |
| 34 | - @Schema(description = "审批状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") | |
| 35 | - private Integer auditStatus; | |
| 36 | - | |
| 37 | -} |