Commit 7d026a35dc7b7aaa6aab2cf8cef96b08d9477cf7

Authored by jiangwei
2 parents fccc4aa6 652359a1

Merge remote-tracking branch 'origin/master' into pms_minratio

# Conflicts:
#	config/routers/pms.ts
Showing 71 changed files with 1529 additions and 588 deletions
config/routers/capital.ts
... ... @@ -12,7 +12,7 @@ export default [
12 12 component: './capital/SupplySetting'
13 13 },
14 14 {
15   - path: '/ams/standardMange', // 编辑管理
  15 + path: '/ams/setting/standardMange', // 编辑管理
16 16 component: './capital/StandardMange'
17 17 },
18 18 {
... ... @@ -24,7 +24,7 @@ export default [
24 24 component: './capital/SpecConfig'
25 25 },
26 26 {
27   - path: '/ams/standard/name', // 资产分类标准
  27 + path: '/ams/setting/standard/name', // 资产分类标准
28 28 component: './capital/StandardName'
29 29 },
30 30 {
... ...
config/routers/cas.ts
... ... @@ -45,6 +45,10 @@ export default [
45 45 path: '/cas/baseConfig/workTimeDuration', // 下班可延时时长
46 46 component: './cas/baseConfig/WorkTimeDuration',
47 47 },
  48 + {
  49 + path: '/cas/baseConfig/ShopRelateBizConfig', // 门店业务关联配置
  50 + component: './cas/baseConfig/ShopRelateBizConfig',
  51 + },
48 52  
49 53 // 毛利目标设置
50 54 {
... ... @@ -311,10 +315,7 @@ export default [
311 315 path: '/cas/cassetting/manHoursDiscountConfig/create/:id/:brandId?', //工时减免规则配置
312 316 component: './cas/afterSaleConfiguration/manHoursDiscountConfig/subpages/ConfigCreate',
313 317 },
314   - {
315   - path: '/cas/manhoursProportionConfig', // 机修组工时分成比例配置
316   - component: './cas/afterSaleConfiguration/manhoursProportionConfig',
317   - },
  318 +
318 319 // {
319 320 // path: '/cas/part/plantype', // 备件计划类型
320 321 // component: './cas/spareParts/PlanType'
... ... @@ -388,31 +389,31 @@ export default [
388 389 },
389 390 {
390 391 //终身质保卡设置
391   - path: '/cas/WarrantyCard/Setting', // 终身质保卡设置
  392 + path: '/cas/promotionConfig/WarrantyCard/Setting', // 终身质保卡设置
392 393 component: './cas/WarrantyCardSetting',
393 394 },
394 395 {
395   - path: '/cas/WarrantyCard/Detail/:brandId/:warrantyId?/:isCopy?', //新增、编辑、查看
  396 + path: '/cas/promotionConfig/WarrantyCard/Detail/:brandId/:warrantyId?/:isCopy?', //新增、编辑、查看
396 397 component: './cas/WarrantyCardCreate',
397 398 },
398 399 {
399   - path: '/cas/WarrantyCard/UseLog', //使用记录
  400 + path: '/cas/promotionConfig/WarrantyCard/UseLog', //使用记录
400 401 component: './cas/WarrantyCardUseLog',
401 402 },
402 403 {
403   - path: '/cas/MaintenancePackageCard/PurchaseRecord', //保养套餐卡->购买记录
  404 + path: '/cas/promotionConfig/MaintenancePackageCard/PurchaseRecord', //保养套餐卡->购买记录
404 405 component: './cas/MaintenanceCard/purchaseRecord',
405 406 },
406 407 {
407   - path: '/cas/MaintenancePackageCard/list', //保养套餐卡->列表
  408 + path: '/cas/promotionConfig/MaintenancePackageCard/list', //保养套餐卡->列表
408 409 component: './cas/MaintenanceCard/MPList',
409 410 },
410 411 {
411   - path: '/cas/MaintenancePackageCard/list/upsert/:brandId/:maintainId?/:isCopy?', //保养套餐卡->新建编辑
  412 + path: '/cas/promotionConfig/MaintenancePackageCard/list/upsert/:brandId/:maintainId?/:isCopy?', //保养套餐卡->新建编辑
412 413 component: './cas/MaintenanceCard/Upsert',
413 414 },
414 415 {
415   - path: '/cas/MaintenancePackageCard/list/oil/:brandId/:maintainId?/:isCopy?', //保养套餐卡->新建编辑机油
  416 + path: '/cas/promotionConfig/MaintenancePackageCard/list/oil/:brandId/:maintainId?/:isCopy?', //保养套餐卡->新建编辑机油
416 417 component: './cas/MaintenanceCard/Oil',
417 418 },
418 419 /**
... ... @@ -444,14 +445,14 @@ export default [
444 445 * 市场行动
445 446 */
446 447 {
447   - path: '/cas/marketAction',
  448 + path: '/cas/promotionConfig/marketAction',
448 449 component: './cas/MarketAction/index',
449 450 },
450 451 /**
451 452 * 市场行动 => 详情
452 453 */
453 454 {
454   - path: '/cas/marketAction/edit/:id?',
  455 + path: '/cas/promotionConfig/marketAction/edit/:id?',
455 456 component: './cas/MarketAction/EditComfirm/index',
456 457 },
457 458  
... ... @@ -493,18 +494,25 @@ export default [
493 494 * 客户类型结算
494 495 */
495 496 {
496   - path: '/cas/CustomerType/CustomerTypePay',
  497 + path: '/cas/ManageConfig/CustomerTypePay',
497 498 component: './cas/CustomerTypePay',
498 499 },
499 500 /**
500 501 * 客户白名单
501 502 */
502 503 {
503   - path: '/cas/CustomerType/CustomerTypeWhiteList',
  504 + path: '/cas/ManageConfig/CustomerTypeWhiteList',
504 505 component: './cas/CustomerTypeWhiteList',
505 506 },
506 507 {
507   - path: '/cas/CustomerType/CustomerTypeWhiteApplyList/:type', //积分商城->商品管理->编辑、新增
  508 + path: '/cas/ManageConfig/CustomerTypeWhiteApplyList/:type', //积分商城->商品管理->编辑、新增
508 509 component: './cas/CustomerTypeWhiteList/subpages/ApplyList',
509 510 },
  511 + /**
  512 + * 机修组工时分成比例配置
  513 + */
  514 + {
  515 + path: '/cas/ManageConfig/manhoursProportionConfig',
  516 + component: './cas/afterSaleConfiguration/manhoursProportionConfig',
  517 + },
510 518 ];
... ...
config/routers/crm_new.ts
... ... @@ -74,7 +74,7 @@ export default [
74 74 component: './crm_new/OnlineImport',
75 75 },
76 76 {
77   - path: '/crm/threePartyPlatformClue', // 三方平台线索配置
  77 + path: '/crm/goalSetting/threePartyPlatformClue', // 三方平台线索配置
78 78 component: './crm_new/ThreePartyPlatformClue',
79 79 },
80 80 {
... ...
config/routers/decoration.ts
... ... @@ -16,10 +16,7 @@ export default [
16 16 path: '/decoration/decorationGoods/deoGoodsPool', // 装潢商品池
17 17 component: './decoration/deco/DeoGoodsPool',
18 18 },
19   - {
20   - path: '/decoration/retailPriceCoefficient', // 装潢零售价格系数
21   - component: './pms/part/DecoPriceCoefficient',
22   - },
  19 +
23 20 {
24 21 path: '/decoration/permissiondiscounts', // 装潢权限优惠设置
25 22 component: './decoration/deco/PermissionDiscounts',
... ... @@ -28,18 +25,7 @@ export default [
28 25 path: '/decoration/workKnowledgeBase', // 装潢作业知识库
29 26 component: './decoration/deco/WorkKnowledgeBase',
30 27 },
31   - {
32   - path: '/decoration/decorationGoods/decorationPromotion/sPPManage', // 特价
33   - component: './decoration/deco/DecorationPromotion/SPPManage',
34   - },
35   - {
36   - path: '/decoration/decorationGoods/decorationPromotion/decorationPackage', // 满送
37   - component: './decoration/deco/DecorationPromotion/DecorationPackage',
38   - },
39   - {
40   - path: '/decoration/decorationGoods/decorationPromotion/decorateFullFree', // 套餐
41   - component: './decoration/deco/DecorationPromotion/DecorateFullFree',
42   - },
  28 +
43 29  
44 30 //商品管理 ===> 配件零售
45 31 {
... ... @@ -78,4 +64,26 @@ export default [
78 64 path: '/decoration/partsGoods/decorationPromotion/decorateFullFree', // 套餐
79 65 component: './decoration/parts/DecorationPromotion/DecorateFullFree',
80 66 },
  67 + //促销设置
  68 + {
  69 + path: '/decoration/promotionsettings/deoGoodsManagement', // 装潢商品管理
  70 + component: './decoration/deco/DeoGoodsManagement',
  71 + },
  72 + {
  73 + path: '/decoration/promotionsettings/sPPManage', // 特价
  74 + component: './decoration/deco/DecorationPromotion/SPPManage',
  75 + },
  76 + {
  77 + path: '/decoration/promotionsettings/decorationPackage', // 满送
  78 + component: './decoration/deco/DecorationPromotion/DecorationPackage',
  79 + },
  80 + {
  81 + path: '/decoration/promotionsettings/decorateFullFree', // 套餐
  82 + component: './decoration/deco/DecorationPromotion/DecorateFullFree',
  83 + },
  84 + //管控
  85 + {
  86 + path: '/decoration/controlsettings/retailPriceCoefficient', // 装潢零售价格系数
  87 + component: './pms/part/DecoPriceCoefficient',
  88 + },
81 89 ];
82 90 \ No newline at end of file
... ...
config/routers/fvm.ts
... ... @@ -78,7 +78,7 @@ export default [
78 78 },
79 79 /**不启票计划提醒 */
80 80 {
81   - path: '/fvm/plan/noticket',
  81 + path: '/fvm/control/noticket',
82 82 component: './stock/Plan/NoticketConfig',
83 83 },
84 84 /** 提前输机 */
... ... @@ -100,7 +100,7 @@ export default [
100 100 /** *******系统设置****** */
101 101  
102 102 {
103   - path: '/fvm/systems/ticket/price', // 启票价百分比调整设置
  103 + path: '/fvm/control/ticket/price', // 启票价百分比调整设置
104 104 component: './stock/Systems/TicketPercentSetting',
105 105 },
106 106 {
... ... @@ -160,7 +160,7 @@ export default [
160 160 component: './stock/Systems/ConcessionConfig',
161 161 },
162 162 {
163   - path: '/fvm/addprice', // 车辆加价设置
  163 + path: '/fvm/promotion/addprice', // 车辆加价设置
164 164 component: './stock/CarAddPrice',
165 165 },
166 166 {
... ... @@ -176,7 +176,7 @@ export default [
176 176 component: './stock/Systems/TicketIncreaseToBeDone',
177 177 },
178 178 {
179   - path: '/fvm/systems/invoice/whitelist', // 开票管控白名单
  179 + path: '/fvm/control/invoice/whitelist', // 开票管控白名单
180 180 component: './stock/Systems/Invoice/WhiteList',
181 181 },
182 182  
... ... @@ -194,7 +194,7 @@ export default [
194 194 component: './stock/StoreHouse/ShopStorage',
195 195 },
196 196 {
197   - path: '/fvm/storehouse/regionalQuery', // 区域库查询授权
  197 + path: '/fvm/control/regionalQuery', // 区域库查询授权
198 198 component: './stock/StoreHouse/RegionalQueryAuth',
199 199 },
200 200 {
... ... @@ -232,7 +232,7 @@ export default [
232 232 },
233 233 /**车辆上架管理 */
234 234 {
235   - path: '/fvm/shop/product/onsale',
  235 + path: '/fvm/promotion/onsale',
236 236 component: './stock/ProductSetting',
237 237 },
238 238 /**门店维度上架 */
... ... @@ -324,15 +324,15 @@ export default [
324 324  
325 325 /**厂家补贴 */
326 326 {
327   - path: '/fvm/subsidy/replace', // 置换补贴
  327 + path: '/fvm/promotion/subsidy/replace', // 置换补贴
328 328 component: './stock/ManufacturerSubsidies/Replace',
329 329 },
330 330 {
331   - path: 'fvm/subsidy/keyAccount', // 大客户补贴
  331 + path: 'fvm/promotion/subsidy/keyAccount', // 大客户补贴
332 332 component: './stock/ManufacturerSubsidies/KeyAccount',
333 333 },
334 334 {
335   - path: 'fvm/subsidy/addPurchase', // 增购补贴
  335 + path: 'fvm/promotion/subsidy/addPurchase', // 增购补贴
336 336 component: './stock/ManufacturerSubsidies/AddPurchase',
337 337 },
338 338 {
... ... @@ -394,7 +394,7 @@ export default [
394 394 },
395 395 // 加装车配置
396 396 {
397   - path: '/fvm/vehicle/additional',
  397 + path: '/fvm/promotion/vehicle/additional',
398 398 component: './stock/VehicleAdditional',
399 399 },
400 400 ];
... ...
config/routers/mkt.ts
1 1 /**营销活动 */
2 2 export default [
3 3 {
4   - path: '/mkt/manage',
  4 + path: '/mkt/control/manage',
5 5 component: './mkt/ActivityManage',
6 6 },
7 7 {
... ... @@ -10,7 +10,7 @@ export default [
10 10 },
11 11 /**评价有礼配置 */
12 12 {
13   - path: '/mkt/evaluate/gifts',
  13 + path: '/mkt/control/evaluate/gifts',
14 14 component: './mkt/EvaluativeGifts',
15 15 },
16 16 /**活动中奖概况运维 */
... ... @@ -39,15 +39,15 @@ export default [
39 39 component: './mkt/PromotionGoal',
40 40 },
41 41 {
42   - path: '/mkt/article', // 文章库
  42 + path: '/mkt/control/article', // 文章库
43 43 component: './mkt/articleList',
44 44 },
45 45 {
46   - path: '/mkt/original/article', // 原创文章
  46 + path: '/mkt/control/original/article', // 原创文章
47 47 component: './mkt/articleList',
48 48 },
49 49 {
50   - path: '/mkt/poster', //海报库列表
  50 + path: '/mkt/control/poster', //海报库列表
51 51 component: './mkt/posterList',
52 52 },
53 53 {
... ... @@ -55,15 +55,15 @@ export default [
55 55 component: './mkt/posterCreate',
56 56 },
57 57 {
58   - path: '/mkt/video', // 视频库
  58 + path: '/mkt/control/video', // 视频库
59 59 component: './mkt/videoLibrary'
60 60 },
61 61 {
62   - path: '/mkt/questions', // 问答项
  62 + path: '/mkt/control/questions', // 问答项
63 63 component: './mkt/questions'
64 64 },
65 65 {
66   - path: '/mkt/share/resources', // 文案标准库
  66 + path: '/mkt/control/share/resources', // 文案标准库
67 67 component: './mkt/ShareResources'
68 68 },
69 69 ];
70 70 \ No newline at end of file
... ...
config/routers/order3.ts
... ... @@ -43,7 +43,7 @@ export default [
43 43 },
44 44 {
45 45 //零售任务分配
46   - path: '/order3/saleTask',
  46 + path: '/order3/goalSetting/saleTask',
47 47 component: './order3/SaleTask',
48 48 },
49 49 {
... ... @@ -77,12 +77,12 @@ export default [
77 77 },
78 78 {
79 79 //零售任务设置
80   - path: '/order3/OrderRetailSetting',
  80 + path: '/order3/goalSetting/orderRetailSetting',
81 81 component: './order3/OrderRetailSetting',
82 82 },
83 83 {
84 84 //大客户单位设置
85   - path: '/order3/largeBusSetting',
  85 + path: '/order3/promotionSettings/largeBusSetting',
86 86 component: './order3/LargeBusSetting',
87 87 },
88 88 {
... ... @@ -112,7 +112,7 @@ export default [
112 112 },
113 113 {
114 114 //权限优惠设置
115   - path: '/order3/orderSetting/orderPermissionDiscount',
  115 + path: '/order3/promotionSettings/orderPermissionDiscount',
116 116 component: './order3/OrderSetting/OrderPermissionDiscount',
117 117 },
118 118 {
... ... @@ -132,7 +132,7 @@ export default [
132 132 },
133 133 {
134 134 //特价车补贴配置
135   - path: '/order3/orderSetting/specialCarSales',
  135 + path: '/order3/promotionSettings/specialCarSales',
136 136 component: './order3/SpecialCarSales',
137 137 },
138 138 {
... ... @@ -157,27 +157,27 @@ export default [
157 157 },
158 158 {
159 159 //每日送优惠
160   - path: '/order3/dailyGivePreferential',
  160 + path: '/order3/promotionSettings/dailyGivePreferential',
161 161 component: './order3/DailyGivePreferential',
162 162 },
163 163 {
164 164 //买车即送
165   - path: '/order3/buyCarGift',
  165 + path: '/order3/promotionSettings/buyCarGift',
166 166 component: './order3/BuyCarGift',
167 167 },
168 168 {
169 169 // 置换补贴
170   - path: '/order3/carPurchaseSubsidy/replacementSubsidy',
  170 + path: '/order3/promotionSettings/replacementSubsidy',
171 171 component: './order3/CarPurchaseSubsidy/ReplacementSubsidy',
172 172 },
173 173 {
174 174 // 大客户补贴
175   - path: '/order3/carPurchaseSubsidy/keyCustomerSubsidy',
  175 + path: '/order3/promotionSettings/keyCustomerSubsidy',
176 176 component: './order3/CarPurchaseSubsidy/KeyCustomerSubsidy',
177 177 },
178 178 {
179 179 // 增购补贴
180   - path: '/order3/carPurchaseSubsidy/additionalSubsidy',
  180 + path: '/order3/promotionSettings/additionalSubsidy',
181 181 component: './order3/CarPurchaseSubsidy/AdditionalPurchaseSubsidy',
182 182 },
183 183 {
... ... @@ -202,12 +202,12 @@ export default [
202 202 },
203 203 {
204 204 // 零售线索占比配置
205   - path: '/order3/retailTaskConfiguration',
  205 + path: '/order3/goalSetting/retailTaskConfiguration',
206 206 component: './order3/RetailTaskConfiguration',
207 207 },
208 208 {
209 209 // 附加值任务配置
210   - path: '/order3/addValueTaskConfig',
  210 + path: '/order3/goalSetting/addValueTaskConfig',
211 211 component: './order3/AddValueTaskConfig',
212 212 },
213 213 {
... ... @@ -257,7 +257,7 @@ export default [
257 257 },
258 258 {
259 259 //零售任务白名单设置
260   - path: '/order3/retailTaskWhitelist',
  260 + path: '/order3/goalSetting/retailTaskWhitelist',
261 261 component: './order3/RetailTaskWhitelist',
262 262 },
263 263 {
... ... @@ -277,7 +277,7 @@ export default [
277 277 },
278 278 {
279 279 //交付中心目标
280   - path: '/order3/deliverCentralGoals',
  280 + path: '/order3/goalSetting/deliverCentralGoals',
281 281 component: './order3/DeliverCentralGoals',
282 282 },
283 283 {
... ... @@ -317,7 +317,7 @@ export default [
317 317 },
318 318 {
319 319 // 直营策车厂家促销设置
320   - path: '/order3/directCarPromotion',
  320 + path: '/order3/promotionSettings/directCarPromotion',
321 321 component: './order3/DirectCarPromotion',
322 322 },
323 323 ];
... ...
config/routers/pms.ts
  1 +/*
  2 + * @Author: jiangwei jiangwei.feewee.cn
  3 + * @Date: 2024-04-03 17:42:01
  4 + * @LastEditors: jiangwei jiangwei.feewee.cn
  5 + * @LastEditTime: 2024-04-07 10:07:02
  6 + * @FilePath: /fw-cms/config/routers/pms.ts
  7 + * @Description:
  8 + *
  9 + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
  10 + */
1 11 export default [
2 12 {
3 13 path: '/pms/part/repertory', //备件库标准管理
... ... @@ -7,10 +17,7 @@ export default [
7 17 path: '/pms/part/repertoryCreate/:partNo', // 编辑、新增备件标准
8 18 component: './pms/part/RepertoryCreate',
9 19 },
10   - {
11   - path: '/pms/part/partPriceCoefficient', // 配件价格系数配置
12   - component: './pms/part/PartPriceCoefficient',
13   - },
  20 +
14 21 {
15 22 path: '/pms/part/decoPriceCoefficient', // 装潢件价格系数配置
16 23 component: './pms/part/DecoPriceCoefficient',
... ... @@ -39,18 +46,12 @@ export default [
39 46 path: '/pms/part/settlementSetting', // 结算系数设置
40 47 component: './pms/part/SettlementSetting',
41 48 },
42   - {
43   - path: '/pms/partPlan/factoryTask', // 月度任务
44   - component: './pms/partPlan/FactoryTask',
45   - },
  49 +
46 50 {
47 51 path: '/pms/storage/storageManage', // 仓储管理 -> 仓库管理
48 52 component: './pms/storage/StorageManage',
49 53 },
50   - {
51   - path: '/pms/storage/locationManage', // 仓储管理 -> 库位管理
52   - component: './pms/storage/LocationManage',
53   - },
  54 +
54 55 {
55 56 path: '/pms/storage/partShop', // 服务站配件
56 57 component: './pms/storage/partShop',
... ... @@ -87,10 +88,7 @@ export default [
87 88 path: '/pms/partPlan/shipmentfw', // 配件发运单(霏微运维用)
88 89 component: './pms/partPlan/PlanShipping',
89 90 },
90   - {
91   - path: '/pms/partPlan/planSupplier', // 采购供应商
92   - component: './pms/partPlan/PlanSupplier',
93   - },
  91 +
94 92 {
95 93 path: '/pms/partPlan/minRatioPlan', // 最低库销比计划
96 94 component: './pms/partPlan/MinRatioPlan',
... ... @@ -155,10 +153,7 @@ export default [
155 153 path: '/pms/part/priceSettingTodo',
156 154 component: './pms/part/PriceSettingTodo',
157 155 },
158   - {
159   - path: '/pms/part/pickUpAddress', // 提货地址设置
160   - component: './pms/part/PickUpAddress',
161   - },
  156 +
162 157 {
163 158 path: '/pms/part/partSplit', // 配件拆分设置
164 159 component: './pms/part/PartSplit',
... ... @@ -255,4 +250,27 @@ export default [
255 250 path: '/pms/setting/minratiowhitelist', // 不纳入库销比计算白名单
256 251 component: './pms/setting/MinRatiowhitelist',
257 252 },
  253 +
  254 + // 管控设置---配件零售价格
  255 + {
  256 + path: '/pms/controlsettings/partPriceCoefficient', // 配件价格系数配置
  257 + component: './pms/part/PartPriceCoefficient',
  258 + },
  259 + {
  260 + path: '/pms/controlsettings/pickUpAddress', // 提货地址设置
  261 + component: './pms/part/PickUpAddress',
  262 + },
  263 + {
  264 + path: '/pms/controlsettings/planSupplier', // 采购供应商
  265 + component: './pms/partPlan/PlanSupplier',
  266 + },
  267 + {
  268 + path: '/pms/controlsettings/locationManage', // 仓储管理 -> 库位管理
  269 + component: './pms/storage/LocationManage',
  270 + },
  271 + //目标设置
  272 + {
  273 + path: '/pms/targetsetting/factoryTask', // 月度任务
  274 + component: './pms/partPlan/FactoryTask',
  275 + },
258 276 ];
... ...
src/components/SelectorWithFull/MultipleSelector.tsx
... ... @@ -99,7 +99,7 @@ export default function MultipleSelector<V = any, T = Record<string, string | nu
99 99 return (
100 100 <div className={classNames(st.wrapper, className)}>
101 101 <TreeSelect {...other} multiple {...tProps} />
102   - {treeData.length > 1 ? (
  102 + {treeData.length > 1 && !other?.disabled ? (
103 103 <Checkbox className={st.cb} checked={isAllSelect()} onChange={onAllSelect}>
104 104 全选
105 105 </Checkbox>
... ...
src/pages/admin/employee/api.ts
... ... @@ -81,8 +81,8 @@ export function roleRemoveApi(id: string | number) {
81 81 }
82 82  
83 83 // 商家门店树
84   -export function getShopTreeApi(): http.PromiseResp<UserRole.ShopTreeOption[]> {
85   - return request.get(`${host.oop}/select/dealers/shops`);
  84 +export function getShopTreeApi(params: { showAll: boolean }): http.PromiseResp<UserRole.ShopTreeOption[]> {
  85 + return request.get(`${host.oop}/select/dealers/shops`, { params });
86 86 }
87 87  
88 88 //保存用户角色
... ...
src/pages/admin/employee/components/AddRoleModal.tsx
... ... @@ -89,7 +89,7 @@ export default function AddRoleModal({ visible, _onCancel, record = {}, refreshi
89 89  
90 90 function fetchRangeData() {
91 91 setTreeLoading(true);
92   - getShopTreeApi()
  92 + getShopTreeApi({ showAll: true })
93 93 .then((res) => {
94 94 const { data = [] } = res;
95 95 setAllRangeList(data.filter((i) => (i?.children?.length ?? 0) > 0));
... ... @@ -110,34 +110,34 @@ export default function AddRoleModal({ visible, _onCancel, record = {}, refreshi
110 110 selectable: false,
111 111 children: _.compact(
112 112 item.children &&
113   - item.children.map((i) => {
114   - // 0为所有业态
115   - if (
116   - currentRole &&
117   - currentRole.authRange
118   - ?.split(',')
119   - .map((v) => Number(v))
120   - .includes(0)
121   - ) {
122   - return {
123   - title: i.label,
124   - value: i.value,
125   - key: i.value,
126   - bizType: i.bizType,
127   - isLeaf: true,
128   - };
129   - }
130   - if ((currentRole ? currentRole.authRange || '' : '').split(',').includes(String(i.bizType))) {
131   - return {
132   - title: i.label,
133   - value: i.value,
134   - key: i.value,
135   - bizType: i.bizType,
136   - isLeaf: true,
137   - };
138   - }
139   - return null;
140   - }),
  113 + item.children.map((i) => {
  114 + // 0为所有业态
  115 + if (
  116 + currentRole &&
  117 + currentRole.authRange
  118 + ?.split(',')
  119 + .map((v) => Number(v))
  120 + .includes(0)
  121 + ) {
  122 + return {
  123 + title: i.label,
  124 + value: i.value,
  125 + key: i.value,
  126 + bizType: i.bizType,
  127 + isLeaf: true,
  128 + };
  129 + }
  130 + if ((currentRole ? currentRole.authRange || '' : '').split(',').includes(String(i.bizType))) {
  131 + return {
  132 + title: i.label,
  133 + value: i.value,
  134 + key: i.value,
  135 + bizType: i.bizType,
  136 + isLeaf: true,
  137 + };
  138 + }
  139 + return null;
  140 + }),
141 141 ),
142 142 }));
143 143  
... ...
src/pages/approval/ApprovalSetting/subpages/components/DefaultFlowNewOrEdit.tsx
... ... @@ -24,6 +24,7 @@ import { Condition_Type_Enum as TriggerType } from &#39;./PreSettingForm/entity&#39;;
24 24 import { geneRandomNum } from '@/utils/tools';
25 25 import CommonSettingForm from './CommonSettingForm';
26 26 import ShopSelectByBizType from '@/pages/approval/components/ShopSelectByBizType';
  27 +import type { LabeledValue } from 'antd/lib/select';
27 28  
28 29 const { Option } = Select;
29 30 const FormItem = Form.Item;
... ... @@ -80,11 +81,11 @@ export default function DefaultSettingNewOrEdit(props: Props) {
80 81 }
81 82 });
82 83 const newCondVals = (data?.conditionValues ?? []).concat(essVals);
83   - // idOrCode to idOrCode--bizType
  84 + // idOrCode to idOrCode__bizType
84 85 newCondVals.forEach((n) => {
85 86 if (n.flowTriggerDto.type === TriggerType.门店) {
86 87 const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({
87   - idOrCode: `${i.idOrCode}--${i.bizType}`,
  88 + idOrCode: `${i.idOrCode}__${i.bizType}`,
88 89 name: i.name,
89 90 bizType: i.bizType,
90 91 }));
... ... @@ -157,11 +158,11 @@ export default function DefaultSettingNewOrEdit(props: Props) {
157 158 message.error('请填写全部触发条件的对应值');
158 159 return;
159 160 }
160   - // idOrCode--bizType to idOrCode
  161 + // idOrCode__bizType to idOrCode
161 162 conditionVals.forEach((n) => {
162 163 if (n.flowTriggerDto.type === TriggerType.门店) {
163 164 const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({
164   - idOrCode: i.idOrCode.split('--')[0]!,
  165 + idOrCode: i.idOrCode.split('__')[0]!,
165 166 name: i.name,
166 167 bizType: i.bizType,
167 168 }));
... ... @@ -201,12 +202,12 @@ export default function DefaultSettingNewOrEdit(props: Props) {
201 202 const onConditionChange = (item: ApprovalSetting.ConditionVal, values: any, index: number) => {
202 203 const { value, flowTriggerDto } = item;
203 204  
204   - // idOrCode--bizType
  205 + // idOrCode__bizType
205 206 let newValue;
206 207 if (flowTriggerDto.type === TriggerType.门店) {
207 208 newValue = Array.isArray(values)
208 209 ? values.map((i) => {
209   - const currBizType = i.value.split('--')[1]!;
  210 + const currBizType = i.value.split('__')[1]!;
210 211 return { idOrCode: i.value, name: i.label, bizType: Number(currBizType) };
211 212 })
212 213 : values;
... ... @@ -286,6 +287,19 @@ export default function DefaultSettingNewOrEdit(props: Props) {
286 287  
287 288 const _maxRule = originalData && typeof originalData.max === 'number' ? originalData.max : Infinity;
288 289 const _minRule = originalData && typeof originalData.min === 'number' ? originalData.min : -Infinity;
  290 +
  291 + let initType = 1;
  292 + if (type === TriggerType['门店']) {
  293 + const newOriginalData: LabeledValue[] =
  294 + originalData.length > 0
  295 + ? originalData.map((i: any) => ({
  296 + value: i.idOrCode,
  297 + label: i.name,
  298 + }))
  299 + : [];
  300 + const isTypeAll = newOriginalData.length === 1 && newOriginalData[0].value === '-1__-1'; // 是全部门店
  301 + initType = isTypeAll ? -1 : 1;
  302 + }
289 303 return (
290 304 <FormItem key={id} label={`${index + 1}、${name || ''}(${TriggerAll[judgeRule]})`} style={{ marginBottom: 20 }}>
291 305 {judgeRule === 1 ? (
... ... @@ -337,7 +351,7 @@ export default function DefaultSettingNewOrEdit(props: Props) {
337 351 <ShopSelectByBizType
338 352 labelInValue
339 353 multiple
340   - initType={1}
  354 + initType={initType}
341 355 value={
342 356 originalData.length > 0
343 357 ? originalData.map((i: any) => ({
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/AbilitySelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getAbilityPage } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const AbilitySelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getAbilityPage, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const AbilitySelector = ({ visible, index, item, readOnly, onChange }: Pr
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/AccountSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import usePagination from '@/hooks/usePagination';
4 4 import { getAccountApi } from '@/pages/approval/FlowSetting/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const AccountSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { list, setParams } = usePagination(getAccountApi, {}, { delay });
... ... @@ -31,9 +33,33 @@ export const AccountSelector = ({ visible, index, item, readOnly, onChange }: Pr
31 33 }
32 34 }, [visible]);
33 35  
  36 + const getFilteredData = () => {
  37 + const oriOptions = list.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  38 + if (searchValue.trim() === '') {
  39 + return oriOptions;
  40 + }
  41 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  42 + };
  43 +
  44 + const handleSelect = (_: LabeledValue, option: any) => {
  45 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  46 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  47 + oriNames.push(option.label);
  48 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  49 + const filteredData = getFilteredData();
  50 + if (valueMatchArr.length === filteredData.length) {
  51 + setSearchValue('');
  52 + }
  53 + };
  54 +
34 55 return (
35 56 <SelectorWithFull
36 57 showSearch
  58 + searchValue={searchValue}
  59 + onSearch={(value) => {
  60 + setSearchValue(value);
  61 + }}
  62 + onSelect={handleSelect}
37 63 treeNodeFilterProp="label"
38 64 maxTagCount={100}
39 65 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/BacklogSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getBacklogList } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const BacklogSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getBacklogList, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const BacklogSelector = ({ visible, index, item, readOnly, onChange }: Pr
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.itemCode, value: item.itemCode, label: item.itemName }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/BizTypeSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import useInitial from '@/hooks/useInitail';
4 4 import { queryAllBizType } from '@/common/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const BizTypeSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(queryAllBizType, [], undefined, delay);
... ... @@ -26,9 +28,33 @@ export const BizTypeSelector = ({ visible, index, item, readOnly, onChange }: Pr
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.value, value: item.value, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/BrandSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import useInitial from '@/hooks/useInitail';
4 4 import { getBrandFilterApi } from '@/common/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const BrandSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getBrandFilterApi, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const BrandSelector = ({ visible, index, item, readOnly, onChange }: Prop
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/ContractTypeSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import usePagination from '@/hooks/usePagination';
4 4 import { getContractTypes } from '../../../api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const ContractTypeSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { list, setParams } = usePagination(getContractTypes, {}, { delay });
... ... @@ -26,9 +28,33 @@ export const ContractTypeSelector = ({ visible, index, item, readOnly, onChange
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = list.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/FittingsSelector.tsx
... ... @@ -2,6 +2,8 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getShopListApi } from '@/components/ShopSelectNew/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
  6 +
5 7 interface Props {
6 8 visible: boolean;
7 9 index: number;
... ... @@ -14,6 +16,7 @@ interface Props {
14 16 export const FittingsSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
15 17 const { value } = item;
16 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
17 20  
18 21 const [delay, setDelay] = useState(true);
19 22 const { data: list, setParams } = useInitial(getShopListApi, [], { type: 1, bizTypes: '6' }, delay);
... ... @@ -31,9 +34,33 @@ export const FittingsSelector = ({ visible, index, item, readOnly, onChange }: P
31 34 }
32 35 }, [visible]);
33 36  
  37 + const getFilteredData = () => {
  38 + const oriOptions = list.map((item) => ({ key: item.shopId, value: item.shopId, label: item.shopShortName }));
  39 + if (searchValue.trim() === '') {
  40 + return oriOptions;
  41 + }
  42 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  43 + };
  44 +
  45 + const handleSelect = (_: LabeledValue, option: any) => {
  46 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  47 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  48 + oriNames.push(option.label);
  49 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  50 + const filteredData = getFilteredData();
  51 + if (valueMatchArr.length === filteredData.length) {
  52 + setSearchValue('');
  53 + }
  54 + };
  55 +
34 56 return (
35 57 <SelectorWithFull
36 58 showSearch
  59 + searchValue={searchValue}
  60 + onSearch={(value) => {
  61 + setSearchValue(value);
  62 + }}
  63 + onSelect={handleSelect}
37 64 treeNodeFilterProp="label"
38 65 maxTagCount={100}
39 66 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/FoundSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getFoundPage } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const FoundSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getFoundPage, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const FoundSelector = ({ visible, index, item, readOnly, onChange }: Prop
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.value, value: item.value, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/IndicatorSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getIndicatorList } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const IndicatorSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getIndicatorList, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const IndicatorSelector = ({ visible, index, item, readOnly, onChange }:
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.code, value: item.code, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/OfficeWordTypeSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import useInitial from '@/hooks/useInitail';
4 4 import { getOfficeWordTypes } from '../../../api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const OfficeWordTypeSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getOfficeWordTypes, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const OfficeWordTypeSelector = ({ visible, index, item, readOnly, onChang
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/PostSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import usePagination from '@/hooks/usePagination';
4 4 import { getPost } from '@/pages/approval/FlowSetting/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const PostSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { list, setParams } = usePagination(getPost, {}, { delay });
... ... @@ -32,9 +34,33 @@ export const PostSelector = ({ visible, index, item, readOnly, onChange }: Props
32 34 }
33 35 }, [visible]);
34 36  
  37 + const getFilteredData = () => {
  38 + const oriOptions = list.map((item) => ({ key: item.id, value: item.id, label: item.postName }));
  39 + if (searchValue.trim() === '') {
  40 + return oriOptions;
  41 + }
  42 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  43 + };
  44 +
  45 + const handleSelect = (_: LabeledValue, option: any) => {
  46 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  47 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  48 + oriNames.push(option.label);
  49 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  50 + const filteredData = getFilteredData();
  51 + if (valueMatchArr.length === filteredData.length) {
  52 + setSearchValue('');
  53 + }
  54 + };
  55 +
35 56 return (
36 57 <SelectorWithFull
37 58 showSearch
  59 + searchValue={searchValue}
  60 + onSearch={(value) => {
  61 + setSearchValue(value);
  62 + }}
  63 + onSelect={handleSelect}
38 64 treeNodeFilterProp="label"
39 65 maxTagCount={100}
40 66 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/PostTypeSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getPostTypeList } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const PostTypeSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getPostTypeList, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const PostTypeSelector = ({ visible, index, item, readOnly, onChange }: P
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.type, value: item.type, label: item.typeName }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/RPTypesSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import useInitial from '@/hooks/useInitail';
4 4 import { getRPTypes } from '@/common/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 configType: number;
... ... @@ -16,6 +17,7 @@ interface Props {
16 17 export const RPTypesSelector = ({ configType, visible, index, item, readOnly, onChange }: Props) => {
17 18 const { value } = item;
18 19 const originalData = JSON.parse(value || '{}');
  20 + const [searchValue, setSearchValue] = useState('');
19 21  
20 22 const [delay, setDelay] = useState(true);
21 23 // @ts-ignore
... ... @@ -28,9 +30,33 @@ export const RPTypesSelector = ({ configType, visible, index, item, readOnly, on
28 30 }
29 31 }, [visible]);
30 32  
  33 + const getFilteredData = () => {
  34 + const oriOptions = data.map((item) => ({ key: item.value, value: item.value, label: item.name }));
  35 + if (searchValue.trim() === '') {
  36 + return oriOptions;
  37 + }
  38 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  39 + };
  40 +
  41 + const handleSelect = (_: LabeledValue, option: any) => {
  42 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  43 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  44 + oriNames.push(option.label);
  45 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  46 + const filteredData = getFilteredData();
  47 + if (valueMatchArr.length === filteredData.length) {
  48 + setSearchValue('');
  49 + }
  50 + };
  51 +
31 52 return (
32 53 <SelectorWithFull
33 54 showSearch
  55 + searchValue={searchValue}
  56 + onSearch={(value) => {
  57 + setSearchValue(value);
  58 + }}
  59 + onSelect={handleSelect}
34 60 treeNodeFilterProp="label"
35 61 maxTagCount={100}
36 62 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/RoleSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import { getAllRoleCodeApi } from '@/common/api';
3 3 import useInitial from '@/hooks/useInitail';
4 4 import SelectorWithFull from '@/components/SelectorWithFull';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const RoleSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getAllRoleCodeApi, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const RoleSelector = ({ visible, index, item, readOnly, onChange }: Props
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.roleCode, value: item.roleCode, label: item.roleName }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/SealSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import usePagination from '@/hooks/usePagination';
4 4 import { getList } from '@/pages/contract/StampMatter/api';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const SealSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { list, setParams } = usePagination(getList, {}, { delay });
... ... @@ -26,9 +28,33 @@ export const SealSelector = ({ visible, index, item, readOnly, onChange }: Props
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = list.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label!.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/ShopBizTypeSelector.tsx
... ... @@ -11,7 +11,7 @@ interface Props {
11 11 onChange: (item: ApprovalSetting.ConditionVal, value: any, index: number) => void;
12 12 }
13 13  
14   -// 门店业态
  14 +// 门店业态--已废弃
15 15 export const ShopBizTypeSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 16 const { value } = item;
17 17 const originalData = JSON.parse(value || '{}');
... ...
src/pages/approval/ApprovalSetting/subpages/components/Selectors/StorageSelector.tsx
... ... @@ -2,6 +2,7 @@ import React, { useEffect, useState } from &#39;react&#39;;
2 2 import SelectorWithFull from '@/components/SelectorWithFull';
3 3 import { getStorageList } from '@/pages/approval/FlowSetting/api';
4 4 import useInitial from '@/hooks/useInitail';
  5 +import type { LabeledValue } from 'antd/lib/select';
5 6  
6 7 interface Props {
7 8 visible: boolean;
... ... @@ -15,6 +16,7 @@ interface Props {
15 16 export const StorageSelector = ({ visible, index, item, readOnly, onChange }: Props) => {
16 17 const { value } = item;
17 18 const originalData = JSON.parse(value || '{}');
  19 + const [searchValue, setSearchValue] = useState('');
18 20  
19 21 const [delay, setDelay] = useState(true);
20 22 const { data, setParams } = useInitial(getStorageList, [], {}, delay);
... ... @@ -26,9 +28,33 @@ export const StorageSelector = ({ visible, index, item, readOnly, onChange }: Pr
26 28 }
27 29 }, [visible]);
28 30  
  31 + const getFilteredData = () => {
  32 + const oriOptions = data.map((item) => ({ key: item.id, value: item.id, label: item.name }));
  33 + if (searchValue.trim() === '') {
  34 + return oriOptions;
  35 + }
  36 + return oriOptions.filter((i) => i.label.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  37 + };
  38 +
  39 + const handleSelect = (_: LabeledValue, option: any) => {
  40 + const oriNames = originalData.length > 0 ? originalData.map((i: any) => i.name) : [];
  41 + // originalData 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  42 + oriNames.push(option.label);
  43 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  44 + const filteredData = getFilteredData();
  45 + if (valueMatchArr.length === filteredData.length) {
  46 + setSearchValue('');
  47 + }
  48 + };
  49 +
29 50 return (
30 51 <SelectorWithFull
31 52 showSearch
  53 + searchValue={searchValue}
  54 + onSearch={(value) => {
  55 + setSearchValue(value);
  56 + }}
  57 + onSelect={handleSelect}
32 58 treeNodeFilterProp="label"
33 59 maxTagCount={100}
34 60 disabled={readOnly}
... ...
src/pages/approval/FlowSetting/subpages/ConditionSetting/components/CustomFlowNewOrEdit.tsx
... ... @@ -26,6 +26,7 @@ import usePagination from &#39;@/hooks/usePagination&#39;;
26 26 import { getPost } from '../../../api';
27 27 import PostsSelectorByAll from '../../../components/PostsSelectorByAll';
28 28 import ShopSelectByBizType from '@/pages/approval/components/ShopSelectByBizType';
  29 +import type { LabeledValue } from 'antd/lib/select';
29 30  
30 31 const { Option } = Select;
31 32 const FormItem = Form.Item;
... ... @@ -97,11 +98,11 @@ export default function CustomFlowNewOrEdit(props: Props) {
97 98 }
98 99 });
99 100 const newCondVals = (data?.conditionValues ?? []).concat(essVals);
100   - // idOrCode to idOrCode--bizType
  101 + // idOrCode to idOrCode__bizType
101 102 newCondVals.forEach((n) => {
102 103 if (n.flowTriggerDto.type === TriggerType.门店) {
103 104 const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({
104   - idOrCode: `${i.idOrCode}--${i.bizType}`,
  105 + idOrCode: `${i.idOrCode}__${i.bizType}`,
105 106 name: i.name,
106 107 bizType: i.bizType,
107 108 }));
... ... @@ -176,11 +177,11 @@ export default function CustomFlowNewOrEdit(props: Props) {
176 177 message.error('请填写全部触发条件的对应值');
177 178 return;
178 179 }
179   - // idOrCode--bizType to idOrCode
  180 + // idOrCode__bizType to idOrCode
180 181 conditionVals.forEach((n) => {
181 182 if (n.flowTriggerDto.type === TriggerType.门店) {
182 183 const value = JSON.parse(n.value).map((i: FlowSetting.CondValItem) => ({
183   - idOrCode: i.idOrCode.split('--')[0]!,
  184 + idOrCode: i.idOrCode.split('__')[0]!,
184 185 name: i.name,
185 186 bizType: i.bizType,
186 187 }));
... ... @@ -214,12 +215,12 @@ export default function CustomFlowNewOrEdit(props: Props) {
214 215 const onConditionChange = (item: FlowSetting.ConditionVal, values: any, index: number) => {
215 216 const { value, flowTriggerDto } = item;
216 217  
217   - // idOrCode--bizType
  218 + // idOrCode__bizType
218 219 let newValue;
219 220 if (flowTriggerDto.type === TriggerType.门店) {
220 221 newValue = Array.isArray(values)
221 222 ? values.map((i) => {
222   - const currBizType = i.value.split('--')[1]!;
  223 + const currBizType = i.value.split('__')[1]!;
223 224 return { idOrCode: i.value, name: i.label, bizType: Number(currBizType) };
224 225 })
225 226 : values;
... ... @@ -299,6 +300,19 @@ export default function CustomFlowNewOrEdit(props: Props) {
299 300  
300 301 const _maxRule = originalData && typeof originalData.max === 'number' ? originalData.max : Infinity;
301 302 const _minRule = originalData && typeof originalData.min === 'number' ? originalData.min : -Infinity;
  303 +
  304 + let initType = 1;
  305 + if (type === TriggerType['门店']) {
  306 + const newOriginalData: LabeledValue[] =
  307 + originalData.length > 0
  308 + ? originalData.map((i: any) => ({
  309 + value: i.idOrCode,
  310 + label: i.name,
  311 + }))
  312 + : [];
  313 + const isTypeAll = newOriginalData.length === 1 && newOriginalData[0].value === '-1__-1'; // 是全部门店
  314 + initType = isTypeAll ? -1 : 1;
  315 + }
302 316 return (
303 317 <FormItem key={id} label={`${index + 1}、${name || ''}(${TriggerAll[judgeRule]})`} style={{ marginBottom: 20 }}>
304 318 {judgeRule === 1 ? (
... ... @@ -350,7 +364,7 @@ export default function CustomFlowNewOrEdit(props: Props) {
350 364 <ShopSelectByBizType
351 365 labelInValue
352 366 multiple
353   - initType={1}
  367 + initType={initType}
354 368 value={
355 369 originalData.length > 0
356 370 ? originalData.map((i: any) => ({
... ...
src/pages/approval/components/ShopSelectByBizType/index.tsx
1 1 import type { Ref } from 'react';
2   -import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
3   -import { Checkbox, Radio, Row, Spin, TreeSelect } from 'antd';
  2 +import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react';
  3 +import { Radio, Row, Spin, TreeSelect } from 'antd';
4 4 import useInitail from '@/hooks/useInitail';
5 5 import type { ShopItem } from './api';
6 6 import { getShopListByBizTypeApi, getShopListByDealerApi } from './api';
7   -import { unique } from '@/utils/validate';
8   -import type { CheckboxChangeEvent } from 'antd/lib/checkbox';
9 7 import type { LabeledValue } from 'antd/lib/select';
  8 +import _ from 'lodash';
10 9  
11 10 const divId = `TreeSelect_ShopSelect_Div_${Date.now()}`; // 生成岗位div唯一key
12 11  
13 12 interface Props {
14   - value?: LabeledValue[]; // 人员id 列表
  13 + value?: LabeledValue[];
15 14 onChange?: (value: LabeledValue[]) => void;
16 15 multiple?: boolean;
17 16 labelInValue?: boolean;
18   - initType?: 1 | 2;
  17 + initType?: number;
19 18 disabled?: boolean;
20   - /** 📢 以下2个属性 仅同时使用一个 📢 */
21   - showIds?: number[]; // 仅显示项目ID列表
22   - hiddenIds?: number[]; // 不显示的列表ID
23   - /** 📢 以上2个属性 仅同时使用一个 📢 */
24   - disabledIds?: number[]; // 禁止选择列表ID
25 19 }
26 20  
27 21 interface DataItem {
... ... @@ -43,53 +37,28 @@ export interface ShopSelectRef {
43 37 export default forwardRef(ShopSelectByBizType);
44 38  
45 39 function ShopSelectByBizType(
46   - { value = [], onChange, multiple = false, labelInValue = false, initType = 1, disabled = false, showIds, hiddenIds, disabledIds }: Props,
  40 + { value = [], onChange, multiple = false, labelInValue = false, initType = 1, disabled = false }: Props,
47 41 ref: Ref<ShopSelectRef>,
48 42 ) {
49   - if (showIds?.length && hiddenIds?.length) {
50   - console.error(`(<ShopSelectByBizType>):\`showIds\` 和 \`hiddenIds\` 不能同时传入。`);
51   - }
52   -
53 43 const { data: byBizTypeList, loading: byBizTypeLoading } = useInitail(getShopListByBizTypeApi, [], { allType: true });
54 44 const { data: byDealerList, loading: byDealerLoading } = useInitail(getShopListByDealerApi, [], {});
55   - const [type, setType] = useState<1 | 2>(initType);
  45 + const [type, setType] = useState<number>(initType);
56 46 const [values, setValues] = useState<LabeledValue[]>(value);
57   - const [checkInfo, setCheckInfo] = useState({
58   - indeterminate: false,
59   - checkAll: false,
60   - }); // 全选按钮的信息,indeterminate 半选中状态,checkAll 全选状态
61   - const allValues = useRef<LabeledValue[]>([]); // 为了方便全选按钮被点击时赋值,将所有人员再计算list的时候,顺便赋值给该变量
  47 +
  48 + // 拓展搜索交互
  49 + const [searchValue, setSearchValue] = useState('');
62 50  
63 51 useEffect(() => {
64 52 if (value.length > 0) {
65 53 setValues(value);
66   - setCheckInfo({
67   - indeterminate: value && value.length > 0 && value.length !== allValues.current.length,
68   - checkAll: value && value.length === allValues.current.length,
69   - });
70 54 } else {
71 55 setValues([]);
72   - setCheckInfo({
73   - indeterminate: false,
74   - checkAll: false,
75   - });
76 56 }
77 57 }, [value]);
78 58  
79   - useEffect(() => {
80   - setCheckInfo({
81   - indeterminate: values && values.length > 0 && values.length !== allValues.current.length,
82   - checkAll: values && values.length === allValues.current.length,
83   - });
84   - }, [values, allValues.current]);
85   -
86 59 useImperativeHandle(ref, () => ({
87 60 reset: () => {
88 61 setValues([]);
89   - setCheckInfo({
90   - indeterminate: false,
91   - checkAll: false,
92   - });
93 62 },
94 63 }));
95 64  
... ... @@ -99,21 +68,28 @@ function ShopSelectByBizType(
99 68 const list = useMemo<DataItem[]>(() => {
100 69 if (type === 1) {
101 70 // 按业态方式
102   - allValues.current = []; // 将所有门店置为空
103   - return byBizTypeList.map((bizType, index) => {
104   - const children = processingChildrenData(bizType, showIds, hiddenIds, disabledIds);
105   - // 将门店下的门店赋值给allValues
106   - allValues.current = allValues.current.concat(
107   - (children || [])
108   - .filter((child) => !child.disabled)
109   - .map((shop) => ({
110   - label: `${shop.shopName}`,
111   - value: shop.shopId,
112   - })),
113   - );
114   - if (index === byBizTypeList.length - 1) {
115   - allValues.current = unique(allValues.current, 'value');
116   - }
  71 + return byBizTypeList.map((bizType) => {
  72 + const headerAllId = `${-1}__${bizType.value}`;
  73 + const children = processingChildrenData(bizType, headerAllId, value);
  74 +
  75 + // 前端手动在列表头部增加一个 {id: -1, name: '全部'} 的选项
  76 + const headerAll = {
  77 + pid: bizType.value,
  78 + title: `全部${bizType.label}`,
  79 + // value: idOrCode to idOrCode__bizType
  80 + value: headerAllId,
  81 + key: headerAllId,
  82 + isLeaf: true,
  83 + level: 2,
  84 + shopId: -1,
  85 + shopName: '全部',
  86 + // disabled:
  87 + // value.filter((i) => {
  88 + // // @ts-ignore
  89 + // const pid = Number(i.value.split('__')[1]);
  90 + // return i.value !== headerAllId && pid === bizType.value;
  91 + // }).length > 0,
  92 + } as DataItem;
117 93  
118 94 return {
119 95 pid: -1,
... ... @@ -122,26 +98,15 @@ function ShopSelectByBizType(
122 98 key: `bizType-${bizType.value}`,
123 99 isLeaf: false,
124 100 level: 1,
125   - selectable: false,
126   - disabled: !children?.length,
127   - children,
  101 + checkable: false,
  102 + children: [headerAll].concat(children ?? []),
128 103 } as DataItem;
129 104 });
130 105 } else if (type === 2) {
131 106 // 按商家方式
132   - allValues.current = []; // 将所有门店置为空
133   - return byDealerList.map((dealer, index) => {
134   - const children = processingChildrenData(dealer, showIds, hiddenIds, disabledIds);
135   - // 将商家下的门店赋值给allValues
136   - allValues.current = allValues.current.concat(
137   - (children || []).map((shop) => ({
138   - label: shop.shopName,
139   - value: shop.shopId,
140   - })),
141   - );
142   - if (index === byDealerList.length - 1) {
143   - allValues.current = unique(allValues.current, 'value');
144   - }
  107 + return byDealerList.map((dealer) => {
  108 + const headerAllId = `${-1}__${dealer.value}`;
  109 + const children = processingChildrenData(dealer, headerAllId, value);
145 110  
146 111 return {
147 112 pid: -1,
... ... @@ -151,40 +116,95 @@ function ShopSelectByBizType(
151 116 isLeaf: false,
152 117 level: 1,
153 118 selectable: false,
154   - disabled: !children?.length,
155 119 children,
156 120 } as DataItem;
157 121 });
158 122 } else return [];
159   - }, [type, byBizTypeList, byDealerList, showIds, hiddenIds]);
160   -
161   - const _onChange: (_value: LabeledValue[], labelList: React.ReactNode[], extra: any) => void = (_value, labelList, extra) => {
162   - setValues(_value);
163   - // if (multiple) {
164   - // setCheckInfo({
165   - // indeterminate:
166   - // _value &&
167   - // _value.length > 0 &&
168   - // _value.length !== allValues.current.length,
169   - // checkAll: _value && _value.length === allValues.current.length,
170   - // });
171   - // }
  123 + }, [type, byBizTypeList, byDealerList, value]);
  124 +
  125 + const _onChange = (_value: LabeledValue[], labelList: React.ReactNode[], extra: any) => {
  126 + // 手动处理互斥逻辑过滤数据
  127 + // console.log('_value', _value);
  128 + // console.log('extra', extra);
  129 + let calcedValue = _.cloneDeep(_value);
  130 + if (calcedValue.length > 1 && type === 1) {
  131 + // 新增选项
  132 + if (calcedValue.length > extra.preValue.length) {
  133 + const latestValue = calcedValue[calcedValue.length - 1];
  134 + const bizType = latestValue.value.toString().split('__')[1];
  135 + if (latestValue.value.toString().includes('-1')) {
  136 + // 说明新增选项为【全部】,则清空同级其他子项
  137 + calcedValue = calcedValue.filter((i) => {
  138 + const currBizType = i.value.toString().split('__')[1];
  139 + return currBizType !== bizType;
  140 + });
  141 + calcedValue.push(latestValue);
  142 + } else {
  143 + // 说明新增选项为同级子项,则清空同级【全部】
  144 + calcedValue = calcedValue.filter((i) => !(i.value === `-1__${bizType}`));
  145 + }
  146 + }
  147 + }
  148 + setValues(calcedValue);
172 149 // @ts-ignore
173   - onChange && onChange(labelInValue ? _value : _value.map((_v) => _v.value));
  150 + onChange && onChange(labelInValue ? calcedValue : calcedValue.map((_v) => _v.value));
  151 + };
  152 +
  153 + const getFilteredData = () => {
  154 + if (searchValue.trim() === '') {
  155 + return list;
  156 + }
  157 + let newChilds: DataItem[] = [];
  158 + list.forEach((i) => {
  159 + const filteredChildren = (i.children ?? []).filter((i) => i.title.toString().toLowerCase().includes(searchValue.trim().toLowerCase()));
  160 + if (filteredChildren.length > 0) {
  161 + newChilds = newChilds.concat(filteredChildren);
  162 + }
  163 + });
  164 + return newChilds;
174 165 };
175 166  
176   - const checkAll = (e: CheckboxChangeEvent) => {
177   - const checked = e.target.checked;
178   - // setCheckInfo({ indeterminate: false, checkAll: checked });
179   - setValues(checked ? allValues.current : []);
180   - onChange && onChange((checked ? (labelInValue ? allValues.current : allValues.current.map((_v) => _v.value)) : []) as LabeledValue[]);
  167 + const handleSelect = (_value: any, node: any) => {
  168 + let oriNames = value.length > 0 ? value.map((i: any) => i.label) : [];
  169 + // value 更新为异步,需手动拼接最新选择值以判断当前筛选值是否已被勾选完
  170 + if (node.pid === -1) {
  171 + // 点击父节点
  172 + oriNames = oriNames.concat(node.children.map((i: DataItem) => i.title));
  173 + } else {
  174 + oriNames.push(node.title);
  175 + }
  176 + const valueMatchArr = oriNames.filter((i: string) => i.toLowerCase().includes(searchValue.trim().toLowerCase()));
  177 + const filteredData = getFilteredData();
  178 + if (valueMatchArr.length === filteredData.length) {
  179 + setSearchValue('');
  180 + }
181 181 };
182 182  
183 183 return (
184 184 <div id={divId}>
185 185 <Spin spinning={byDealerLoading || byBizTypeLoading}>
186 186 <Row justify="space-between" align="middle" style={{ marginBottom: 10 }}>
187   - <Radio.Group disabled={disabled} value={type} onChange={(e) => setType(e.target.value)}>
  187 + <Radio.Group
  188 + disabled={disabled}
  189 + value={type}
  190 + onChange={(e) => {
  191 + setType(e.target.value);
  192 + if (e.target.value !== -1) {
  193 + // 按业态或商家选择门店时,已选项中只要存在一项【全部】,切换时需清空已选项,反之已选项如果都是具体门店,则切换时不清空,两个维度都可回显查看数据
  194 + if (value.filter((i) => i.value.toString().includes('-1')).length > 0) {
  195 + setValues([]);
  196 + onChange && onChange([]);
  197 + }
  198 + } else {
  199 + const typeAll = [labelInValue ? { value: '-1__-1', label: '全部门店' } : '-1__-1'] as LabeledValue[];
  200 + setValues(typeAll);
  201 + onChange && onChange(typeAll);
  202 + }
  203 + }}
  204 + >
  205 + <Radio key={-1} value={-1}>
  206 + 全部门店
  207 + </Radio>
188 208 <Radio key={1} value={1}>
189 209 按业态选择
190 210 </Radio>
... ... @@ -192,18 +212,17 @@ function ShopSelectByBizType(
192 212 按商家选择
193 213 </Radio>
194 214 </Radio.Group>
195   - {multiple && !disabled ? (
196   - <Checkbox indeterminate={checkInfo.indeterminate} checked={checkInfo.checkAll} onChange={checkAll}>
197   - 全选
198   - </Checkbox>
199   - ) : null}
200 215 </Row>
201 216 <TreeSelect
  217 + searchValue={searchValue}
  218 + onSearch={(value) => {
  219 + setSearchValue(value);
  220 + }}
  221 + onSelect={handleSelect}
202 222 style={{ width: '100%' }}
203   - disabled={disabled}
  223 + disabled={disabled || type === -1}
204 224 value={values}
205 225 treeData={list}
206   - // multiple={multiple}
207 226 treeCheckable={multiple}
208 227 allowClear
209 228 labelInValue
... ... @@ -219,34 +238,25 @@ function ShopSelectByBizType(
219 238 );
220 239 }
221 240  
222   -function processingChildrenData(data: ShopItem, showIds?: number[], hiddenIds?: number[], disabledIds?: number[]): DataItem[] | undefined {
223   - let _data: ShopItem[] | undefined, _children: DataItem[] | undefined;
224   -
225   - if (showIds?.length) {
226   - _data = data.children ? data.children.filter((shop) => showIds.includes(shop.value || -1)) : undefined;
227   - } else if (hiddenIds?.length) {
228   - _data = data.children ? data.children.filter((shop) => !hiddenIds.includes(shop.value || -1)) : undefined;
229   - } else {
230   - _data = data.children;
231   - }
  241 +function processingChildrenData(data: ShopItem, headerAllId: string, value: LabeledValue[]): DataItem[] | undefined {
  242 + const _data: ShopItem[] | undefined = data.children;
  243 + const pid = Number(headerAllId.split('__')[1]);
232 244  
233 245 // eslint-disable-next-line prefer-const
234   - _children = _data
  246 + return _data
235 247 ? _data.map((shop) => {
236 248 return {
237 249 pid: data.value,
238 250 title: shop.label,
239   - // value: idOrCode to idOrCode--bizType
240   - value: `${shop.value}--${shop.bizType}`,
241   - key: `${shop.value}--${shop.bizType}`,
  251 + // value: idOrCode to idOrCode__bizType
  252 + value: `${shop.value}__${shop.bizType}`,
  253 + key: `${shop.value}__${shop.bizType}`,
242 254 isLeaf: true,
243 255 level: 2,
244   - disabled: disabledIds?.includes(shop.value || -1),
  256 + // disabled: value.findIndex((i) => i.value === headerAllId) > -1 && pid === data.value,
245 257 shopId: shop.value,
246 258 shopName: shop.label,
247 259 } as DataItem;
248 260 })
249 261 : undefined;
250   -
251   - return _children;
252 262 }
... ...
src/pages/backlog/TaskConfig/components/CreateModal.tsx
... ... @@ -210,26 +210,26 @@ export default function CreateModal({ visible, onCancel, item, onRefreshing, sys
210 210 }}
211 211 </Form.Item>
212 212  
213   - <Form.Item noStyle shouldUpdate={(pre, cur) => pre.itemType !== cur.itemType || pre.customTemp !== cur.customTemp}>
  213 + <Form.Item noStyle shouldUpdate={(pre, cur) => pre.itemType !== cur.itemType}>
214 214 {({ getFieldValue }) => {
215 215 const itemType = getFieldValue('itemType');
216 216 const customTemp = getFieldValue('customTemp');
217 217  
218 218 if (itemType === TodoTypeEnum['提示性']) {
219 219 // 业务性待办
220   - if (!customTemp) {
221   - // 不使用自定义模板
222   - return (
223   - <Form.Item
224   - label="待办模版"
225   - name="dynamicTemp"
226   - rules={[{ required: true, message: '必填项' }]}
227   - extra={<span>{'换行使用“\n”,动态内容用“${}”包含,如:您的验证码是“${}”(其中code是变量)'}</span>}
228   - >
229   - <TextArea placeholder="请输入" allowClear autoSize={{ minRows: 4 }} />
230   - </Form.Item>
231   - );
232   - }
  220 + // if (!customTemp) {
  221 + // 不使用自定义模板
  222 + return (
  223 + <Form.Item
  224 + label="待办模版"
  225 + name="dynamicTemp"
  226 + rules={[{ required: true, message: '必填项' }]}
  227 + extra={<span>{'换行使用“\n”,动态内容用“${}”包含,如:您的验证码是“${}”(其中code是变量)'}</span>}
  228 + >
  229 + <TextArea placeholder="请输入" allowClear autoSize={{ minRows: 4 }} />
  230 + </Form.Item>
  231 + );
  232 + // }
233 233 }
234 234 return null;
235 235 }}
... ...
src/pages/capital/ReceiveRules/subPages/ShopsDimension/index.tsx
... ... @@ -14,7 +14,7 @@ import AuthCheckResult from &#39;@/pages/capital/ReceiveRules/component/AuthCheckRes
14 14 export default function SpecConfig() {
15 15 const { list, loading, setLoading, setParams, paginationConfig } = usePagination(api.getShopPostAuthApi, {});
16 16 const [confirLoaing, setConfirLoading] = useState<boolean>(false);
17   - const [modalPa, setModalPa] = useState({ visible: false, rowValue: undefined });
  17 + const [modalPa, setModalPa] = useState({ visible: false, rowValue: undefined, isEdit: false });
18 18  
19 19 const edit = (record: any) => {
20 20 const editItem = {
... ... @@ -23,7 +23,7 @@ export default function SpecConfig() {
23 23 postList: { value: record.postId, label: record.postName },
24 24 standardId: { id: record.standardId, name: record.name }
25 25 };
26   - setModalPa({ visible: true, rowValue: editItem });
  26 + setModalPa({ visible: true, isEdit: true, rowValue: editItem });
27 27 };
28 28  
29 29 const handDelete = (v: OdSetting.GoodsAuthList) => {
... ... @@ -66,13 +66,65 @@ export default function SpecConfig() {
66 66 api.addSingleAuth(params).then(res => {
67 67 message.success('保存成功');
68 68 setLoading(true);
69   - setModalPa({ visible: false, rowValue: undefined });
  69 + setModalPa({ visible: false, isEdit: false, rowValue: undefined });
70 70 }).catch(e => {
71 71 message.error(e.message);
72 72 }).finally(() => {
73 73 // setConfirmloading(false);
74 74 });
75 75 }
  76 +
  77 + /**新增多选门店岗位 */
  78 + function saveAddAuth(i: any) {
  79 + const params = {
  80 + standardIds: i.standardId.id ? [i.standardId.id] : [],
  81 + shopAuthPostList: [
  82 + {
  83 + shopIds: i.shopIds.map((shop: { value: any }) => shop.value),
  84 + postList: i.postList.map((post: { value: any; label: any }) => ({ postId: post.value, postName: post.label })),
  85 + periodDto: { maxNum: i.maxNum, periodType: i.periodType, period: i.period },
  86 + },
  87 + ],
  88 + };
  89 + setConfirLoading(true);
  90 + api.saveGoodsDimensionCheck({ ...params, pageSize: 1000 })
  91 + .then((res) => {
  92 + if (res.data && res.data?.total) {
  93 + Modal.confirm({
  94 + title: '已有授权信息,继续提交将覆盖以下授权',
  95 + icon: <ExclamationCircleOutlined />,
  96 + width: 700,
  97 + content: <AuthCheckResult data={res.data} />,
  98 + okText: '确认',
  99 + cancelText: '取消',
  100 + onOk: () => onSubmitItems(params),
  101 + });
  102 + } else {
  103 + onSubmitItems(params);
  104 + }
  105 + })
  106 + .catch((e) => {
  107 + message.error(e.message);
  108 + })
  109 + .finally(() => {
  110 + setConfirLoading(false);
  111 + });
  112 + }
  113 +
  114 + function onSubmitItems(params: any) {
  115 + api.saveGoodsDimension(params)
  116 + .then((res) => {
  117 + message.success('保存成功');
  118 + // history.back();
  119 + setLoading(true);
  120 + })
  121 + .catch((e) => {
  122 + message.error(e.message);
  123 + })
  124 + .finally(() => {
  125 + setConfirLoading(false);
  126 + });
  127 + }
76 128 return (
77 129 <PageHeaderWrapper
78 130 title="门店维度授权"
... ... @@ -84,7 +136,7 @@ export default function SpecConfig() {
84 136 <Button
85 137 type="primary"
86 138 icon={<PlusOutlined />}
87   - onClick={() => setModalPa({ visible: true, rowValue: undefined })}
  139 + onClick={() => setModalPa({ visible: true, isEdit: false, rowValue: undefined })}
88 140 >
89 141 新增
90 142 </Button>
... ... @@ -142,13 +194,14 @@ export default function SpecConfig() {
142 194 />
143 195 </Table>
144 196 <AddModal
145   - multiple={false}
146   - visible={modalPa.visible}
147   - onSave={save}
  197 + // multiple={false}
148 198 selectGoods
  199 + multiple={!modalPa.isEdit}
  200 + visible={modalPa.visible}
  201 + onSave={modalPa.isEdit ? save : saveAddAuth}
149 202 disabled={!!modalPa.rowValue}
150 203 current={modalPa.rowValue}
151   - onCancel={() => { setModalPa({ visible: false, rowValue: undefined }); }}
  204 + onCancel={() => { setModalPa({ visible: false, isEdit: false, rowValue: undefined }); }}
152 205 />
153 206 </Card>
154 207 </PageHeaderWrapper>
... ...
src/pages/cas/ClaimConfirmation/components/SpecialFeeConfirm.tsx
... ... @@ -4,6 +4,7 @@ import type { ColumnsType } from &#39;antd/es/table&#39;;
4 4 import moment from 'moment';
5 5  
6 6 import { formatPartCnt } from '@/pages/cas/utils';
  7 +import rmb from '@/utils/rmb';
7 8  
8 9 import { checkSpecialFee, getSpecialFeeDetail, SpecialFee, SpecialFeeApproveEnum, SpecialFeeParams, SpecialItem } from '../api';
9 10 import ImageModal from "@/pages/cas/ClaimConfirmation/components/ImageModal";
... ... @@ -86,14 +87,14 @@ export default function SpecialFeeDetail({ current, visible, setVisible, setLoad
86 87 dataIndex: 'itemPartFee',
87 88 title: '材料费',
88 89 onCell: (record: any) => renderCell(record),
89   - render: (val) => `${Number(val).toFixed(2)}`,
  90 + render: (val) => rmb.p(val),
90 91 align: 'right',
91 92 },
92 93 {
93 94 dataIndex: 'manHoursFee',
94 95 title: '工时费',
95 96 onCell: (record: any) => renderCell(record),
96   - render: (val) => `${Number(val).toFixed(2)}`,
  97 + render: (val) => rmb.p(val),
97 98 align: 'right',
98 99 },
99 100 {
... ... @@ -112,13 +113,13 @@ export default function SpecialFeeDetail({ current, visible, setVisible, setLoad
112 113 {
113 114 dataIndex: 'unitPrice',
114 115 title: '原价',
115   - render: (val) => `${Number(val).toFixed(2)}`,
  116 + render: (val) => rmb.p(val),
116 117 align: 'right',
117 118 },
118 119 {
119 120 dataIndex: 'partFee',
120 121 title: '单价',
121   - render: (val) => `${Number(val).toFixed(2)}`,
  122 + render: (val) => rmb.p(val),
122 123 align: 'right',
123 124 },
124 125 ];
... ...
src/pages/cas/ClaimReviewPool/EditComfirm/index.tsx
... ... @@ -89,8 +89,8 @@ function Index(props: Props) {
89 89 render={(name) => (name !== undefined ? name : '--')}
90 90 width={200}
91 91 />
92   - <Column title="救援费(元)" dataIndex="claimSubmitAmount" align="center" render={(name) => (name !== undefined ? name : '--')} width={200} />
93   - {/* <Column title="提报金额(元)" dataIndex="claimSubmitAmount" align="center" render={(name) => (name !== undefined ? name : '--')} /> */}
  92 + {/*todo 救援模块未上线,默认展示--,上线后展示对应字段 */}
  93 + <Column title="救援费(元)" dataIndex="claimSubmitAmount" align="center" render={() => '--'} width={200} />
94 94 </Table>
95 95 </Card>
96 96 </PageHeaderWrapper>
... ...
src/pages/cas/MaintenanceCard/MPList/components/Operation.tsx
... ... @@ -18,12 +18,12 @@ export default function Oparetion(props: Props) {
18 18  
19 19 /** 查看详情 编辑 */
20 20 function _viewDetail() {
21   - history.push(`/cas/MaintenancePackageCard/list/upsert/${record.brandId}/${record.maintainId}?brandName=${record && record.brandName || ''}`);
  21 + history.push(`/cas/promotionConfig/MaintenancePackageCard/list/upsert/${record.brandId}/${record.maintainId}?brandName=${record && record.brandName || ''}`);
22 22 }
23 23  
24 24 function _viewDetailOil() {
25 25 history.push(
26   - `/cas/MaintenancePackageCard/list/oil/${record.brandId}/${
  26 + `/cas/promotionConfig/MaintenancePackageCard/list/oil/${record.brandId}/${
27 27 record.maintainId
28 28 }?brandName=${(record && record.brandName) || ""}`
29 29 );
... ... @@ -132,4 +132,4 @@ export default function Oparetion(props: Props) {
132 132 )}
133 133 </>
134 134 );
135   -}
136 135 \ No newline at end of file
  136 +}
... ...
src/pages/cas/MaintenanceCard/MPList/index.tsx
... ... @@ -17,7 +17,7 @@ const Setting = (props: ConnectProps) =&gt; {
17 17 const { list, loading, innerParams, hasStorage, setParams, paginationConfig, setLoading } = usePagination<IF.ListVO>(
18 18 getListApi,
19 19 {},
20   - { pageName: '/cas/MaintenancePackageCard/list', notList: true, delay },
  20 + { pageName: '/cas/promotionConfig/MaintenancePackageCard/list', notList: true, delay },
21 21 );
22 22  
23 23 useEffect(() => {
... ... @@ -47,7 +47,7 @@ const Setting = (props: ConnectProps) =&gt; {
47 47 return;
48 48 }
49 49 const brand = brands.find((r) => r.brandId == brandId);
50   - history.push(`/cas/MaintenancePackageCard/list/upsert/${brandId}?brandName=${(brand && brand.brandName) || ''}`);
  50 + history.push(`/cas/promotionConfig/MaintenancePackageCard/list/upsert/${brandId}?brandName=${(brand && brand.brandName) || ''}`);
51 51 }
52 52  
53 53 return (
... ...
src/pages/cas/MaintenanceCard/Upsert/index.tsx
... ... @@ -31,26 +31,6 @@ const Create = (props: Prop) =&gt; {
31 31 const [oil, setOil] = useState<number>();
32 32 const [exData, setExData] = useState<any[]>([]);
33 33  
34   - // const { setFormStorage, removeFormStorage, hasFormStorage } = useFormStorage(`form/cas/MaintenancePackageCard/list/upsert/${brandId}/${maintainId}/${isCopy}`, form);
35   - // const { removeStorage } = useStorage(`/cas/MaintenancePackageCard/list/upsert/${brandId}/${maintainId}/${isCopy}`, {
36   - // detail: {
37   - // data: detail,
38   - // setData: setDetail
39   - // },
40   - // current: {
41   - // data: current,
42   - // setData: setCurrent
43   - // }
44   - // })
45   -
46   - // useEffect(() => {
47   - // if (!hasFormStorage) {
48   - // if (maintainId) {
49   - // loadData();
50   - // }
51   - // }
52   - // }, [hasFormStorage]);
53   -
54 34 useEffect(() => {
55 35 if (maintainId) {
56 36 loadData();
... ... @@ -100,7 +80,7 @@ const Create = (props: Prop) =&gt; {
100 80 setOil(_oil);
101 81 })
102 82 .catch((e) => console.log(e.message))
103   - }
  83 + }
104 84 _data.series = {value: res.data!.seriesId, label: res.data!.seriesName}
105 85 // _data.oilDosage = oil
106 86 if (isCopy) {
... ... @@ -220,4 +200,4 @@ const Create = (props: Prop) =&gt; {
220 200 );
221 201 }
222 202  
223   -export default Create;
224 203 \ No newline at end of file
  204 +export default Create;
... ...
src/pages/cas/MarketAction/index.tsx
... ... @@ -46,7 +46,7 @@ export default () =&gt; {
46 46 <Card>
47 47 <Row justify="space-between" style={{ marginBottom: 16 }}>
48 48 <Filter setParams={setParams} innerParams={innerParams} />
49   - <Button type="primary" onClick={() => history.push(`/cas/marketAction/edit`)}>
  49 + <Button type="primary" onClick={() => history.push(`/cas//marketAction/edit`)}>
50 50 新增
51 51 </Button>
52 52 </Row>
... ... @@ -146,7 +146,7 @@ export default () =&gt; {
146 146 {record.status !== 3 && (
147 147 <Typography.Link
148 148 onClick={() => {
149   - history.push(`/cas/marketAction/edit/${record.id}`);
  149 + history.push(`/cas/promotionConfig/marketAction/edit/${record.id}`);
150 150 }}
151 151 >
152 152 编辑
... ...
src/pages/cas/WarrantyCardSetting/components/Operation.tsx
... ... @@ -18,7 +18,7 @@ export default function Oparetion(props: Props) {
18 18  
19 19 /** 查看详情 编辑 */
20 20 function _viewDetail() {
21   - history.push(`/cas/WarrantyCard/Detail/${record.brandId}/${record.warrantyId}?brandName=${record && record.brandName || ''}`);
  21 + history.push(`/cas/promotionConfig/WarrantyCard/Detail/${record.brandId}/${record.warrantyId}?brandName=${record && record.brandName || ''}`);
22 22 }
23 23  
24 24  
... ... @@ -104,4 +104,4 @@ export default function Oparetion(props: Props) {
104 104 )}
105 105 </React.Fragment>
106 106 );
107   -}
108 107 \ No newline at end of file
  108 +}
... ...
src/pages/cas/WarrantyCardSetting/index.tsx
... ... @@ -17,7 +17,7 @@ const Setting = (props: common.ConnectProps) =&gt; {
17 17 const { list, loading, innerParams, hasStorage, setParams, paginationConfig, setLoading } = usePagination<IF.ListVO>(
18 18 getListApi,
19 19 {},
20   - { pageName: '/cas/WarrantyCard/Setting', notList: true, delay },
  20 + { pageName: '/cas/promotionConfig/WarrantyCard/Setting', notList: true, delay },
21 21 );
22 22  
23 23 useEffect(() => {
... ... @@ -47,7 +47,7 @@ const Setting = (props: common.ConnectProps) =&gt; {
47 47 return;
48 48 }
49 49 const brand = brands.find((r) => r.brandId == brandId);
50   - history.push(`/cas/WarrantyCard/Detail/${brandId}?brandName=${(brand && brand.brandName) || ''}`);
  50 + history.push(`/cas/promotionConfig/WarrantyCard/Detail/${brandId}?brandName=${(brand && brand.brandName) || ''}`);
51 51 }
52 52  
53 53 return (
... ...
src/pages/cas/baseConfig/ShopRelateBizConfig/api.ts 0 → 100644
  1 +import { http } from '@/typing/http';
  2 +import request from '@/utils/request';
  3 +import { CAS_HOST } from '@/utils/host';
  4 +import { BizType } from './entity';
  5 +
  6 +type P<T> = http.PromiseResp<T>;
  7 +type Page<T> = http.PromisePageResp<T>;
  8 +
  9 +interface ListParams {
  10 + groupId?: number;
  11 + shopId?: number;
  12 + userId?: number;
  13 + userName?: string;
  14 + pageSize?: number;
  15 + current?: number;
  16 + keywords?: string; // 业务门店
  17 + authBusiness?: BizType; // 授权售后业务类型
  18 +}
  19 +
  20 +export interface ListResult {
  21 + id: number; // 配置 id
  22 + authBusiness: BizType; // 门店授权业务类型
  23 + authBusinessName: string; // 业务类型名称
  24 + associationShopId: number; // 业务门店id
  25 + associationShopName: string; // 业务门店
  26 + shopList: { id: number; shopName: string }[]; // 门店列表
  27 +}
  28 +
  29 +export interface Shop {
  30 + id: number;
  31 + shopName: string;
  32 + [key: string]: any;
  33 +}
  34 +
  35 +export interface SaveParams {
  36 + id?: number;
  37 + authBusiness: BizType;
  38 + associationShopId: number;
  39 + associationShopName: string;
  40 + shopIds: number[]; // 关联门店
  41 +}
  42 +
  43 +// 列表
  44 +export function listApi(params: ListParams): Page<ListResult> {
  45 + return request.get(`${CAS_HOST}/erp/shop/association/setting/page`, { params });
  46 +}
  47 +
  48 +// 详情
  49 +export function detailApi(associationShopId: number): P<ListResult> {
  50 + return request.get(`${CAS_HOST}/erp/shop/association/setting/detail`, { params: { associationShopId } });
  51 +}
  52 +
  53 +// 保存
  54 +export function saveApi(params: SaveParams) {
  55 + return request.post(`${CAS_HOST}/erp/shop/association/setting/save`, params);
  56 +}
  57 +
  58 +// 删除
  59 +export function deleteApi(id: number) {
  60 + return request.post(`${CAS_HOST}/erp/shop/association/setting/delete`, { id });
  61 +}
  62 +
  63 +// 业务对应门店列表
  64 +export function getShopListApi(authBusiness: BizType): P<Shop[]> {
  65 + return request.get(`${CAS_HOST}/erp/shop/association/find/shops`, { params: { authBusiness } });
  66 +}
... ...
src/pages/cas/baseConfig/ShopRelateBizConfig/components/EditModal.tsx 0 → 100644
  1 +import React, { useEffect, useState } from 'react';
  2 +import { Form, message, Modal, Radio, Select } from 'antd';
  3 +
  4 +import SelectorWithFull from '@/components/SelectorWithFull';
  5 +
  6 +import useInitail from '@/hooks/useInitail';
  7 +import { fetchShopListByRangeTypeApi } from '@/common/api';
  8 +import { BizTypeData } from "@/pages/cas/baseConfig/ShopRelateBizConfig/entity";
  9 +import { getShopListApi, saveApi, type ListResult, type SaveParams } from '../api';
  10 +
  11 +const FormItem = Form.Item;
  12 +const Option = Select.Option;
  13 +
  14 +interface Props {
  15 + open: boolean;
  16 + onCancel: () => any;
  17 + detail: ListResult; // 详情数据
  18 +}
  19 +
  20 +export default function EditModal({ open, onCancel, detail }: Props) {
  21 + const [form] = Form.useForm();
  22 + const [delay, setDelay] = useState(true);
  23 + const [allDelay, setAllDelay] = useState(true);
  24 + // 所有门店
  25 + const { data: allShops, setParams: setAllParams } = useInitail(fetchShopListByRangeTypeApi, [], {}, allDelay);
  26 + // 包含业务的门店列表
  27 + const { data: shops, setParams } = useInitail(getShopListApi, [], 10, delay);
  28 +
  29 + useEffect(() => {
  30 + if (open) {
  31 + setAllDelay(false);
  32 + setAllParams({}, true);
  33 +
  34 + if (detail && detail.shopList) {
  35 + form.setFieldsValue({
  36 + id: detail.id,
  37 + authBusiness: detail.authBusiness,
  38 + associationShop: {
  39 + value: detail.associationShopId,
  40 + label: detail.associationShopName,
  41 + },
  42 + shopIds: detail.shopList.map((shop) => shop.id),
  43 + });
  44 + setDelay(false);
  45 + setParams(detail.authBusiness, true);
  46 + } else {
  47 + form.resetFields();
  48 + }
  49 + }
  50 + }, [open]);
  51 +
  52 + // 获取对应业务门店列表
  53 + const handleBizChange = (e) => {
  54 + setDelay(false);
  55 + setParams(e.target.value, true);
  56 + };
  57 +
  58 + function handleSave(formValue: any) {
  59 + const params: SaveParams = {
  60 + id: formValue.id,
  61 + authBusiness: formValue.authBusiness,
  62 + associationShopId: formValue.associationShop.value,
  63 + associationShopName: formValue.associationShop.label,
  64 + shopIds: formValue.shopIds,
  65 + };
  66 +
  67 + saveApi(params)
  68 + .then(() => {
  69 + message.success('操作成功');
  70 + onCancel();
  71 + })
  72 + .catch((e) => message.error(e.message));
  73 + }
  74 +
  75 + return (
  76 + <Modal
  77 + open={open}
  78 + maskClosable={false}
  79 + title={`${!detail.id ? '新增' : '编辑'}业务映射门店`}
  80 + width={700}
  81 + onCancel={() => onCancel()}
  82 + onOk={() => form.submit()}
  83 + >
  84 + <Form form={form} labelCol={{ span: 4 }} wrapperCol={{ span: 18 }} initialValues={{ type: 1 }} onFinish={handleSave}>
  85 + <FormItem name="id" hidden />
  86 + <FormItem name="authBusiness" label="业务" rules={[{ required: true, message: '请选择业务' }]}>
  87 + <Radio.Group onChange={handleBizChange}>
  88 + {BizTypeData.map((item) => <Radio value={item.value}>{item.label}</Radio>)}
  89 + </Radio.Group>
  90 + </FormItem>
  91 + <FormItem name="associationShop" label="业务门店" rules={[{ required: true, message: '请选择业务门店' }]}>
  92 + <Select placeholder="选择业务门店" labelInValue showSearch optionFilterProp="children">
  93 + {shops.map((shop) => (
  94 + <Option value={shop.id}>{shop.shopName}</Option>
  95 + ))}
  96 + </Select>
  97 + </FormItem>
  98 + <FormItem name="shopIds" label="映射门店" rules={[{ required: true, message: '映射门店' }]}>
  99 + <SelectorWithFull
  100 + placeholder="选择映射门店"
  101 + data={allShops}
  102 + allowClear
  103 + multiple
  104 + showSearch
  105 + treeNodeFilterProp="label"
  106 + autoClearSearchValue={false}
  107 + fieldKeyNames={{ keyName: 'id', valueName: 'id', labelName: 'name' }}
  108 + />
  109 + </FormItem>
  110 + </Form>
  111 + </Modal>
  112 + );
  113 +}
... ...
src/pages/cas/baseConfig/ShopRelateBizConfig/entity.ts 0 → 100644
  1 +export enum BizType {
  2 + /** 维保 */
  3 + MAINTAIN = 10,
  4 + /** 钣喷 */
  5 + METAL = 20,
  6 + /** 装潢 */
  7 + DECORATION = 30,
  8 +}
  9 +
  10 +export const BizTypeData = [
  11 + {
  12 + label: '维保',
  13 + value: BizType.MAINTAIN,
  14 + },
  15 + {
  16 + label: '钣喷',
  17 + value: BizType.METAL,
  18 + },
  19 + {
  20 + label: '装潢',
  21 + value: BizType.DECORATION,
  22 + },
  23 +];
... ...
src/pages/cas/baseConfig/ShopRelateBizConfig/index.tsx 0 → 100644
  1 +import React, { useState } from 'react';
  2 +import { PageHeaderWrapper } from '@ant-design/pro-layout';
  3 +import { Button, Card, Col, Divider, Input, message, Popconfirm, Radio, Row, Table } from 'antd';
  4 +import { debounce } from 'lodash';
  5 +import { ColumnsType } from 'antd/lib/table';
  6 +
  7 +import usePagination from '@/hooks/usePagination';
  8 +
  9 +import TextWithMore from '@/components/TextWithMore';
  10 +
  11 +import { BizTypeData } from '@/pages/cas/baseConfig/ShopRelateBizConfig/entity';
  12 +import { deleteApi, listApi, type ListResult } from './api';
  13 +
  14 +import EditModal from './components/EditModal';
  15 +
  16 +const Search = Input.Search;
  17 +
  18 +export default function WorkStationIndex() {
  19 + const [open, setOpen] = useState(false);
  20 + const [item, setItem] = useState<any>({});
  21 +
  22 + const { list, loading, setLoading, setParams, paginationConfig } = usePagination(listApi, [], {});
  23 +
  24 + const columns: ColumnsType<ListResult> = [
  25 + {
  26 + title: '业务',
  27 + dataIndex: 'authBusinessName',
  28 + },
  29 + {
  30 + title: '业务门店',
  31 + dataIndex: 'associationShopName',
  32 + },
  33 + {
  34 + title: '映射门店',
  35 + dataIndex: 'shopList',
  36 + render: (shops: any, record) => <TextWithMore title={`${record.authBusinessName}业务映射门店`} list={shops} dataIndex="shopName" />,
  37 + },
  38 + {
  39 + title: '操作',
  40 + dataIndex: 'associationShopId',
  41 + render: (id, record) => (
  42 + <>
  43 + <a
  44 + onClick={(e) => {
  45 + e.preventDefault();
  46 + setItem(record);
  47 + setOpen(true);
  48 + }}
  49 + >
  50 + 编辑
  51 + </a>
  52 + <span>
  53 + <Divider type="vertical" />
  54 + <Popconfirm title="是否删除?" onConfirm={() => handleDelete(id)} okText="确定" cancelText="取消">
  55 + <a onClick={(e) => e.preventDefault()} style={{ color: 'red' }}>
  56 + 删除
  57 + </a>
  58 + </Popconfirm>
  59 + </span>
  60 + </>
  61 + ),
  62 + },
  63 + ];
  64 +
  65 + const handleSearch = debounce((keywords: string) => setParams({ keywords }, true), 500);
  66 +
  67 + const handleTypeChange = (e: any) => {
  68 + setParams({ authBusiness: e.target.value }, true);
  69 + };
  70 +
  71 + function handleDelete(id: number) {
  72 + deleteApi(id)
  73 + .then(() => {
  74 + message.success('删除成功');
  75 + setLoading(true);
  76 + })
  77 + .catch((e) => message.error(e.message));
  78 + }
  79 +
  80 + return (
  81 + <PageHeaderWrapper title="业务映射门店">
  82 + <Card>
  83 + <Row justify="space-between" style={{ marginBottom: 16 }}>
  84 + <Col>
  85 + <Radio.Group defaultValue={undefined} onChange={handleTypeChange}>
  86 + <Radio.Button value={undefined}>全部</Radio.Button>
  87 + {BizTypeData.map((item) => (
  88 + <Radio.Button key={item.value} value={item.value}>
  89 + {item.label}
  90 + </Radio.Button>
  91 + ))}
  92 + </Radio.Group>
  93 + <Search style={{ width: 240, marginLeft: 20 }} placeholder="搜索业务门店" allowClear onChange={(e) => handleSearch(e.target.value)} />
  94 + </Col>
  95 + <Col>
  96 + <Button type="primary" onClick={() => setOpen(true)}>
  97 + 新增
  98 + </Button>
  99 + </Col>
  100 + </Row>
  101 +
  102 + <Table dataSource={list} columns={columns} pagination={paginationConfig} rowKey="id" loading={loading} />
  103 + </Card>
  104 +
  105 + <EditModal
  106 + open={open}
  107 + detail={item}
  108 + onCancel={() => {
  109 + setOpen(false);
  110 + setItem({});
  111 + setLoading(true);
  112 + }}
  113 + />
  114 + </PageHeaderWrapper>
  115 + );
  116 +}
... ...
src/pages/dalaran/MediaSettings/components/ThemeSettings/Modal.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-05-06 10:39:03
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2024-01-05 15:07:27
  5 + * @LastEditTime: 2024-04-03 09:33:29
6 6 */
7 7 /**
8 8 * Disclaimer:
... ... @@ -378,8 +378,8 @@ function TopicItem({ oldValue, value, onChange }: TopicItemProps) {
378 378 onChange={(e) => setInputVal(e.target.value)}
379 379 onPressEnter={save}
380 380 style={{ flex: 1 }}
381   - maxLength={13}
382   - showCount
  381 + // maxLength={13}
  382 + // showCount
383 383 />
384 384 <Button type="link" size="small" onClick={save}>
385 385 {key ? '修改' : '添加'}
... ...
src/pages/decoration/deco/DecorationPromotion/DecorateFullFree/index.tsx
... ... @@ -192,7 +192,7 @@ function DecorateFullFree() {
192 192 <Divider type="vertical" />
193 193 <Popconfirm
194 194 title="是否提前结束?"
195   - onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({ ...innerParams, current: 1 }, true))}
  195 + onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({ ...innerParams }, true))}
196 196 okText="确定"
197 197 cancelText="取消"
198 198 >
... ... @@ -220,7 +220,7 @@ function DecorateFullFree() {
220 220 <AdjustDateModal
221 221 visible={adjustDateVisible}
222 222 onCancel={() => setAdjustDateVisible(false)}
223   - fetchList={() => setParams({ ...innerParams, current: 1 }, true)}
  223 + fetchList={() => setParams({ ...innerParams }, true)}
224 224 id={item.id}
225 225 startTime={item.startTime}
226 226 endTime={item.endTime}
... ...
src/pages/decoration/deco/DecorationPromotion/DecorationPackage/index.tsx
... ... @@ -145,7 +145,7 @@ function DecorationPackage() {
145 145 <Divider type="vertical" />
146 146 <Popconfirm
147 147 title="是否提前结束?"
148   - onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({...innerParams, current: 1}, true))}
  148 + onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({...innerParams}, true))}
149 149 okText="确定"
150 150 cancelText="取消"
151 151 >
... ... @@ -173,7 +173,7 @@ function DecorationPackage() {
173 173 <AdjustDateModal
174 174 visible={adjustDateVisible}
175 175 onCancel={() => setAdjustDateVisible(false)}
176   - fetchList={() => setParams({...innerParams, current: 1}, true)}
  176 + fetchList={() => setParams({...innerParams}, true)}
177 177 id={item.id}
178 178 startTime={item.startTime}
179 179 endTime={item.endTime}
... ...
src/pages/decoration/deco/DecorationPromotion/SPPManage/subPage/indexPage.tsx
1 1 import React, { useState } from 'react';
2   -import { Button, Popconfirm, Divider, Table, message, DatePicker, Input } from 'antd';
  2 +import { Button, Popconfirm, Divider, Table, message, DatePicker, Input, Select } from 'antd';
3 3 import { useStore } from '../index';
4 4 import * as API from '../api';
5 5 import usePagination from '@/hooks/usePagination';
... ... @@ -11,6 +11,7 @@ import AdjustDateModal from &#39;@/pages/decoration/deco/componets/AdjustDateModal&#39;;
11 11 const { Column } = Table;
12 12 const { RangePicker } = DatePicker;
13 13 const { Search } = Input;
  14 +const { Option } = Select;
14 15  
15 16 export function earlyEndHandle(id: number, callBack?: () => any) {
16 17 API.earlyEnd(id).then(() => {
... ... @@ -90,9 +91,15 @@ export default function IndexPage() {
90 91 ],
91 92 }}
92 93 format="YYYY-MM-DD"
93   - //disabledDate={(current) => disalbeTime(current)}
94 94 onChange={(time) => onTime(time)}
95 95 />
  96 + <Select style={{ width: 200, marginLeft: 10 }} placeholder="请选择状态" onChange={v => setParams({ flowStatus: v}, true)} allowClear>
  97 + <Option value="1">待审批</Option>
  98 + <Option value="2">已通过</Option>
  99 + <Option value="3">已拒绝</Option>
  100 + <Option value="98">已过期</Option>
  101 + <Option value="99">已取消</Option>
  102 + </Select>
96 103 </div>
97 104 <Button type="primary" onClick={itemClick}>
98 105 新增
... ... @@ -158,7 +165,7 @@ export default function IndexPage() {
158 165 <Divider type="vertical" />
159 166 <Popconfirm
160 167 title="是否提前结束?"
161   - onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({...innerParams, current: 1}, true))}
  168 + onConfirm={() => earlyEndHandle(record.id || 0, () => setParams({...innerParams}, true))}
162 169 okText="确定"
163 170 cancelText="取消"
164 171 >
... ... @@ -185,7 +192,7 @@ export default function IndexPage() {
185 192 <AdjustDateModal
186 193 visible={adjustDateVisible}
187 194 onCancel={() => setAdjustDateVisible(false)}
188   - fetchList={() => setParams({...innerParams, current: 1}, true)}
  195 + fetchList={() => setParams({}, true)}
189 196 id={item.id}
190 197 startTime={item.startTime}
191 198 endTime={item.endTime}
... ...
src/pages/ehr/CommonSettings/HrSetting/index.tsx
... ... @@ -58,11 +58,11 @@ const HrSettingKV: { [key in HrSettingKey]: KValue } = {
58 58 }
59 59 },
60 60 },
61   - personalityTestSystemOff: {
62   - title: '性格测试',
63   - type: 'custom',
64   - customRender: PersonalityTest,
65   - },
  61 + // personalityTestSystemOff: {
  62 + // title: '性格测试',
  63 + // type: 'custom',
  64 + // customRender: PersonalityTest,
  65 + // },
66 66 leaveControlRate: {
67 67 title: '离职目标管控率',
68 68 type: 'custom',
... ...
src/pages/ehr/PersonManage/components/PersonFilter.tsx
... ... @@ -2,6 +2,7 @@ import React from &#39;react&#39;;
2 2 import { Input, Radio } from 'antd';
3 3 import { useStore } from '../index';
4 4 import FeeweeFilterOption from '@/pages/notice/components/FeeweeFilterOption';
  5 +import ShopSelectNew from '@/components/ShopSelectNew';
5 6  
6 7 const RadioButton = Radio.Button;
7 8 const RadioGroup = Radio.Group;
... ... @@ -10,7 +11,7 @@ export default function PersonFilter() {
10 11 const { pagination } = useStore();
11 12  
12 13 return (
13   - <div style={{ display: 'flex', flex: 1, justifyContent: 'start', alignItems: 'end', gap: 10 }}>
  14 + <div style={{ display: 'flex', flex: 1, justifyContent: 'start', alignItems: 'end', flexWrap: 'wrap', gap: 10 }}>
14 15 <RadioGroup
15 16 defaultValue={2}
16 17 buttonStyle="solid"
... ... @@ -34,6 +35,56 @@ export default function PersonFilter() {
34 35 style={{ minWidth: 300 }}
35 36 />
36 37 </FeeweeFilterOption>
  38 + <FeeweeFilterOption title="在职门店">
  39 + <ShopSelectNew
  40 + style={{ minWidth: 260 }}
  41 + value={
  42 + pagination.innerParams.dutyShopName && pagination.innerParams.dutyShopId
  43 + ? [
  44 + {
  45 + label: pagination.innerParams.dutyShopName,
  46 + value: pagination.innerParams.dutyShopId,
  47 + },
  48 + ]
  49 + : []
  50 + }
  51 + onChange={(shops: any) =>
  52 + pagination.setParams(
  53 + {
  54 + dutyShopId: shops.length ? shops[0].value : undefined,
  55 + dutyShopName: shops.length ? shops[0].label : undefined,
  56 + current: 1,
  57 + },
  58 + true,
  59 + )
  60 + }
  61 + />
  62 + </FeeweeFilterOption>
  63 + <FeeweeFilterOption title="社保门店">
  64 + <ShopSelectNew
  65 + style={{ minWidth: 260 }}
  66 + value={
  67 + pagination.innerParams.fundShopName && pagination.innerParams.fundShopId
  68 + ? [
  69 + {
  70 + label: pagination.innerParams.fundShopName,
  71 + value: pagination.innerParams.fundShopId,
  72 + },
  73 + ]
  74 + : []
  75 + }
  76 + onChange={(shops: any) =>
  77 + pagination.setParams(
  78 + {
  79 + fundShopId: shops.length ? shops[0].value : undefined,
  80 + fundShopName: shops.length ? shops[0].label : undefined,
  81 + current: 1,
  82 + },
  83 + true,
  84 + )
  85 + }
  86 + />
  87 + </FeeweeFilterOption>
37 88 </div>
38 89 );
39 90 }
... ...
src/pages/ehr/PersonManage/interface.d.ts
... ... @@ -2,12 +2,16 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-04-13 09:39:04
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-04-13 15:00:55
  5 + * @LastEditTime: 2024-04-02 14:20:34
6 6 */
7 7 declare namespace Person {
8 8 interface QueryParams {
9 9 keyWords?: string; // 搜索关键字(岗位名称、电话号码、姓名)
10 10 staffStatus?: 1 | 2 | 8 | 9; // 员工状态 1试用期 2正式 8待离职 9离职 为空则是全部(全部不包含离职员工)
  11 + dutyShopId?: number; // 在职门店
  12 + dutyShopName?: string;
  13 + fundShopId?: number; // 社保门店
  14 + fundShopName?: string;
11 15 }
12 16  
13 17 interface List {
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/components/ConfirmModal.tsx
1 1 import React, { useEffect, useRef, useState } from "react";
2 2 import EditTable from "@/pages/ehr/components/EditTable";
3 3 import { useStore } from "../index";
  4 +import type {
  5 + InputRef} from "antd";
4 6 import {
5 7 Button,
6 8 Divider,
7 9 Input,
8   - InputRef,
9 10 message,
10 11 Modal,
11 12 Popover,
... ... @@ -16,8 +17,8 @@ import { SearchOutlined } from &quot;@ant-design/icons&quot;;
16 17 import { formatObjText, priceToThousands } from "@/utils/utils";
17 18 import moment from "moment";
18 19 import DetailItem from "@/pages/ehr/Authentication/Settings/components/DetailItem";
19   -import { ColumnType } from "antd/lib/table";
20   -import { FilterConfirmProps } from "antd/lib/table/interface";
  20 +import type { ColumnType } from "antd/lib/table";
  21 +import type { FilterConfirmProps } from "antd/lib/table/interface";
21 22 import { checkNull } from "@/utils/validate";
22 23  
23 24 export default function SubsidyConfirmModal() {
... ... @@ -199,7 +200,7 @@ export default function SubsidyConfirmModal() {
199 200 zIndex={1002}
200 201 destroyOnClose
201 202 >
202   - <Row style={{ alignItems: "center", justifyContent: "space-around" }}>
  203 + <Row style={{ alignItems: 'center', justifyContent: 'space-around' }}>
203 204 <DetailItem
204 205 style={{ marginBottom: 0 }}
205 206 title="补贴标准"
... ... @@ -207,24 +208,25 @@ export default function SubsidyConfirmModal() {
207 208 desp={
208 209 <>
209 210 <span>
210   - {`${priceToThousands(confirmModalInfo.item?.amount ?? "")} ${!confirmModalInfo.item?.specialSubsidy
211   - ? confirmModalInfo.item?.amountType === 1
212   - ? "元/天"
213   - : confirmModalInfo.item?.amountType === 3
214   - ? "元/月"
215   - : ""
216   - : "元/月"
217   - }`}
  211 + {`${priceToThousands(confirmModalInfo.item?.amount ?? '')} ${
  212 + !confirmModalInfo.item?.specialSubsidy
  213 + ? confirmModalInfo.item?.amountType === 1
  214 + ? '元/天'
  215 + : confirmModalInfo.item?.amountType === 3
  216 + ? '元/月'
  217 + : ''
  218 + : '元/月'
  219 + }`}
218 220 </span>
219 221 {confirmModalInfo.item?.specialSubsidy ? (
220 222 <span
221 223 style={{
222 224 fontSize: 12,
223   - color: "#FF9625",
224   - padding: "1px 5px",
  225 + color: '#FF9625',
  226 + padding: '1px 5px',
225 227 marginLeft: 5,
226 228 borderRadius: 2,
227   - border: "1px solid #FF9625",
  229 + border: '1px solid #FF9625',
228 230 }}
229 231 >
230 232 特殊
... ... @@ -239,9 +241,9 @@ export default function SubsidyConfirmModal() {
239 241 title="适用门店"
240 242 desp={
241 243 confirmModalInfo.item?.specialSubsidy ? (
242   - "-"
  244 + '-'
243 245 ) : confirmModalInfo.item?.shopScope === 1 ? (
244   - "全部门店"
  246 + '全部门店'
245 247 ) : (
246 248 <Popover
247 249 trigger="click"
... ... @@ -249,12 +251,12 @@ export default function SubsidyConfirmModal() {
249 251 content={
250 252 <div
251 253 style={{
252   - display: "flex",
253   - flexWrap: "wrap",
254   - justifyContent: "flex-start",
255   - alignItems: "center",
  254 + display: 'flex',
  255 + flexWrap: 'wrap',
  256 + justifyContent: 'flex-start',
  257 + alignItems: 'center',
256 258 maxWidth: 400,
257   - gap: "0 20px",
  259 + gap: '0 20px',
258 260 }}
259 261 >
260 262 {confirmModalInfo.item?.shopList?.map((shop) => (
... ... @@ -264,12 +266,7 @@ export default function SubsidyConfirmModal() {
264 266 }
265 267 >
266 268 <span>
267   - {formatObjText(
268   - confirmModalInfo.item?.shopList ?? [],
269   - "shopName",
270   - 2,
271   - "个门店"
272   - )}
  269 + {formatObjText(confirmModalInfo.item?.shopList ?? [], 'shopName', 2, '个门店')}
273 270 <a>查看</a>
274 271 </span>
275 272 </Popover>
... ... @@ -282,9 +279,9 @@ export default function SubsidyConfirmModal() {
282 279 title="适用岗位"
283 280 desp={
284 281 confirmModalInfo.item?.specialSubsidy ? (
285   - "-"
  282 + '-'
286 283 ) : confirmModalInfo.item?.postScope === 1 ? (
287   - "全部岗位"
  284 + '全部岗位'
288 285 ) : (
289 286 <Popover
290 287 trigger="click"
... ... @@ -292,12 +289,12 @@ export default function SubsidyConfirmModal() {
292 289 content={
293 290 <div
294 291 style={{
295   - display: "flex",
296   - flexWrap: "wrap",
297   - justifyContent: "flex-start",
298   - alignItems: "center",
  292 + display: 'flex',
  293 + flexWrap: 'wrap',
  294 + justifyContent: 'flex-start',
  295 + alignItems: 'center',
299 296 maxWidth: 400,
300   - gap: "0 20px",
  297 + gap: '0 20px',
301 298 }}
302 299 >
303 300 {confirmModalInfo.item?.postList?.map((post) => (
... ... @@ -307,12 +304,7 @@ export default function SubsidyConfirmModal() {
307 304 }
308 305 >
309 306 <span>
310   - {formatObjText(
311   - confirmModalInfo.item?.postList ?? [],
312   - "postName",
313   - 2,
314   - "个岗位"
315   - )}
  307 + {formatObjText(confirmModalInfo.item?.postList ?? [], 'postName', 2, '个岗位')}
316 308 <a>查看</a>
317 309 </span>
318 310 </Popover>
... ... @@ -325,25 +317,20 @@ export default function SubsidyConfirmModal() {
325 317 title="适用范围"
326 318 desp={
327 319 confirmModalInfo.item?.specialSubsidy ? (
328   - "-"
  320 + '-'
329 321 ) : confirmModalInfo.item?.scopeStaff ? (
330 322 <span>
331   - {confirmModalInfo.item?.scopeStaff
332   - ? ScopeType[confirmModalInfo.item?.scopeStaff]
333   - : ""}
  323 + {confirmModalInfo.item?.scopeStaff ? ScopeType[confirmModalInfo.item?.scopeStaff] : ''}
334 324 {confirmModalInfo.item?.scopeStaff !== 3 ? (
335 325 <>
336 326 时间
337   - {confirmModalInfo.item?.scopeStaffTimeMin ?? ""}-
338   - {confirmModalInfo.item?.scopeStaffTimeMax ?? ""}
339   - {confirmModalInfo.item?.scopeStaffTimeUnit
340   - ? ScopeUnit[confirmModalInfo.item?.scopeStaffTimeUnit]
341   - : ""}
  327 + {confirmModalInfo.item?.scopeStaffTimeMin ?? ''}-{confirmModalInfo.item?.scopeStaffTimeMax ?? ''}
  328 + {confirmModalInfo.item?.scopeStaffTimeUnit ? ScopeUnit[confirmModalInfo.item?.scopeStaffTimeUnit] : ''}
342 329 </>
343 330 ) : null}
344 331 </span>
345 332 ) : (
346   - "-"
  333 + '-'
347 334 )
348 335 }
349 336 />
... ... @@ -352,9 +339,7 @@ export default function SubsidyConfirmModal() {
352 339 <Row>
353 340 <DetailItem
354 341 title="计算方式"
355   - desp={`日均补贴金额 * (${standardConfirmModalInfo.attendanceConfigList
356   - ?.map((item) => item.desc + "天数")
357   - .join("+")})`}
  342 + desp={`日均补贴金额 * (${standardConfirmModalInfo.attendanceConfigList?.map((item) => item.desc + '天数').join('+')})`}
358 343 />
359 344 </Row>
360 345 <EditTable
... ... @@ -364,7 +349,7 @@ export default function SubsidyConfirmModal() {
364 349 showTotal: (total, range) => `共 ${total} 条数据,当前展示第 ${range[0]}-${range[1]} 条数据`,
365 350 }}
366 351 bordered={false}
367   - scroll={{ scrollToFirstRowOnChange: true, x: 1500, y: "65vh" }}
  352 + scroll={{ scrollToFirstRowOnChange: true, x: 1500, y: '65vh' }}
368 353 rowKey="staffId"
369 354 uniqueKey="staffId"
370 355 onRow={(record) => ({
... ... @@ -374,150 +359,128 @@ export default function SubsidyConfirmModal() {
374 359 },
375 360 })}
376 361 rowSelection={{
377   - type: "checkbox",
378   - selectedRowKeys: items
379   - ?.filter((item) => item.selected ?? true)
380   - ?.map((item) => item.staffId || ""),
  362 + type: 'checkbox',
  363 + selectedRowKeys: items?.filter((item) => item.selected ?? true)?.map((item) => item.staffId || ''),
381 364 onSelect,
382 365 onSelectAll,
383 366 }}
384 367 columns={[
385 368 {
386   - title: "员工姓名",
387   - dataIndex: "staffName",
  369 + title: '员工姓名',
  370 + dataIndex: 'staffName',
388 371 width: 120,
389   - fixed: "left",
390   - ...getColumnSearchProps("staffName", "员工姓名"),
  372 + fixed: 'left',
  373 + ...getColumnSearchProps('staffName', '员工姓名'),
391 374 },
392 375 {
393   - title: "人员岗位",
394   - dataIndex: "postName",
  376 + title: '人员岗位',
  377 + dataIndex: 'postName',
395 378 width: 150,
396   - ...getColumnSearchProps("postName", "人员岗位"),
  379 + ...getColumnSearchProps('postName', '人员岗位'),
397 380 },
398 381 {
399   - title: "在职门店",
400   - dataIndex: "shopName",
  382 + title: '在职门店',
  383 + dataIndex: 'shopName',
401 384 width: 150,
402   - ...getColumnSearchProps("shopName", "在职门店"),
  385 + ...getColumnSearchProps('shopName', '在职门店'),
403 386 },
404 387 {
405   - title: "入职时间",
406   - dataIndex: "entryDate",
  388 + title: '入职时间',
  389 + dataIndex: 'entryDate',
407 390 width: 110,
408   - sorter: (
409   - a: EHrSubsidyConfirm.TypeStaffVO,
410   - b: EHrSubsidyConfirm.TypeStaffVO
411   - ) => (a.entryDate ?? -1) - (b.entryDate ?? -1),
412   - render: (entryDate: number) => (entryDate ? moment(entryDate).format("YYYY-MM-DD") : "-"),
  391 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.entryDate ?? -1) - (b.entryDate ?? -1),
  392 + render: (entryDate: number) => (entryDate ? moment(entryDate).format('YYYY-MM-DD') : '-'),
413 393 },
414 394 {
415   - title: "转正时间",
416   - dataIndex: "regularDate",
  395 + title: '转正时间',
  396 + dataIndex: 'regularDate',
417 397 width: 110,
418   - sorter: (
419   - a: EHrSubsidyConfirm.TypeStaffVO,
420   - b: EHrSubsidyConfirm.TypeStaffVO
421   - ) => (a.regularDate ?? -1) - (b.regularDate ?? -1),
422   - render: (regularDate: number) => (regularDate ? moment(regularDate).format("YYYY-MM-DD") : "-"),
  398 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.regularDate ?? -1) - (b.regularDate ?? -1),
  399 + render: (regularDate: number) => (regularDate ? moment(regularDate).format('YYYY-MM-DD') : '-'),
423 400 },
424 401 {
425   - title: "离职时间",
426   - dataIndex: "leaveDate",
  402 + title: '离职时间',
  403 + dataIndex: 'leaveDate',
427 404 width: 110,
428   - sorter: (
429   - a: EHrSubsidyConfirm.TypeStaffVO,
430   - b: EHrSubsidyConfirm.TypeStaffVO
431   - ) => (a.leaveDate ?? -1) - (b.leaveDate ?? -1),
432   - render: (leaveDate: number) => (leaveDate ? moment(leaveDate).format("YYYY-MM-DD") : "-"),
  405 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.leaveDate ?? -1) - (b.leaveDate ?? -1),
  406 + render: (leaveDate: number) => (leaveDate ? moment(leaveDate).format('YYYY-MM-DD') : '-'),
433 407 },
434 408 {
435   - title: "上班天数",
436   - hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("上班")
437   - ),
438   - dataIndex: "workDays",
  409 + title: '上班天数',
  410 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes('上班')),
  411 + dataIndex: 'workDays',
439 412 width: 90,
440   - sorter: (
441   - a: EHrSubsidyConfirm.TypeStaffVO,
442   - b: EHrSubsidyConfirm.TypeStaffVO
443   - ) => (a.workDays ?? -1) - (b.workDays ?? -1),
  413 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.workDays ?? -1) - (b.workDays ?? -1),
444 414 render: (workDays: number) => `${workDays ?? 0} 天`,
445 415 },
446 416 {
447   - title: "请假天数",
448   - hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("请假")
449   - ),
450   - dataIndex: "askForLeaveDays",
  417 + title: '请假天数',
  418 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes('请假')),
  419 + dataIndex: 'askForLeaveDays',
451 420 width: 90,
452   - sorter: (
453   - a: EHrSubsidyConfirm.TypeStaffVO,
454   - b: EHrSubsidyConfirm.TypeStaffVO
455   - ) => (a.askForLeaveDays ?? -1) - (b.askForLeaveDays ?? -1),
  421 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.askForLeaveDays ?? -1) - (b.askForLeaveDays ?? -1),
456 422 render: (askForLeaveDays: number) => `${askForLeaveDays ?? 0} 天`,
457 423 },
458 424 {
459   - title: "出差天数",
460   - hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("出差")
461   - ),
462   - dataIndex: "evectionDays",
  425 + title: '出差天数',
  426 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes('出差')),
  427 + dataIndex: 'evectionDays',
463 428 width: 90,
464   - sorter: (
465   - a: EHrSubsidyConfirm.TypeStaffVO,
466   - b: EHrSubsidyConfirm.TypeStaffVO
467   - ) => (a.evectionDays ?? -1) - (b.evectionDays ?? -1),
  429 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.evectionDays ?? -1) - (b.evectionDays ?? -1),
468 430 render: (evectionDays: number) => `${evectionDays ?? 0} 天`,
469 431 },
470 432 {
471   - title: "休息天数",
472   - hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes("休息")
473   - ),
474   - dataIndex: "restDays",
  433 + title: '休息天数',
  434 + hide: !standardConfirmModalInfo.attendanceConfigList?.find((item) => item.desc?.includes('休息')),
  435 + dataIndex: 'restDays',
475 436 width: 90,
476   - sorter: (
477   - a: EHrSubsidyConfirm.TypeStaffVO,
478   - b: EHrSubsidyConfirm.TypeStaffVO
479   - ) => (a.restDays ?? -1) - (b.restDays ?? -1),
  437 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.restDays ?? -1) - (b.restDays ?? -1),
480 438 render: (restDays: number) => `${restDays ?? 0} 天`,
481 439 },
482 440 {
483   - title: "补贴标准",
  441 + title: '晚班天数',
  442 + dataIndex: 'nightDays',
  443 + width: 90,
  444 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.nightDays ?? -1) - (b.nightDays ?? -1),
  445 + render: (nightDays: number) => `${nightDays ?? 0} 天`,
  446 + },
  447 + {
  448 + title: '补贴标准',
484 449 width: 150,
485   - dataIndex: "standardAmount",
486   - sorter: (
487   - a: EHrSubsidyConfirm.TypeStaffVO,
488   - b: EHrSubsidyConfirm.TypeStaffVO
489   - ) => (a.standardAmount ?? -1) - (b.standardAmount ?? -1),
  450 + dataIndex: 'standardAmount',
  451 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.standardAmount ?? -1) - (b.standardAmount ?? -1),
490 452 render: (standardAmount: number) => `${priceToThousands(standardAmount)} 元`,
491 453 },
492 454 {
493   - title: "系统计算金额",
  455 + title: '系统计算金额',
494 456 width: 150,
495   - dataIndex: "systemCalcAmount",
496   - sorter: (
497   - a: EHrSubsidyConfirm.TypeStaffVO,
498   - b: EHrSubsidyConfirm.TypeStaffVO
499   - ) => (a.standardAmount ?? -1) - (b.standardAmount ?? -1),
  457 + dataIndex: 'systemCalcAmount',
  458 + sorter: (a: EHrSubsidyConfirm.TypeStaffVO, b: EHrSubsidyConfirm.TypeStaffVO) => (a.standardAmount ?? -1) - (b.standardAmount ?? -1),
500 459 render: (systemCalcAmount: number) => `${priceToThousands(systemCalcAmount)} 元`,
501 460 },
502 461 {
503   - title: "实际补贴金额",
504   - dataIndex: "realAmount",
  462 + title: '实际补贴金额',
  463 + dataIndex: 'realAmount',
505 464 width: 150,
506 465 editable: true,
507   - inputType: "number",
  466 + inputType: 'number',
508 467 max: 999.99,
509   - fixed: "right",
510   - render: (realAmount: number, record: EHrSubsidyConfirm.TypeStaffVO) => <span style={record.systemCalcAmount !== record.realAmount ? { color: '#F4333C' } : undefined}>{`${priceToThousands(realAmount)} 元`}</span>,
  468 + fixed: 'right',
  469 + render: (realAmount: number, record: EHrSubsidyConfirm.TypeStaffVO) => (
  470 + <span style={record.systemCalcAmount !== record.realAmount ? { color: '#F4333C' } : undefined}>{`${priceToThousands(
  471 + realAmount,
  472 + )} 元`}</span>
  473 + ),
511 474 },
512 475 {
513   - title: "备注",
  476 + title: '备注',
514 477 editable: true,
515 478 required: false,
516   - inputType: "text",
  479 + inputType: 'text',
517 480 width: 200,
518   - dataIndex: "remark",
519   - fixed: "right",
520   - render: (remark: string) => remark ?? "-",
  481 + dataIndex: 'remark',
  482 + fixed: 'right',
  483 + render: (remark: string) => remark ?? '-',
521 484 },
522 485 ]}
523 486 />
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidyConfirm/interface.d.ts
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-03-13 09:12:25
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-06-02 09:19:30
  5 + * @LastEditTime: 2024-03-28 15:27:21
6 6 */
7 7 declare namespace EHrSubsidyConfirm {
8 8 interface QueryParams {
... ... @@ -127,6 +127,7 @@ declare namespace EHrSubsidyConfirm {
127 127 askForLeaveDays?: number; // 请假天数
128 128 evectionDays?: number; // 出差天数
129 129 restDays?: number; // 休息天数
  130 + nightDays?: number; // 晚班天数
130 131 standardAmount?: number; // 补贴标准金额
131 132 realAmount?: number; // 实际补贴金额
132 133 systemCalcAmount?: number; // 系统计算金额
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/components/List.tsx
... ... @@ -2,7 +2,7 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2023-02-15 17:42:54
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2023-05-11 11:40:29
  5 + * @LastEditTime: 2024-03-28 15:14:20
6 6 */
7 7 import {
8 8 formatObjText,
... ... @@ -38,7 +38,7 @@ export default function SubsidySettingsList() {
38 38 align="left"
39 39 width={120}
40 40 render={(amount: number, record: EHrSubsidySetting.List) => `${priceToThousands(amount)} ${
41   - pagination.innerParams.type === 2
  41 + pagination.innerParams.type !== 1
42 42 ? record.amountType === 1
43 43 ? "元/天"
44 44 : record.amountType === 3
... ...
src/pages/ehr/PhoneChargeAndSubsidy/subpages/SubsidySettings/components/Modal.tsx
1 1 import { checkNull, validatorNumberCanWithDecimal } from '@/utils/validate';
2 2 import { Form, Input, message, Modal, Select } from 'antd';
3   -import { LabeledValue } from 'antd/lib/select';
  3 +import type { LabeledValue } from 'antd/lib/select';
4 4 import React, { useEffect, useRef, useState } from 'react';
5 5 import { saveSubsidySettingApi } from '../api';
6 6 import { useStore } from '../index';
7   -import Post, { PostRef } from './Post';
8   -import Scope, { Value as ScopeValue } from './Scope';
9   -import Shop, { Value as ShopValue } from './Shop';
  7 +import type { PostRef } from './Post';
  8 +import Post from './Post';
  9 +import type { Value as ScopeValue } from './Scope';
  10 +import Scope from './Scope';
  11 +import type { Value as ShopValue } from './Shop';
  12 +import Shop from './Shop';
10 13  
11 14 export default function SubsidySettingsModal() {
12 15 const { current, setCurrent, visible, setVisible, pagination, subsidyTypeList, nationInitial } = useStore();
... ... @@ -138,9 +141,9 @@ export default function SubsidySettingsModal() {
138 141 <Input
139 142 placeholder="请输入补贴金额"
140 143 allowClear
141   - suffix={pagination.innerParams.type === 2 ? undefined : '元'}
  144 + suffix={pagination.innerParams.type !== 1 ? undefined : '元'}
142 145 addonAfter={
143   - pagination.innerParams.type === 2 ? (
  146 + pagination.innerParams.type !== 1 ? (
144 147 <Form.Item noStyle name="amountType">
145 148 <Select>
146 149 <Select.Option value={1}>元/天</Select.Option>
... ...
src/pages/ehr/PostSetting/components/IndexDetail.tsx
... ... @@ -2,18 +2,18 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-04-13 09:39:04
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2024-03-08 11:26:17
  5 + * @LastEditTime: 2024-04-02 14:46:43
6 6 */
7 7 import React from 'react';
8 8 import { useStore } from '../index';
9   -import { Table, Popover, Row, Button } from 'antd';
  9 +import { Table, Popover, Row, Button, Badge } from 'antd';
10 10 import { LeftCircleOutlined } from '@ant-design/icons';
11 11 import { detailShopApi } from '../api';
12 12 import useInitail from '@/hooks/useInitail';
13 13 import { PersonStatus, PersonStatusColor } from '@/pages/ehr/PersonManage/entity';
14 14  
15 15 export default function IndexDetail() {
16   - const { currentShopItem, setCurrentShopItem, breadcrumbs, setBreadcrumbs, setCurrentBreadcrumb } = useStore();
  16 + const { currentShopItem, setCurrentShopItem, breadcrumbs, setBreadcrumbs, setCurrentBreadcrumb, ChangeType, ChangeTypeColor } = useStore();
17 17 const { data, loading } = useInitail(detailShopApi, [], (currentShopItem && currentShopItem.id) || 0);
18 18  
19 19 const getBack = () => {
... ... @@ -30,6 +30,7 @@ export default function IndexDetail() {
30 30 <span style={{ display: 'inline-block', marginBottom: 20, fontSize: 16 }}>
31 31 合计:{new Set(data.map((d) => d.staffId)).size || 0}&nbsp;&nbsp;人
32 32 </span>
  33 + {/* @ts-ignore */}
33 34 <Button icon={<LeftCircleOutlined />} type="link" onClick={getBack}>
34 35 返回
35 36 </Button>
... ... @@ -45,9 +46,13 @@ export default function IndexDetail() {
45 46 title="人员状态"
46 47 dataIndex="staffStatus"
47 48 align="center"
48   - render={(staffStatus: number) =>
49   - staffStatus ? <span style={{ color: PersonStatusColor[staffStatus] || '#000' }}>{PersonStatus[staffStatus]}</span> : '-'
50   - }
  49 + render={(staffStatus: number) => (staffStatus ? <Badge color={PersonStatusColor[staffStatus]} text={PersonStatus[staffStatus]} /> : '-')}
  50 + />
  51 + <Table.Column
  52 + title="人员变动状态"
  53 + dataIndex="changeType"
  54 + align="center"
  55 + render={(changeType: number) => (changeType ? <Badge color={ChangeTypeColor[changeType]} text={ChangeType[changeType]} /> : '-')}
51 56 />
52 57 <Table.Column
53 58 title="门店"
... ...
src/pages/ehr/PostSetting/components/IndexPostDetail.tsx
... ... @@ -2,18 +2,19 @@
2 2 * @Author: wangqiang@feewee.cn
3 3 * @Date: 2022-04-13 09:39:04
4 4 * @LastEditors: wangqiang@feewee.cn
5   - * @LastEditTime: 2024-01-05 09:30:40
  5 + * @LastEditTime: 2024-04-02 14:43:45
6 6 */
7 7 import React from 'react';
8 8 import { useStore } from '../index';
9   -import { Table, Popover, Row, Button } from 'antd';
  9 +import { Table, Popover, Row, Button, Badge } from 'antd';
10 10 import { LeftCircleOutlined } from '@ant-design/icons';
11 11 import { postDetailApi } from '../api';
12 12 import usePagination from '@/hooks/usePagination';
13 13 import { PersonStatus, PersonStatusColor } from '@/pages/ehr/PersonManage/entity';
14 14  
15 15 export default function IndexDetail() {
16   - const { currentPostItem, setCurrentPostItem, breadcrumbs, setBreadcrumbs, setCurrentBreadcrumb, isShopGoToDetail } = useStore();
  16 + const { currentPostItem, setCurrentPostItem, breadcrumbs, setBreadcrumbs, setCurrentBreadcrumb, isShopGoToDetail, ChangeType, ChangeTypeColor } =
  17 + useStore();
17 18 const { list, paginationConfig, loading } = usePagination(postDetailApi, {
18 19 postId: (currentPostItem && currentPostItem.id) || 0,
19 20 });
... ... @@ -30,6 +31,7 @@ export default function IndexDetail() {
30 31 <>
31 32 <Row justify="space-between" style={{ marginBottom: 20 }}>
32 33 <span style={{ display: 'inline-block', marginBottom: 20, fontSize: 16 }}>合计:{paginationConfig.total || 0}&nbsp;&nbsp;人</span>
  34 + {/* @ts-ignore */}
33 35 <Button icon={<LeftCircleOutlined />} type="link" onClick={getBack}>
34 36 返回
35 37 </Button>
... ... @@ -45,9 +47,13 @@ export default function IndexDetail() {
45 47 title="人员状态"
46 48 dataIndex="staffStatus"
47 49 align="center"
48   - render={(staffStatus: number) =>
49   - staffStatus ? <span style={{ color: PersonStatusColor[staffStatus] || '#000' }}>{PersonStatus[staffStatus]}</span> : '-'
50   - }
  50 + render={(staffStatus: number) => (staffStatus ? <Badge color={PersonStatusColor[staffStatus]} text={PersonStatus[staffStatus]} /> : '-')}
  51 + />
  52 + <Table.Column
  53 + title="人员变动状态"
  54 + dataIndex="changeType"
  55 + align="center"
  56 + render={(changeType: number) => (changeType ? <Badge color={ChangeTypeColor[changeType]} text={ChangeType[changeType]} /> : '-')}
51 57 />
52 58 <Table.Column
53 59 title="门店"
... ...
src/pages/ehr/PostSetting/components/IndexShop/ShopList.tsx
1 1 import React from 'react';
2   -import { Row, Popconfirm, message, Divider, Radio, Tag, Table } from 'antd';
  2 +import { Row, Popconfirm, message, Divider, Radio, Tag, Table, Popover } from 'antd';
  3 +import { InfoCircleOutlined } from '@ant-design/icons';
3 4 import { useStore } from '../../index';
4 5 import Modal from './ShopModal';
5 6 import { cancelApprovalApi, deleteShopPostApi, postLimitApi } from '../../api';
... ... @@ -120,7 +121,19 @@ export default function ShopList() {
120 121 title="当前在岗数"
121 122 dataIndex="postNum"
122 123 align="left"
123   - render={(num: number, item: PostSetting.ShopList) => <a onClick={() => detailClick(item)}>{priceToThousands(num, 0)} 人</a>}
  124 + render={(num: number, item: PostSetting.ShopList) =>
  125 + item.remark ? (
  126 + <Popover content={item.remark} title="提示" placement="topLeft">
  127 + <Row align="middle" style={{ gap: 10 }}>
  128 + <a onClick={() => detailClick(item)}>{priceToThousands(num, 0)} 人</a>
  129 + {/* @ts-ignore */}
  130 + <InfoCircleOutlined style={{ color: 'var(--antd-wave-shadow-color)' }} />
  131 + </Row>
  132 + </Popover>
  133 + ) : (
  134 + <a onClick={() => detailClick(item)}>{priceToThousands(num, 0)} 人</a>
  135 + )
  136 + }
124 137 />
125 138 ) : (
126 139 <Table.Column title="原定岗数" dataIndex="oldLimitNum" align="left" render={(num: number) => `${priceToThousands(num, 0)} 人`} />
... ...
src/pages/ehr/PostSetting/interface.d.ts
... ... @@ -51,6 +51,7 @@ declare namespace PostSetting {
51 51 auditNo?: string;
52 52 oldLimitNum?: number; // 原岗位标准限制人数
53 53 status?: number; // 状态 1草稿 2待审批 3审批拒绝 4审批通过 5撤销审批
  54 + remark?: string; // 提示,有则需要提示
54 55 }
55 56  
56 57 interface PostLimit {
... ... @@ -77,6 +78,7 @@ declare namespace PostSetting {
77 78 salaryShopId?: number; // 薪资发放门店id
78 79 salaryShopName?: string; // 薪资发放门店名称
79 80 staffStatus?: number;
  81 + changeType?: number; // 2 调岗位
80 82 }
81 83  
82 84 type PostLevel = '业务岗位' | '初级管理岗' | '中级管理岗' | '高级管理岗';
... ...
src/pages/ehr/PostSetting/store.ts
... ... @@ -69,6 +69,18 @@ export default function useStore() {
69 69 '#FF921C',
70 70 }
71 71  
  72 + enum ChangeType {
  73 + 调角色 = 1,
  74 + 调岗位 = 2,
  75 + 离职 = 3
  76 + }
  77 +
  78 + enum ChangeTypeColor {
  79 + '#FF921C' = 1,
  80 + '#4189FD' = 2,
  81 + '#F4333C' = 3,
  82 + }
  83 +
72 84 useEffect(() => {
73 85 // // 仅查询流程角色 roleType = 2
74 86 getAllRoleCodeApi({ roleType: 2 }).then((res) => {
... ... @@ -120,5 +132,7 @@ export default function useStore() {
120 132 roleList,
121 133 Status,
122 134 StatusColor,
  135 + ChangeType,
  136 + ChangeTypeColor
123 137 };
124 138 }
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/api.ts
1   -import request from "@/utils/request";
2   -import { ABILITY_HOST } from "@/utils/host";
3   -import { http } from "@/typing/http";
  1 +import request from '@/utils/request';
  2 +import { ABILITY_HOST } from '@/utils/host';
  3 +import type { http } from '@/typing/http';
4 4  
5 5 /** 获取题库列表 */
6   -export function getQuestionBankListApi(
7   - params: QuestionBank.QueryParams
8   -): http.PromisePageResp<QuestionBank.List> {
  6 +export function getQuestionBankListApi(params: QuestionBank.QueryParams): http.PromisePageResp<QuestionBank.List> {
9 7 return request.get(`${ABILITY_HOST}/erp/question/factory/list`, { params });
10 8 }
11 9  
... ... @@ -22,9 +20,7 @@ export function deleteQuestionBankApi(id: number) {
22 20 }
23 21  
24 22 /** 获取题目列表 */
25   -export function getQuestionListApi(params: {
26   - factoryId: number;
27   -}): http.PromisePageResp<QuestionBank.Question> {
  23 +export function getQuestionListApi(params: { factoryId: number }): http.PromisePageResp<QuestionBank.Question> {
28 24 return request.get(`${ABILITY_HOST}/erp/question/info/list`, { params });
29 25 }
30 26  
... ... @@ -45,11 +41,7 @@ export function deleteQuestionApi(id: number) {
45 41 * @param {QuestionBank.ImportQuestionParams} params
46 42 */
47 43 export function importQuestionApi(params: QuestionBank.ImportQuestionParams) {
48   - return request.post<string>(
49   - `${ABILITY_HOST}/erp/question/import/excel`,
50   - params,
51   - { contentType: "form-data" }
52   - );
  44 + return request.post<string>(`${ABILITY_HOST}/erp/question/import/excel`, params, { contentType: 'form-data' });
53 45 }
54 46  
55 47 /**
... ... @@ -57,9 +49,7 @@ export function importQuestionApi(params: QuestionBank.ImportQuestionParams) {
57 49 * @param {QuestionBank.QueryParams} params
58 50 * @return {http.PromisePageResp<QuestionBank.List>}
59 51 */
60   -export function getDraftListApi(
61   - params: QuestionBank.QueryParams
62   -): http.PromisePageResp<QuestionBank.List> {
  52 +export function getDraftListApi(params: QuestionBank.QueryParams): http.PromisePageResp<QuestionBank.List> {
63 53 return request.get(`${ABILITY_HOST}/erp/draft/page`, { params });
64 54 }
65 55  
... ... @@ -68,9 +58,7 @@ export function getDraftListApi(
68 58 * @param {QuestionBank.List} params
69 59 * @return {http.PromiseResp<string>}
70 60 */
71   -export function saveDraftApi(
72   - params: QuestionBank.List
73   -): http.PromiseResp<string> {
  61 +export function saveDraftApi(params: QuestionBank.List): http.PromiseResp<string> {
74 62 return request.post(`${ABILITY_HOST}/erp/draft/save`, params);
75 63 }
76 64  
... ... @@ -79,9 +67,7 @@ export function saveDraftApi(
79 67 * @param {number} factoryId
80 68 * @return {http.PromiseResp<QuestionBank.List>}
81 69 */
82   -export function getDraftByFactoryIdApi(
83   - factoryId: number
84   -): http.PromiseResp<QuestionBank.List> {
  70 +export function getDraftByFactoryIdApi(factoryId: number): http.PromiseResp<QuestionBank.List> {
85 71 return request.get(`${ABILITY_HOST}/erp/draft/by/factory`, {
86 72 params: { factoryId },
87 73 });
... ... @@ -103,9 +89,7 @@ export function deleteDraftApi(draftId: number): http.PromiseResp&lt;string&gt; {
103 89 * @param {QuestionBank.DraftQuestionParams} params
104 90 * @return {http.PromiseRespA<QuestionBank.Question>}
105 91 */
106   -export function getQuestionListByDraftApi(
107   - params: QuestionBank.DraftQuestionParams
108   -): http.PromiseRespA<QuestionBank.Question> {
  92 +export function getQuestionListByDraftApi(params: QuestionBank.DraftQuestionParams): http.PromiseRespA<QuestionBank.Question> {
109 93 return request.get(`${ABILITY_HOST}/erp/draft/question/list`, {
110 94 params,
111 95 });
... ... @@ -116,9 +100,7 @@ export function getQuestionListByDraftApi(
116 100 * @param {QuestionBank.Question} params
117 101 * @return {http.PromiseResp<number>}
118 102 */
119   -export function saveDraftQuestionApi(
120   - params: QuestionBank.Question
121   -): http.PromiseResp<number> {
  103 +export function saveDraftQuestionApi(params: QuestionBank.Question): http.PromiseResp<number> {
122 104 return request.post(`${ABILITY_HOST}/erp/draft/question/save`, params);
123 105 }
124 106  
... ... @@ -127,9 +109,7 @@ export function saveDraftQuestionApi(
127 109 * @param {QuestionBank.DeleteDraftQuestionParams} params
128 110 * @return {http.PromiseResp<string>}
129 111 */
130   -export function deleteDraftQuestionApi(
131   - params: QuestionBank.DeleteDraftQuestionParams
132   -): http.PromiseResp<string> {
  112 +export function deleteDraftQuestionApi(params: QuestionBank.DeleteDraftQuestionParams): http.PromiseResp<string> {
133 113 return request.post(`${ABILITY_HOST}/erp/draft/question/remove`, params);
134 114 }
135 115  
... ... @@ -138,13 +118,8 @@ export function deleteDraftQuestionApi(
138 118 * @param {QuestionBank.BatchDeleteDraftQuestionParams} params
139 119 * @return {http.PromiseResp<string>}
140 120 */
141   -export function batchDeleteDraftQuestionApi(
142   - params: QuestionBank.BatchDeleteDraftQuestionParams
143   -): http.PromiseResp<string> {
144   - return request.post(
145   - `${ABILITY_HOST}/erp/draft/question/batch/remove`,
146   - params
147   - );
  121 +export function batchDeleteDraftQuestionApi(params: QuestionBank.BatchDeleteDraftQuestionParams): http.PromiseResp<string> {
  122 + return request.post(`${ABILITY_HOST}/erp/draft/question/batch/remove`, params);
148 123 }
149 124  
150 125 /**
... ... @@ -152,9 +127,7 @@ export function batchDeleteDraftQuestionApi(
152 127 * @param {number} draftId
153 128 * @return {http.PromiseResp<string>}
154 129 */
155   -export function deleteAllDraftQuestionApi(
156   - draftId: number
157   -): http.PromiseResp<string> {
  130 +export function deleteAllDraftQuestionApi(draftId: number): http.PromiseResp<string> {
158 131 return request.get(`${ABILITY_HOST}/erp/draft/question/all/remove`, {
159 132 params: { draftId },
160 133 });
... ... @@ -166,11 +139,7 @@ export function deleteAllDraftQuestionApi(
166 139 * @return {http.PromiseResp<string>}
167 140 */
168 141 export function approvalDraftApi(draftId: number): http.PromiseResp<string> {
169   - return request.post(
170   - `${ABILITY_HOST}/erp/draft/submit`,
171   - { draftId },
172   - { contentType: "form-data" }
173   - );
  142 + return request.post(`${ABILITY_HOST}/erp/draft/submit`, { draftId }, { contentType: 'form-data' });
174 143 }
175 144  
176 145 /**
... ... @@ -178,9 +147,7 @@ export function approvalDraftApi(draftId: number): http.PromiseResp&lt;string&gt; {
178 147 * @param {number} factoryId
179 148 * @return {*}
180 149 */
181   -export function exportQuestionBankApi(
182   - factoryId: number
183   -): http.PromiseResp<BlobPart> {
  150 +export function exportQuestionBankApi(factoryId: number): http.PromiseResp<BlobPart> {
184 151 return request.get(`${ABILITY_HOST}/erp/question/export/question`, {
185 152 params: { factoryId },
186 153 });
... ... @@ -202,10 +169,17 @@ export function exportDraftApi(draftId: number): http.PromiseResp&lt;BlobPart&gt; {
202 169 * @param {QuestionBank.ImportQuestionParams} params
203 170 * @return {http.PromiseResp<string>}
204 171 */
205   -export function importDraftQuestionApi(
206   - params: QuestionBank.ImportQuestionParams
207   -): http.PromiseResp<string> {
  172 +export function importDraftQuestionApi(params: QuestionBank.ImportQuestionParams): http.PromiseResp<string> {
208 173 return request.post(`${ABILITY_HOST}/erp/draft/import/excel`, params, {
209   - contentType: "form-data",
  174 + contentType: 'form-data',
210 175 });
211 176 }
  177 +
  178 +/**
  179 + * @description: 撤销草稿审批
  180 + * @param {string} auditNo
  181 + * @return {http.PromiseResp<string>}
  182 + */
  183 +export function cancelDraftApprovalApi(auditNo: string): http.PromiseResp<string> {
  184 + return request.get(`${ABILITY_HOST}/erp/draft/cancel/audit`, { params: { auditNo } });
  185 +}
... ...
src/pages/ehr/ProgramOfStudy/QuestionBank/components/QuestionBankList/components/DraftList/index.tsx
1 1 /*
2 2 * @Date: 2021-07-26 17:19:45
3 3 * @LastEditors: wangqiang@feewee.cn
4   - * @LastEditTime: 2023-09-02 15:51:55
  4 + * @LastEditTime: 2024-03-29 16:46:18
5 5 */
6 6 import React, { useEffect } from 'react';
7 7 import { useStore } from '../../../../index';
8   -import { deleteDraftApi, approvalDraftApi } from '../../../../api';
  8 +import { deleteDraftApi, approvalDraftApi, cancelDraftApprovalApi } from '../../../../api';
9 9 import { Badge, Button, Divider, Input, message, Modal, Popconfirm, Row, Table } from 'antd';
10 10 import { PlusOutlined } from '@ant-design/icons';
11 11 import QuestionBankModal from '../../QuestionBankModal';
... ... @@ -92,6 +92,19 @@ export default function DraftList() {
92 92 message.error(error.message);
93 93 });
94 94 };
  95 + const cancelApprovalDraft = (auditNo: string) => {
  96 + const hide = message.loading('撤销中,请稍后...', 0);
  97 + cancelDraftApprovalApi(auditNo)
  98 + .then((res) => {
  99 + hide();
  100 + message.success(res.result);
  101 + setLoading(true);
  102 + })
  103 + .catch((error) => {
  104 + hide();
  105 + message.error(error.message);
  106 + });
  107 + };
95 108  
96 109 return (
97 110 <>
... ... @@ -210,7 +223,14 @@ export default function DraftList() {
210 223 <Divider type="vertical" />
211 224 </>
212 225 ) : null}
213   - {record.status === StatusText.审批中 ? null : (
  226 + {record.status === StatusText.审批中 ? (
  227 + <>
  228 + <Popconfirm title={`确定撤销【${record.name}】审批?`} onConfirm={() => cancelApprovalDraft(record.auditNo ?? '')}>
  229 + <a style={{ color: 'red' }}>撤销审批</a>
  230 + </Popconfirm>
  231 + <Divider type="vertical" />
  232 + </>
  233 + ) : (
214 234 <>
215 235 <a
216 236 onClick={() => {
... ...
src/pages/finance/BasicConfig/FinanceType/components/CreateModal.tsx
... ... @@ -164,6 +164,12 @@ export default function CreateModal() {
164 164 <Radio value={false}>否</Radio>
165 165 </Radio.Group>
166 166 </FormItem>
  167 + <FormItem label="是否支持主动报销" name='canMainReimburse' initialValue={false} rules={[{ required: true, message: '请选择' }]}>
  168 + <Radio.Group>
  169 + <Radio value>是</Radio>
  170 + <Radio value={false}>否</Radio>
  171 + </Radio.Group>
  172 + </FormItem>
167 173 </Form>
168 174 </Modal>
169 175 );
... ...
src/pages/finance/BasicConfig/FinanceType/index.tsx
... ... @@ -59,6 +59,7 @@ function FinanceType() {
59 59 <Column width={140} title="是否支持划扣" dataIndex="abatement" render={(value: boolean) => (value ? '是' : '否')} />
60 60 <Column width={160} title="划扣是否生成费用" dataIndex="abatementCanCost" render={(value: boolean) => (value ? '是' : '否')} />
61 61 <Column title="是否支持代垫" dataIndex="disbursements" render={(value: boolean) => (value ? '是' : '否')} />
  62 + <Column title="是否支持主动报销" dataIndex="canMainReimburse" render={(value: boolean) => (value ? '是' : '否')} />
62 63 <Column
63 64 title="操作"
64 65 align="center"
... ...
src/pages/finance/FinanceInvestor/api.ts
... ... @@ -8,7 +8,8 @@ type PrRes&lt;T&gt; = http.PromiseResp&lt;T&gt;;
8 8 * 获取数据列表
9 9 */
10 10 export function getFinanceSubjectApi(): PrRes<FinanceSubject.SubjectList[]> {
11   - return request.get(`${FINANCE2_HOST}/investment/subject/list`);
  11 + // return request.get(`${FINANCE2_HOST}/investment/subject/list`);
  12 + return request.get(`${FINANCE2_HOST}/config/investment/subject/list`);
12 13 }
13 14  
14 15 /**
... ...
src/pages/finance/PaymentAllocation/components/ApitalModal.tsx
1   -import React, { useState, useEffect } from "react";
  1 +import React, { useState, useEffect, useMemo } from "react";
2 2 import { Modal, Form, Input, Select, message, Radio } from "antd";
3 3 import { useStore } from "../index";
4 4 import { getRpTypeConfigSaveApi, commonRpTypesApi, RpTypesItem } from "../api";
5 5 import useInitial from "@/hooks/useInitail";
6   -import { CapitalAccountTypeEnum, ConfigType, ConfigTypeEnum, FinanceBankAccountTypeEnum, ProcessMode, ProcessModeEnum } from "@/pages/finance/entitys";
  6 +import { ConfigType, ConfigTypeEnum, ProcessMode, ProcessMode2, ProcessModeEnum } from "@/pages/finance/entitys";
7 7 import { getCompanyBusinessTypesApi } from "@/pages/finance/TradeCompany/api";
8 8 import { getAllRoleCodeApi } from "@/common/api";
9 9 import { Label } from "bizcharts";
... ... @@ -21,6 +21,7 @@ export default function CreateModal() {
21 21 const { visible, setVisible, current, setCurrent, setLoading, } =
22 22 useStore();
23 23 const [delay, setDelay] = useState(true);
  24 + const [configValue, setConfigValue] = useState();
24 25  
25 26 // 查询收支类型(款项)
26 27 const { data, setParams: setRpTypesParams, params: rpTypesParams } = useInitial<RpTypesItem[], any>(commonRpTypesApi, [], {}, delay);
... ... @@ -79,12 +80,16 @@ export default function CreateModal() {
79 80 })
80 81 .catch((e) => {
81 82 message.error(e.message);
82   - }).finally(()=>setSaveLoading(false));
  83 + }).finally(() => setSaveLoading(false));
83 84 }
84 85  
85 86 function onCancel() {
86 87 setVisible(false);
87 88 }
  89 + const processMode = useMemo(() => {
  90 + if (!visible) setConfigValue(undefined);
  91 + return (current.configType == 5 || configValue==5) ? ProcessMode2 : ProcessMode;
  92 + }, [configValue, visible, current])
88 93  
89 94 return (
90 95 <Modal
... ... @@ -106,6 +111,7 @@ export default function CreateModal() {
106 111 if (type) {
107 112 setRpTypesParams({ ...rpTypesParams, ConfigType: type }, true);
108 113 setDelay(false);
  114 + setConfigValue(type)
109 115 //切换款项配置类型,清空已选款项
110 116 form.setFieldValue("typeValue", undefined);
111 117 }
... ... @@ -127,15 +133,18 @@ export default function CreateModal() {
127 133 ))}
128 134 </Select>
129 135 </FormItem>
130   - <FormItem name="processMode" label="款项处理" rules={[{ required: true, message: "请选择款项处理方式" }]}>
131   - <Select placeholder="请选择款项处理方式" showSearch optionFilterProp="children">
132   - {ProcessMode.map((item) => (
133   - <Option key={item.value} value={item.value}>
134   - {item.label}
135   - </Option>
136   - ))}
137   - </Select>
138   - </FormItem>
  136 + {
  137 + (configValue || current.id) &&
  138 + <FormItem name="processMode" label="款项处理" rules={[{ required: true, message: "请选择款项处理方式" }]}>
  139 + <Select placeholder="请选择款项处理方式" showSearch optionFilterProp="children">
  140 + {processMode.map((item) => (
  141 + <Option key={item.value} value={item.value}>
  142 + {item.label}
  143 + </Option>
  144 + ))}
  145 + </Select>
  146 + </FormItem>
  147 + }
139 148 <FormItem noStyle shouldUpdate={(prevValues, curValues) => (prevValues.processMode !== curValues.processMode) || (prevValues.configType !== curValues.configType)}>
140 149 {({ getFieldValue }) => {
141 150 const _processMode = (getFieldValue("processMode") || {});
... ...
src/pages/finance/SpecialAccount/FinancingCompany/components/CreateModal.tsx
... ... @@ -83,14 +83,14 @@ export default function CreateModal() {
83 83 }
84 84  
85 85 function submit(fieldValue: any) {
86   - if (
87   - fieldValue.depositAccount &&
88   - fieldValue?.account &&
89   - fieldValue.depositAccount.value === fieldValue?.account.value
90   - ) {
91   - message.error("还款保证金账户、一般账户请勿配置为同一账户", 1.5);
92   - return;
93   - }
  86 + // if (
  87 + // fieldValue.depositAccount &&
  88 + // fieldValue?.account &&
  89 + // fieldValue.depositAccount.value === fieldValue?.account.value
  90 + // ) {
  91 + // message.error("还款保证金账户、一般账户请勿配置为同一账户", 1.5);
  92 + // return;
  93 + // }
94 94 const param = {
95 95 dealerId,
96 96 ...fieldValue,
... ...
src/pages/finance/entitys.ts
... ... @@ -225,6 +225,7 @@ export enum ConfigTypeEnum {
225 225 // '付款申请',
226 226 '缴费申请' = 3,
227 227 '付款申请' = 4,
  228 + '主动报销' = 5,
228 229 }
229 230  
230 231 export const ConfigType = [
... ... @@ -244,6 +245,10 @@ export const ConfigType = [
244 245 label: '付款申请',
245 246 value: ConfigTypeEnum['付款申请'],
246 247 },
  248 + {
  249 + label: '主动报销',
  250 + value: ConfigTypeEnum['主动报销'],
  251 + },
247 252 ];
248 253 /**
249 254 * 款项处理方式
... ... @@ -277,6 +282,16 @@ export const ProcessMode = [
277 282 value: ProcessModeEnum['生成预付款'],
278 283 },
279 284 ];
  285 +export const ProcessMode2 = [
  286 + {
  287 + label: '默认',
  288 + value: ProcessModeEnum['默认'],
  289 + },
  290 + {
  291 + label: '生成费用',
  292 + value: ProcessModeEnum['生成费用'],
  293 + },
  294 +];
280 295  
281 296 /** 财务角色码 */
282 297 export enum FinanceRoleCode {
... ...
src/pages/stock/DirectVehicles/api.ts
... ... @@ -36,7 +36,8 @@ export function saveRebateApi(params: DirectVehicles.ListItem): PromiseResp&lt;null
36 36 * 获取投资主体数据列表
37 37 */
38 38 export function getFinanceSubjectApi(): PromiseResp<FinanceSubject.SubjectList[]> {
39   - return request.get(`${FINANCE2_HOST}/investment/subject/list`);
  39 + // return request.get(`${FINANCE2_HOST}/investment/subject/list`);
  40 + return request.get(`${FINANCE2_HOST}/config/investment/subject/list`);
40 41 }
41 42 /**
42 43 * 直营车现金折让提交确认
... ...
src/pages/trial/SystemSettings/OilSettings/index.tsx
1 1 import React, { useEffect, useState } from "react";
  2 +import type {
  3 + DatePickerProps
  4 +} from "antd";
2 5 import {
3   - DatePickerProps,
4 6 InputNumber,
5 7 Row,
6 8 Card,
... ... @@ -13,9 +15,11 @@ import {
13 15 Switch,
14 16 } from "antd";
15 17 import { PageHeaderWrapper } from "@ant-design/pro-layout";
  18 +import type {
  19 + ListVO
  20 +} from "./api";
16 21 import {
17 22 getOilListApi,
18   - ListVO,
19 23 saveOilListApi,
20 24 getIsEditStatusApi,
21 25 saveIsEditStatusApi,
... ... @@ -56,7 +60,7 @@ export default function OilSettings() {
56 60  
57 61 const onChange: DatePickerProps["onChange"] = (date, dateString) => {
58 62 setSaveDate(dateString);
59   - let newDataString = dateString.split("-");
  63 + const newDataString = dateString.split("-");
60 64 setParams(
61 65 {
62 66 year: Number(newDataString[0]),
... ... @@ -65,7 +69,7 @@ export default function OilSettings() {
65 69 true
66 70 );
67 71 };
68   -
  72 +
69 73 function handleSubmit() {
70 74 setConfirmLoading(true);
71 75 saveOilListApi(data.vos!)
... ... @@ -91,7 +95,7 @@ export default function OilSettings() {
91 95 };
92 96 const changeOilPrice = (id: number, value: number) => {
93 97 if (value === undefined) return;
94   - let newList = data?.vos.map((item) => {
  98 + const newList = data?.vos.map((item) => {
95 99 if (item.id === id) {
96 100 return { ...item, price: value };
97 101 }
... ... @@ -111,7 +115,7 @@ export default function OilSettings() {
111 115 return (
112 116 <PageHeaderWrapper title="油价设置">
113 117 <Spin spinning={loading}>
114   - <Card loading={loading} style={{height: 420}}>
  118 + <Card loading={loading} style={{ height: 420 }}>
115 119 <div
116 120 style={{
117 121 display: "flex",
... ... @@ -126,19 +130,19 @@ export default function OilSettings() {
126 130 picker="month"
127 131 disabledDate={disabledDate}
128 132 />
129   - <div style={{display: "flex", alignItems: "center"}}>
  133 + {/* <div style={{display: "flex", alignItems: "center"}}>
130 134 <span>整点自动获取油价:</span>
131 135 <Switch
132 136 checked={isEdit === IsEdit["自动获取油价"]}
133 137 onChange={changeStatus}
134 138 />
135   - </div>
  139 + </div> */}
136 140 </div>
137 141 <List
138 142 dataSource={data?.vos}
139 143 style={{ display: "flex", alignItems: "center", marginTop: 20 }}
140 144 renderItem={(item: ListVO) => (
141   - <List.Item style={{display: "flex", alignItems: "center", justifyContent: "space-between", height: 57, width: 400}}>
  145 + <List.Item style={{ display: "flex", alignItems: "center", justifyContent: "space-between", height: 57, width: 400 }}>
142 146 <span style={{ width: 100 }}>
143 147 {item.typeDesc}
144 148 </span>
... ... @@ -159,8 +163,8 @@ export default function OilSettings() {
159 163 value={item.price}
160 164 disabled={!edit}
161 165 onChange={(value) => {
162   - changeOilPrice(item.id, value);
163   - }}
  166 + changeOilPrice(item.id, value);
  167 + }}
164 168 />
165 169 <span style={{ margin: "0 10px" }}>元/升</span>
166 170 </Row>
... ...