From 846a41c6df5fbb6017283570c86b87139fe1efef Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Wed, 4 Nov 2026 16:04:38 +0800 Subject: [PATCH 01/11] =?UTF-8?q?:bug:=20=E4=BF=9D=E7=95=99=E6=AF=9B?= =?UTF-8?q?=E5=88=A9=E6=8A=A5=E8=A1=A8=E6=9A=82=E5=81=9C=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bms/price/domain/vo/PrcProfitReportQuery.java | 2 ++ .../bms/price/service/impl/PrcProfitReportServiceImpl.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java index ab072bdf..8a9b4a09 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java @@ -35,4 +35,6 @@ public class PrcProfitReportQuery extends BaseEntity private String arBillStatus; /** 是否按产品维度分组值下钻订单明细,允许分组字段为空。 */ private Boolean productDrilldown; + /** 仅用于拒绝已暂停的提成未计算订单下钻请求。 */ + private String detailType; } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcProfitReportServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcProfitReportServiceImpl.java index 9ed6a667..8ab3023c 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcProfitReportServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcProfitReportServiceImpl.java @@ -107,6 +107,10 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService { return; } + if ("COMMISSION_MISSING".equals(query.getDetailType())) + { + throw new ServiceException("提成功能已暂停使用"); + } query.setOrderNos(splitFilterValues(query.getOrderNo(), "订单号")); query.setCustomerCodes(splitFilterValues(query.getCustomerCode(), "客户代码")); query.setCustomerNames(splitFilterValues(query.getCustomerName(), "客户名称")); From 942d5932aee0f5b9e1f462c4dd50d7c8015cb541 Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Wed, 4 Nov 2026 18:29:47 +0800 Subject: [PATCH 02/11] =?UTF-8?q?:sparkles:=20=E5=90=8C=E6=AD=A5=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E5=8C=BA=E5=9F=9F=E5=AD=97=E6=AE=B5=E5=B9=B6=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E5=AD=97=E5=85=B8=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../customerinfo/domain/BmsCustomer.java | 6 +- .../impl/BmsCustomerLogServiceImpl.java | 14 +- .../sync/CustomerSyncService.java | 2 + .../mapper/customer/BmsCustomerMapper.xml | 12 +- .../mapper/customer/CustomerSyncMapper.xml | 3 + .../customer/OracleCustomerSyncMapper.xml | 2 +- bms-back/sql/bms_init.sql | 2 +- .../20261030_customer_area_type.sql | 11 -- .../20261104_customer_area_rename.sql | 173 ++++++++++++++++++ .../customerinfo/customeredit/index.vue | 10 +- .../customerinfo/index.vue | 20 +- 11 files changed, 211 insertions(+), 44 deletions(-) delete mode 100644 bms-back/sql/customer+supplier/20261030_customer_area_type.sql create mode 100644 bms-back/sql/customer+supplier/20261104_customer_area_rename.sql diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomer.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomer.java index e78df049..1d67cbb4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomer.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomer.java @@ -47,9 +47,9 @@ public class BmsCustomer extends BaseEntity @Excel(name = "业务类型", readConverterExp = "0=直客,1=同行,2=集运") private String customerType; - /** 区域类型(字典 data_area_type) */ - @Excel(name = "区域类型", dictType = "data_area_type") - private String areaType; + /** 客户区域(字典 customer_area) */ + @Excel(name = "客户区域", dictType = "customer_area") + private String customerArea; /** 启用状态(0正常 1停用) */ @Excel(name = "启用状态", readConverterExp = "0=正常,1=停用") diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerLogServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerLogServiceImpl.java index 43bd4133..fbc69aae 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerLogServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerLogServiceImpl.java @@ -45,10 +45,10 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService private static final ThreadLocal DATE_FMT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd")); - /** 区域类型走字典 data_area_type;缓存未命中时保留原编码。 */ - private static String areaTypeLabel(String value) + /** 客户区域走字典 customer_area;缓存未命中时保留原编码。 */ + private static String customerAreaLabel(String value) { - String label = DictUtils.getDictLabel("data_area_type", value); + String label = DictUtils.getDictLabel("customer_area", value); return StringUtils.isEmpty(label) ? value : label; } @@ -77,7 +77,7 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService /** * 需要记录日志的主表字段(顺序即展示顺序)。 * requireNonBlank 为 true 的字段对应 update SQL 的 <if test="x!=null and x!=''">, - * 其余动态字段仅在新值非 null 时落库;业务员/结算员/客服、区域类型为无条件写入。 + * 其余动态字段仅在新值非 null 时落库;业务员/结算员/客服、客户区域为无条件写入。 */ private static final List FIELD_DEFS = List.of( new FieldDef("customerCode", "客户编码", BmsCustomer::getCustomerCode, true, Function.identity()), @@ -85,7 +85,7 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService new FieldDef("customerCodeDw", "对外代码", BmsCustomer::getCustomerCodeDw, false, Function.identity()), new FieldDef("creditCode", "统一社会信用代码", BmsCustomer::getCreditCode, false, Function.identity()), new FieldDef("customerType", "业务类型", BmsCustomer::getCustomerType, false, CUSTOMER_TYPE_MAP::get), - new FieldDef("areaType", "区域类型", BmsCustomer::getAreaType, false, BmsCustomerLogServiceImpl::areaTypeLabel), + new FieldDef("customerArea", "客户区域", BmsCustomer::getCustomerArea, false, BmsCustomerLogServiceImpl::customerAreaLabel), new FieldDef("isEnable", "启用状态", BmsCustomer::getIsEnable, false, ENABLE_MAP::get), new FieldDef("salesUserId", "业务员", c -> userDisplay(c.getSalesUserId(), c.getSalesUser()), false, Function.identity()), new FieldDef("ed", "资金额度(元)", BmsCustomer::getEd, false, BmsCustomerLogServiceImpl::numText), @@ -208,8 +208,8 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService { // 与 update SQL 的动态条件保持一致:未提交(null/空串)的字段本次不落库,不参与比对 Object raw = def.rawGetter.apply(newCustomer); - // 合同起止、区域类型允许清空;其余动态字段未提交时不落库,也不记日志 - if (raw == null && !isContractDateField(def.field) && !"areaType".equals(def.field)) + // 合同起止、客户区域允许清空;其余动态字段未提交时不落库,也不记日志 + if (raw == null && !isContractDateField(def.field) && !"customerArea".equals(def.field)) { continue; } diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/sync/CustomerSyncService.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/sync/CustomerSyncService.java index 9b45cb26..ccce88fd 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/sync/CustomerSyncService.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/sync/CustomerSyncService.java @@ -60,6 +60,7 @@ public class CustomerSyncService private static final int LEN_CODE = 50; private static final int LEN_NAME = 100; private static final int LEN_CODE_DW = 50; + private static final int LEN_CUSTOMER_AREA = 32; private static final int LEN_USER = 50; private static final int LEN_REMARK = 500; /** 告警明细最多打印条数 */ @@ -178,6 +179,7 @@ public class CustomerSyncService c.setDelFlag("0"); c.setCustomerCodeDw(truncate(getStr(row, "CUSTOMER_OUTER_CODE"), LEN_CODE_DW, code, "customer_code_dw", warnings)); + c.setCustomerArea(truncate(getStr(row, "CUSTOMER_AREA"), LEN_CUSTOMER_AREA, code, "customer_area", warnings)); String sourceSalesCode = clean(getStr(row, "BELONG_SALER")); c.setSourceSalesCode(sourceSalesCode); c.setSalesUserId(resolveSalesUserId(sourceSalesCode, userIdsByLogin, diff --git a/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml b/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml index fbbf8b95..8f35acbb 100644 --- a/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml @@ -11,7 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -45,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select c.customer_id, c.customer_code, c.customer_name, c.customer_code_dw, c.credit_code, c.customer_type, c.area_type, + select c.customer_id, c.customer_code, c.customer_name, c.customer_code_dw, c.credit_code, c.customer_type, c.customer_area, c.is_enable, case when su.user_id is not null then cast(su.user_id as char) else null end as sales_user_id, su.nick_name as sales_user, c.ed, c.zq, c.settlement_user_id, c.settlement_user, @@ -92,7 +92,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and c.credit_code = #{creditCode} and c.customer_type = #{customerType} - and c.area_type = #{areaType} + and c.customer_area = #{customerArea} and c.is_enable = #{isEnable} and c.sales_user_id = #{salesUserId} and su.nick_name = #{salesUser} @@ -317,7 +317,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" customer_code_dw, credit_code, customer_type, - area_type, + customer_area, is_enable, sales_user_id, sales_user, @@ -350,7 +350,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{customerCodeDw}, #{creditCode}, #{customerType}, - #{areaType}, + #{customerArea}, #{isEnable}, #{salesUserId}, #{salesUser}, @@ -387,7 +387,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" customer_code_dw = #{customerCodeDw}, credit_code = #{creditCode}, customer_type = #{customerType}, - area_type = #{areaType}, + customer_area = #{customerArea}, is_enable = #{isEnable}, sales_user_id = #{salesUserId}, sales_user = #{salesUser}, diff --git a/bms-back/bms-system/src/main/resources/mapper/customer/CustomerSyncMapper.xml b/bms-back/bms-system/src/main/resources/mapper/customer/CustomerSyncMapper.xml index 6bd7222d..44913610 100644 --- a/bms-back/bms-system/src/main/resources/mapper/customer/CustomerSyncMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/customer/CustomerSyncMapper.xml @@ -30,6 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" del_flag, create_by, sales_user_id, source_sales_code , customer_code_dw , customer_type + , customer_area , sales_user , settlement_user , service_user @@ -46,6 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" '0', #{createBy}, #{salesUserId}, #{sourceSalesCode} , #{customerCodeDw} , #{customerType} + , #{customerArea} , #{salesUser} , #{settlementUser} , #{serviceUser} @@ -66,6 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" , customer_name = #{customerName} , customer_code_dw = #{customerCodeDw} , customer_type = #{customerType} + , customer_area = #{customerArea} , sales_user_id = #{salesUserId} , source_sales_code = #{sourceSalesCode} , sales_user = #{salesUser} diff --git a/bms-back/bms-system/src/main/resources/mapper/customer/OracleCustomerSyncMapper.xml b/bms-back/bms-system/src/main/resources/mapper/customer/OracleCustomerSyncMapper.xml index 0aad5a20..ecd510ed 100644 --- a/bms-back/bms-system/src/main/resources/mapper/customer/OracleCustomerSyncMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/customer/OracleCustomerSyncMapper.xml @@ -10,7 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" BELONG_SALER, BELONG_SALER_NAME, SETTLEMENT_MAN, SERVICE_MAN, REMARK, WEIGHT_LIMIT, CREDIT_LIMIT, TEMP_AMOUNT, ACCOUNT_AMOUNT, EUR_AMOUNT, - CUSTOMER_TYPE, CUSTOMER_BALANCE_MODE, BL_OPEN, + CUSTOMER_TYPE, CUSTOMER_AREA, CUSTOMER_BALANCE_MODE, BL_OPEN, CREATE_DATE, GMT_CREATE FROM WEISHI_USER.TAB_CUSTOMER diff --git a/bms-back/sql/bms_init.sql b/bms-back/sql/bms_init.sql index 443bf205..02c3ee87 100644 --- a/bms-back/sql/bms_init.sql +++ b/bms-back/sql/bms_init.sql @@ -355,7 +355,7 @@ CREATE TABLE `ctr_customer` ( `customer_code_dw` varchar(50) DEFAULT '' COMMENT '对外代码', `credit_code` varchar(18) DEFAULT '' COMMENT '统一社会信用代码', `customer_type` char(1) DEFAULT '0' COMMENT '业务类型(0直客 1同行 2集运)', - `area_type` varchar(32) DEFAULT NULL COMMENT '区域类型(字典 data_area_type)', + `customer_area` varchar(32) DEFAULT NULL COMMENT '客户区域(字典 customer_area)', `is_enable` char(1) DEFAULT '0' COMMENT '启用状态(0正常 1停用)', `sales_user_id` varchar(64) DEFAULT NULL COMMENT '业务员系统用户ID(sys_user.user_id)', `source_sales_code` varchar(255) DEFAULT NULL COMMENT '客户同步源业务员工号(内部字段)', diff --git a/bms-back/sql/customer+supplier/20261030_customer_area_type.sql b/bms-back/sql/customer+supplier/20261030_customer_area_type.sql deleted file mode 100644 index 725747d8..00000000 --- a/bms-back/sql/customer+supplier/20261030_customer_area_type.sql +++ /dev/null @@ -1,11 +0,0 @@ --- ctr_customer.area_type:客户区域类型,取值来自字典 data_area_type(可重复执行) -SET @col_exists := ( - SELECT COUNT(1) FROM information_schema.COLUMNS - WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' AND COLUMN_NAME = 'area_type' -); -SET @sql := IF(@col_exists = 0, - 'ALTER TABLE `ctr_customer` ADD COLUMN `area_type` varchar(32) DEFAULT NULL COMMENT ''区域类型(字典 data_area_type)'' AFTER `customer_type`', - 'SELECT 1'); -PREPARE stmt FROM @sql; -EXECUTE stmt; -DEALLOCATE PREPARE stmt; diff --git a/bms-back/sql/customer+supplier/20261104_customer_area_rename.sql b/bms-back/sql/customer+supplier/20261104_customer_area_rename.sql new file mode 100644 index 00000000..07c1581e --- /dev/null +++ b/bms-back/sql/customer+supplier/20261104_customer_area_rename.sql @@ -0,0 +1,173 @@ +-- Unified migration: ctr_customer.area_type -> customer_area and data_area_type -> customer_area. +-- Target: MySQL 5.7.x; run the whole file against the intended database in one connection. +-- Confirm both migration_status and dictionary_migration_status report READY. +-- Conflicting columns or dictionary values are preserved and reported for manual review. + +SET @customer_table_exists := ( + SELECT COUNT(1) FROM information_schema.TABLES + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' +); +SET @customer_area_old_exists := ( + SELECT COUNT(1) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' AND COLUMN_NAME = 'area_type' +); +SET @customer_area_new_exists := ( + SELECT COUNT(1) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' AND COLUMN_NAME = 'customer_area' +); +SET @customer_area_conflict_count := 0; + +-- If both columns exist, require matching non-NULL values before merging and dropping the old column. +SET @customer_area_check_sql := IF( + @customer_area_old_exists = 1 AND @customer_area_new_exists = 1, + 'SELECT COUNT(1) INTO @customer_area_conflict_count FROM `ctr_customer` WHERE `area_type` IS NOT NULL AND `customer_area` IS NOT NULL AND BINARY `area_type` <> BINARY `customer_area`', + 'SELECT 0 INTO @customer_area_conflict_count' +); +PREPARE customer_area_stmt FROM @customer_area_check_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +-- In the no-conflict dual-column state, copy values that only exist in the old column. +SET @customer_area_merge_sql := IF( + @customer_area_old_exists = 1 AND @customer_area_new_exists = 1 AND @customer_area_conflict_count = 0, + 'UPDATE `ctr_customer` SET `customer_area` = `area_type` WHERE `customer_area` IS NULL AND `area_type` IS NOT NULL', + 'SELECT 1' +); +PREPARE customer_area_stmt FROM @customer_area_merge_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +-- Drop the legacy column only after its values have been merged without conflicts. +SET @customer_area_drop_sql := IF( + @customer_area_old_exists = 1 AND @customer_area_new_exists = 1 AND @customer_area_conflict_count = 0, + 'ALTER TABLE `ctr_customer` DROP COLUMN `area_type`', + 'SELECT 1' +); +PREPARE customer_area_stmt FROM @customer_area_drop_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +-- Rename the existing column, or create the new column when neither name exists. +SET @customer_area_rename_sql := CASE + WHEN @customer_table_exists = 1 AND @customer_area_old_exists = 1 AND @customer_area_new_exists = 0 THEN + 'ALTER TABLE `ctr_customer` CHANGE COLUMN `area_type` `customer_area` varchar(32) DEFAULT NULL COMMENT ''客户区域(字典 customer_area)'' AFTER `customer_type`' + WHEN @customer_table_exists = 1 AND @customer_area_old_exists = 0 AND @customer_area_new_exists = 0 THEN + 'ALTER TABLE `ctr_customer` ADD COLUMN `customer_area` varchar(32) DEFAULT NULL COMMENT ''客户区域(字典 customer_area)'' AFTER `customer_type`' + ELSE 'SELECT 1' +END; +PREPARE customer_area_stmt FROM @customer_area_rename_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +SET @customer_area_old_exists := ( + SELECT COUNT(1) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' AND COLUMN_NAME = 'area_type' +); +SET @customer_area_new_exists := ( + SELECT COUNT(1) FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ctr_customer' AND COLUMN_NAME = 'customer_area' +); + +SELECT CASE + WHEN @customer_table_exists = 0 THEN 'ERROR: ctr_customer table does not exist in the selected database' + WHEN @customer_area_old_exists = 0 AND @customer_area_new_exists = 1 THEN 'READY' + WHEN @customer_area_conflict_count > 0 THEN 'BLOCKED: resolve conflicting values and rerun this full script' + ELSE 'ERROR: expected customer_area and no area_type; inspect the table before continuing' + END AS migration_status, + @customer_area_conflict_count AS conflicting_rows; + +SELECT COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT +FROM information_schema.COLUMNS +WHERE TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = 'ctr_customer' + AND COLUMN_NAME IN ('area_type', 'customer_area') +ORDER BY ORDINAL_POSITION; + +-- When migration_status is BLOCKED, inspect these rows, resolve each value manually, then rerun this file. +SET @customer_area_conflict_rows_sql := IF( + @customer_area_conflict_count > 0, + 'SELECT `customer_id`, `customer_code`, `area_type`, `customer_area` FROM `ctr_customer` WHERE `area_type` IS NOT NULL AND `customer_area` IS NOT NULL AND BINARY `area_type` <> BINARY `customer_area` ORDER BY `customer_id`', + 'SELECT ''No conflicting customer area values'' AS conflict_check' +); +PREPARE customer_area_stmt FROM @customer_area_conflict_rows_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +-- Rename the dictionary identifier and its values. If both dictionary types already exist, +-- or both dictionaries use the same value, stop and report instead of creating ambiguity. +SET @customer_area_old_dict_exists := ( + SELECT COUNT(1) FROM `sys_dict_type` WHERE `dict_type` = 'data_area_type' +); +SET @customer_area_new_dict_exists := ( + SELECT COUNT(1) FROM `sys_dict_type` WHERE `dict_type` = 'customer_area' +); +SET @customer_area_dict_value_conflicts := ( + SELECT COUNT(1) + FROM `sys_dict_data` old_data + JOIN `sys_dict_data` new_data ON old_data.`dict_value` = new_data.`dict_value` + WHERE old_data.`dict_type` = 'data_area_type' + AND new_data.`dict_type` = 'customer_area' +); + +SET @customer_area_dict_data_sql := IF( + @customer_area_old_exists = 0 AND @customer_area_new_exists = 1 + AND (@customer_area_old_dict_exists = 1 OR @customer_area_new_dict_exists = 1) + AND @customer_area_dict_value_conflicts = 0 + AND NOT (@customer_area_old_dict_exists = 1 AND @customer_area_new_dict_exists = 1), + 'UPDATE `sys_dict_data` SET `dict_type` = ''customer_area'' WHERE `dict_type` = ''data_area_type''', + 'SELECT 1' +); +PREPARE customer_area_stmt FROM @customer_area_dict_data_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +SET @customer_area_dict_type_sql := CASE + WHEN @customer_area_old_exists = 0 AND @customer_area_new_exists = 1 + AND @customer_area_old_dict_exists = 1 AND @customer_area_new_dict_exists = 0 + AND @customer_area_dict_value_conflicts = 0 THEN + 'UPDATE `sys_dict_type` SET `dict_type` = ''customer_area'', `dict_name` = ''客户区域'', `update_time` = NOW() WHERE `dict_type` = ''data_area_type''' + WHEN @customer_area_old_exists = 0 AND @customer_area_new_exists = 1 + AND @customer_area_old_dict_exists = 0 AND @customer_area_new_dict_exists = 1 + AND @customer_area_dict_value_conflicts = 0 THEN + 'UPDATE `sys_dict_type` SET `dict_name` = ''客户区域'', `update_time` = NOW() WHERE `dict_type` = ''customer_area''' + ELSE 'SELECT 1' +END; +PREPARE customer_area_stmt FROM @customer_area_dict_type_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; + +SET @customer_area_old_dict_exists := ( + SELECT COUNT(1) FROM `sys_dict_type` WHERE `dict_type` = 'data_area_type' +); +SET @customer_area_new_dict_exists := ( + SELECT COUNT(1) FROM `sys_dict_type` WHERE `dict_type` = 'customer_area' +); + +SELECT CASE + WHEN @customer_area_old_exists <> 0 OR @customer_area_new_exists <> 1 THEN 'BLOCKED: finish customer column migration first' + WHEN @customer_area_old_dict_exists = 0 AND @customer_area_new_dict_exists = 1 + AND @customer_area_dict_value_conflicts = 0 THEN 'READY' + WHEN @customer_area_old_dict_exists = 1 AND @customer_area_new_dict_exists = 1 THEN 'BLOCKED: both dictionary types exist; merge them manually' + WHEN @customer_area_dict_value_conflicts > 0 THEN 'BLOCKED: dictionary values overlap; reconcile them manually' + ELSE 'MISSING: verify the customer area dictionary in the selected database' + END AS dictionary_migration_status, + @customer_area_dict_value_conflicts AS overlapping_values; + +SELECT `dict_id`, `dict_name`, `dict_type`, `status` +FROM `sys_dict_type` +WHERE `dict_type` IN ('data_area_type', 'customer_area') +ORDER BY `dict_id`; + +SELECT `dict_code`, `dict_type`, `dict_value`, `dict_label`, `status` +FROM `sys_dict_data` +WHERE `dict_type` IN ('data_area_type', 'customer_area') +ORDER BY `dict_type`, `dict_sort`, `dict_code`; + +SET @customer_area_dict_conflict_rows_sql := IF( + @customer_area_dict_value_conflicts > 0, + 'SELECT old_data.`dict_value`, old_data.`dict_label` AS old_label, new_data.`dict_label` AS new_label FROM `sys_dict_data` old_data JOIN `sys_dict_data` new_data ON old_data.`dict_value` = new_data.`dict_value` WHERE old_data.`dict_type` = ''data_area_type'' AND new_data.`dict_type` = ''customer_area'' ORDER BY old_data.`dict_value`', + 'SELECT ''No overlapping dictionary values'' AS conflict_check' +); +PREPARE customer_area_stmt FROM @customer_area_dict_conflict_rows_sql; +EXECUTE customer_area_stmt; +DEALLOCATE PREPARE customer_area_stmt; diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue index dc6a4167..d6b08539 100644 --- a/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue +++ b/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue @@ -63,10 +63,10 @@ - - + + - + - + @@ -349,7 +349,7 @@ const columnDefs = [ { key: 'customerCodeDw', label: '对外代码' }, { key: 'creditCode', label: '统一社会信用代码' }, { key: 'customerType', label: '业务类型' }, - { key: 'areaType', label: '区域类型' }, + { key: 'customerArea', label: '客户区域' }, { key: 'isEnable', label: '启用状态' }, { key: 'salesUserId', label: '业务员' }, // { key: 'ed', label: '资金额度' }, @@ -378,7 +378,7 @@ const single = ref(true) const multiple = ref(true) const total = ref(0) -const { sys_normal_disable, settlement_type, customer_type, data_area_type } = useDict("sys_normal_disable", "settlement_type", "customer_type", "data_area_type") +const { sys_normal_disable, settlement_type, customer_type, customer_area } = useDict("sys_normal_disable", "settlement_type", "customer_type", "customer_area") /** 绑定产品代码串 -> 产品名称展示(产品代码+名称;查不到的产品回显原代码) */ const { ensureProducts, getProductLabel } = useProducts() @@ -412,7 +412,7 @@ const copyColumns = computed(() => [ { key: 'customerCodeDw', label: '对外代码', get: r => r.customerCodeDw || '' }, { key: 'creditCode', label: '统一社会信用代码', get: r => r.creditCode || '' }, { key: 'customerType', label: '业务类型', get: r => proxy.selectDictLabel(customer_type.value, r.customerType) }, - { key: 'areaType', label: '区域类型', get: r => proxy.selectDictLabel(data_area_type.value, r.areaType) }, + { key: 'customerArea', label: '客户区域', get: r => proxy.selectDictLabel(customer_area.value, r.customerArea) }, { key: 'isEnable', label: '启用状态', get: r => proxy.selectDictLabel(sys_normal_disable.value, r.isEnable) }, { key: 'salesUserId', label: '业务员', get: r => r.salesUserNickName || '' }, { key: 'zq', label: '回款账期', get: r => (r.zq === null || r.zq === undefined ? '' : r.zq) }, @@ -445,7 +445,7 @@ const data = reactive({ keywords: undefined, creditCode: undefined, customerType: undefined, - areaType: undefined, + customerArea: undefined, isEnable: undefined, salesUserId: undefined, salesUser: undefined, From 557d43a0b850a5db5bf8517b0a018909269a2523 Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Wed, 4 Nov 2026 19:38:13 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BF=9B=E5=BA=A6?= =?UTF-8?q?=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/price/BillingController.java | 8 + .../main/resources/i18n/messages.properties | 3 + .../domain/BatchAddIncomeBillFeeTask.java | 1 + .../price/service/IPrcOrderBillService.java | 3 + .../service/impl/PrcOrderBillServiceImpl.java | 19 + .../PrcOrderBillLocalRebillAsyncRunner.java | 110 +++++- bms-front/src/api/price/billing.js | 37 +- bms-front/src/views/price/orderBill/index.vue | 352 ++++++++++++++++-- 8 files changed, 483 insertions(+), 50 deletions(-) diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java index 4e980bf6..cc8a5d03 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/BillingController.java @@ -305,6 +305,14 @@ public class BillingController extends BaseController return success(task); } + @PreAuthorize("@ss.hasPermi('price:orderBill:rebill')") + @Log(title = "Order bill local rebill cancel", businessType = BusinessType.UPDATE) + @PostMapping("/orderBill/rebill/task/{taskId}/cancel") + public AjaxResult cancelLocalRebill(@PathVariable("taskId") String taskId) + { + return success(prcOrderBillService.cancelLocalRebill(taskId)); + } + /** * Order no options for remote-search dropdown (bill list multi search). */ diff --git a/bms-back/bms-admin/src/main/resources/i18n/messages.properties b/bms-back/bms-admin/src/main/resources/i18n/messages.properties index 62b2bcf4..5f3e8d29 100644 --- a/bms-back/bms-admin/src/main/resources/i18n/messages.properties +++ b/bms-back/bms-admin/src/main/resources/i18n/messages.properties @@ -232,3 +232,6 @@ price.bill.export.notReady=导出文件尚未生成或已失败 price.bill.export.fileMissing=导出文件不存在或路径非法 price.set.customer.batch.empty=请选择要绑定的客户 price.set.customer.batch.done=批量绑定完成:共 {0} 个客户,新绑定 {1} 个,更换 {2} 个,跳过 {3} 个 +price.bill.recalc.taskCancelled=本地重新计费已取消 +price.bill.recalc.taskCancelNotRunning=任务已结束或不存在,无法取消 +price.bill.recalc.taskIdRequired=任务ID不能为空 diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/BatchAddIncomeBillFeeTask.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/BatchAddIncomeBillFeeTask.java index efe84a48..322c386f 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/BatchAddIncomeBillFeeTask.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/BatchAddIncomeBillFeeTask.java @@ -11,6 +11,7 @@ public class BatchAddIncomeBillFeeTask implements Serializable public static final String STATUS_RUNNING = "RUNNING"; public static final String STATUS_SUCCESS = "SUCCESS"; public static final String STATUS_FAIL = "FAIL"; + public static final String STATUS_CANCELLED = "CANCELLED"; private String taskId; private String status; diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java index a0747cf0..b5db8a2a 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcOrderBillService.java @@ -166,6 +166,9 @@ public interface IPrcOrderBillService /** Poll Redis progress for local rebill task. */ BatchAddIncomeBillFeeTask getLocalRebillTask(String taskId); + /** Cooperative cancel for a running local rebill task. */ + BatchAddIncomeBillFeeTask cancelLocalRebill(String taskId); + /** Data-scoped bill_id list for local rebill (same filters as order-bill list). */ List selectBillIdsForLocalRebill(PrcOrderBill query); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java index 2b65f2ab..5b38b12f 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcOrderBillServiceImpl.java @@ -972,6 +972,25 @@ public class PrcOrderBillServiceImpl implements IPrcOrderBillService return localRebillAsyncRunner.get(taskId); } + @Override + public BatchAddIncomeBillFeeTask cancelLocalRebill(String taskId) + { + if (StringUtils.isEmpty(taskId)) + { + throw new ServiceException(MessageUtils.message("price.bill.recalc.taskIdRequired")); + } + if (localRebillAsyncRunner == null) + { + throw new ServiceException(MessageUtils.message("price.bill.recalc.taskNotExists")); + } + BatchAddIncomeBillFeeTask task = localRebillAsyncRunner.requestCancel(taskId.trim()); + if (task == null) + { + throw new ServiceException(MessageUtils.message("price.bill.recalc.taskNotExists")); + } + return task; + } + @Override public String submitOrderBillExport(String exportType, PrcOrderBill query) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillLocalRebillAsyncRunner.java b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillLocalRebillAsyncRunner.java index 98591ef9..eabb1923 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillLocalRebillAsyncRunner.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/task/PrcOrderBillLocalRebillAsyncRunner.java @@ -6,12 +6,14 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,8 +34,9 @@ import com.bms.price.search.TabOrderSyncEsLog; import com.bms.price.service.IPrcOrderBillService; /** - * 仅根据 prc_order_bill 异步本地重计费(不走 Oracle / 不走 MQ)。 - * 大批量按 {@link #PAGE_SIZE} 分页处理;每一页在短生命周期线程池中执行。 + * Async local rebill from prc_order_bill only (no Oracle / MQ). + * Large jobs page by {@link #PAGE_SIZE}; each page runs in a short-lived pool. + * Cancel is cooperative: current in-flight bills finish, remaining bills are skipped. */ @Component public class PrcOrderBillLocalRebillAsyncRunner @@ -48,6 +51,8 @@ public class PrcOrderBillLocalRebillAsyncRunner public static final int MAX_THREADS = 16; private static final int FAIL_DETAIL_MAX = 200; + private final ConcurrentHashMap cancelFlags = new ConcurrentHashMap(); + @Autowired @Lazy private IPrcOrderBillService orderBillService; @@ -79,6 +84,7 @@ public class PrcOrderBillLocalRebillAsyncRunner StringBuilder failTips = new StringBuilder(); List> failDetails = Collections.synchronizedList(new ArrayList>()); int threads = clampThreads(billingProperties == null ? null : billingProperties.getOrderSourceSyncThreads()); + cancelFlags.computeIfAbsent(taskId, k -> new AtomicBoolean(false)); ExecutorService pool = newWorkerPool(threads, "local-rebill"); try { @@ -89,9 +95,20 @@ public class PrcOrderBillLocalRebillAsyncRunner saveDoneLog(taskId, request, total, 0, 0, threads, failDetails, "FAIL", "no bills"); return; } + if (isCancelRequested(taskId)) + { + finishCancelled(taskId, request, total, success.get(), fail.get(), threads, failDetails); + return; + } int processed = 0; + boolean cancelled = false; for (int from = 0; from < total; from += PAGE_SIZE) { + if (isCancelRequested(taskId)) + { + cancelled = true; + break; + } int to = Math.min(from + PAGE_SIZE, total); List page = billIds.subList(from, to); List> jobs = new ArrayList>(page.size()); @@ -99,6 +116,10 @@ public class PrcOrderBillLocalRebillAsyncRunner { final String one = billId; jobs.add(() -> { + if (isCancelRequested(taskId)) + { + return Boolean.FALSE; + } try { orderBillService.rebillLocalByBillId(one); @@ -118,11 +139,21 @@ public class PrcOrderBillLocalRebillAsyncRunner } invokeAllQuiet(pool, jobs); processed = to; + if (isCancelRequested(taskId)) + { + cancelled = true; + break; + } int percent = Math.min(99, (int) Math.floor(100.0 * processed / total)); put(taskId, BatchAddIncomeBillFeeTask.STATUS_RUNNING, percent, "processing " + processed + "/" + total + " page=" + ((from / PAGE_SIZE) + 1), null, total, success.get(), fail.get()); } + if (cancelled || isCancelRequested(taskId)) + { + finishCancelled(taskId, request, total, success.get(), fail.get(), threads, failDetails); + return; + } String msg = "success=" + success.get() + ", fail=" + fail.get(); String err = fail.get() > 0 && failTips.length() > 0 ? failTips.toString() : null; put(taskId, BatchAddIncomeBillFeeTask.STATUS_SUCCESS, 100, msg, err, @@ -135,6 +166,11 @@ public class PrcOrderBillLocalRebillAsyncRunner } catch (Exception e) { + if (isCancelRequested(taskId)) + { + finishCancelled(taskId, request, total, success.get(), fail.get(), threads, failDetails); + return; + } log.error("local rebill aborted taskId={}", taskId, e); String msg = errorMessage(e); put(taskId, BatchAddIncomeBillFeeTask.STATUS_FAIL, 100, "failed", msg, @@ -144,10 +180,62 @@ public class PrcOrderBillLocalRebillAsyncRunner } finally { + cancelFlags.remove(taskId); shutdownPool(pool); } } + /** + * Request cooperative cancel. Returns current task snapshot (may still be RUNNING until page ends). + */ + public BatchAddIncomeBillFeeTask requestCancel(String taskId) + { + if (StringUtils.isEmpty(taskId)) + { + return null; + } + BatchAddIncomeBillFeeTask task = get(taskId); + if (task == null) + { + return null; + } + String st = task.getStatus(); + if (BatchAddIncomeBillFeeTask.STATUS_SUCCESS.equals(st) + || BatchAddIncomeBillFeeTask.STATUS_FAIL.equals(st) + || BatchAddIncomeBillFeeTask.STATUS_CANCELLED.equals(st)) + { + return task; + } + cancelFlags.computeIfAbsent(taskId, k -> new AtomicBoolean(false)).set(true); + // Keep RUNNING so clients keep polling until finishCancelled writes CANCELLED. + put(taskId, BatchAddIncomeBillFeeTask.STATUS_RUNNING, + Math.max(task.getPercent(), 1), + "cancelling", + null, + task.getTotal(), task.getSuccess(), task.getFail()); + log.info("local rebill cancel requested taskId={} success={} fail={} total={}", + taskId, task.getSuccess(), task.getFail(), task.getTotal()); + return get(taskId); + } + + private void finishCancelled(String taskId, LocalRebillRequest request, int total, int ok, int fail, + int threads, List> failDetails) + { + int percent = total <= 0 ? 100 : Math.min(100, (int) Math.floor(100.0 * (ok + fail) / total)); + String msg = "cancelled success=" + ok + ", fail=" + fail; + put(taskId, BatchAddIncomeBillFeeTask.STATUS_CANCELLED, Math.max(percent, 1), msg, + "cancelled by user", total, ok, fail); + saveDoneLog(taskId, request, total, ok, fail, threads, failDetails, + EsBizLogSupport.STATUS_FAIL, "cancelled by user"); + log.info("local rebill cancelled taskId={} total={} success={} fail={}", taskId, total, ok, fail); + } + + private boolean isCancelRequested(String taskId) + { + AtomicBoolean flag = cancelFlags.get(taskId); + return flag != null && flag.get(); + } + private void saveDoneLog(String taskId, LocalRebillRequest request, int total, int ok, int fail, int threads, List> failDetails, String status, String errorMessage) { @@ -209,6 +297,24 @@ public class PrcOrderBillLocalRebillAsyncRunner public void put(String taskId, String status, int percent, String message, String error, int total, int success, int fail) { + BatchAddIncomeBillFeeTask existing = get(taskId); + if (existing != null + && BatchAddIncomeBillFeeTask.STATUS_CANCELLED.equals(existing.getStatus()) + && !BatchAddIncomeBillFeeTask.STATUS_CANCELLED.equals(status)) + { + // Keep cancelled: do not let a late RUNNING overwrite after user cancel. + BatchAddIncomeBillFeeTask keep = new BatchAddIncomeBillFeeTask(); + keep.setTaskId(taskId); + keep.setStatus(BatchAddIncomeBillFeeTask.STATUS_CANCELLED); + keep.setPercent(Math.max(existing.getPercent(), percent)); + keep.setMessage(existing.getMessage()); + keep.setError(existing.getError()); + keep.setTotal(total > 0 ? total : existing.getTotal()); + keep.setSuccess(Math.max(existing.getSuccess(), success)); + keep.setFail(Math.max(existing.getFail(), fail)); + redisCache.setCacheObject(CACHE_KEY_PREFIX + taskId, keep, TTL_MINUTES, TimeUnit.MINUTES); + return; + } BatchAddIncomeBillFeeTask task = new BatchAddIncomeBillFeeTask(); task.setTaskId(taskId); task.setStatus(status); diff --git a/bms-front/src/api/price/billing.js b/bms-front/src/api/price/billing.js index 17e42223..e4f6ea49 100644 --- a/bms-front/src/api/price/billing.js +++ b/bms-front/src/api/price/billing.js @@ -102,23 +102,29 @@ export function getLocalRebillTask(taskId) { }) } +export function cancelLocalRebill(taskId) { + return request({ + url: '/price/billing/orderBill/rebill/task/' + taskId + '/cancel', + method: 'post' + }) +} + /** - * Async local rebill; poll until done. - * @param {object} data LocalRebillRequest + * Poll local rebill task until terminal status. + * @param {string} taskId * @param {(task: object) => void} [onProgress] */ -export async function localRebillAsync(data, onProgress) { - const submitRes = await submitLocalRebill(data) - const d = submitRes && submitRes.data - const taskId = d && (d.taskId || d) - if (!taskId) throw new Error('missing local rebill taskId') +export async function pollLocalRebillTask(taskId, onProgress) { + const id = String(taskId || '') + if (!id) throw new Error('missing local rebill taskId') const started = Date.now() const maxMs = 30 * 60 * 1000 while (Date.now() - started < maxMs) { - const res = await getLocalRebillTask(String(taskId)) + const res = await getLocalRebillTask(id) const task = res.data || {} if (typeof onProgress === 'function') onProgress(task) if (task.status === 'SUCCESS') return { task } + if (task.status === 'CANCELLED') return { task, cancelled: true } if (task.status === 'FAIL') { const err = new Error(task.error || task.message || 'local rebill failed') err.task = task @@ -129,6 +135,21 @@ export async function localRebillAsync(data, onProgress) { throw new Error('local rebill timeout') } +/** + * Async local rebill; poll until done. + * @param {object} data LocalRebillRequest + * @param {(task: object) => void} [onProgress] + * @param {{ getTaskId?: (taskId: string) => void }} [options] + */ +export async function localRebillAsync(data, onProgress, options) { + const submitRes = await submitLocalRebill(data) + const d = submitRes && submitRes.data + const taskId = d && (d.taskId || d) + if (!taskId) throw new Error('missing local rebill taskId') + if (options && typeof options.getTaskId === 'function') options.getTaskId(String(taskId)) + return pollLocalRebillTask(String(taskId), onProgress) +} + /** Receivable bill detail */ export function getBill(billId) { return request({ diff --git a/bms-front/src/views/price/orderBill/index.vue b/bms-front/src/views/price/orderBill/index.vue index 5087d30a..04ca336a 100644 --- a/bms-front/src/views/price/orderBill/index.vue +++ b/bms-front/src/views/price/orderBill/index.vue @@ -1,5 +1,19 @@ @@ -31,8 +31,8 @@ @@ -55,7 +55,10 @@ import SetSectionCard from './SetSectionCard.vue' import SetCustomerDialog from './SetCustomerDialog.vue' import { isChildEditable } from '../../utils/priceSet' -import { delSetCustomer } from '@/api/price/set' +import { usePriceSetModule, usePriceSetPerm } from '../../composables/usePriceSetModule' + +const { api } = usePriceSetModule() +const editPerm = usePriceSetPerm('edit') const props = defineProps({ /** 套餐详情对象 */ @@ -75,7 +78,7 @@ const customers = computed(() => props.set.customers || []) const editable = computed(() => isChildEditable(props.set.status)) function remove(row) { - proxy.$modal.confirm('确认解绑该客户?').then(() => delSetCustomer(row.customerPricesetId)).then(() => { + proxy.$modal.confirm('确认解绑该客户?').then(() => api.delSetCustomer(row.customerPricesetId)).then(() => { proxy.$modal.msgSuccess('已解绑') emit('refresh') }).catch(() => {}) diff --git a/bms-front/src/views/price/set/components/detail/SetDetailDialog.vue b/bms-front/src/views/price/set/components/detail/SetDetailDialog.vue index 34190bb6..4eaa06ac 100644 --- a/bms-front/src/views/price/set/components/detail/SetDetailDialog.vue +++ b/bms-front/src/views/price/set/components/detail/SetDetailDialog.vue @@ -164,7 +164,9 @@ import SurchargeTags from '../SurchargeTags.vue' import { useDetailCascade } from '../../composables/usePriceSetRefData' import { createEmptyDetailRow, isFixedType, toEditableDetailRow } from '../../utils/priceSet' -import { addSetDetail, updateSetDetail } from '@/api/price/set' +import { usePriceSetModule } from '../../composables/usePriceSetModule' + +const { api } = usePriceSetModule() const props = defineProps({ /** 所属套餐ID */ @@ -228,7 +230,7 @@ async function submit() { const payload = { ...form.value, priceSetId: props.priceSetId } delete payload._countryKey submitting.value = true - const req = payload.psdId ? updateSetDetail(payload) : addSetDetail(payload) + const req = payload.psdId ? api.updateSetDetail(payload) : api.addSetDetail(payload) req.then(() => { proxy.$modal.msgSuccess('保存成功') visible.value = false diff --git a/bms-front/src/views/price/set/components/detail/SetDetailHeader.vue b/bms-front/src/views/price/set/components/detail/SetDetailHeader.vue index 3aa2cd58..c3b76347 100644 --- a/bms-front/src/views/price/set/components/detail/SetDetailHeader.vue +++ b/bms-front/src/views/price/set/components/detail/SetDetailHeader.vue @@ -2,7 +2,7 @@
-

{{ set.priceSetName || '套餐详情' }}

+

{{ set.priceSetName || mod.labels.detailTitleFallback }}

{{ set.priceSetCode }} {{ setStatusLabel(set) }}
@@ -20,14 +20,14 @@ type="danger" plain @click="emit('disable')" - v-hasPermi="['price:set:audit']" + v-hasPermi="auditPerm" >停用 启用
@@ -35,6 +35,10 @@ From 218001e6ae4cbc00085df1bf5fffe04084ada339 Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Thu, 5 Nov 2026 13:15:51 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BC=96=E8=BE=91bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../set/components/create/StepDetails.vue | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/bms-front/src/views/price/set/components/create/StepDetails.vue b/bms-front/src/views/price/set/components/create/StepDetails.vue index 462219f2..ce80df24 100644 --- a/bms-front/src/views/price/set/components/create/StepDetails.vue +++ b/bms-front/src/views/price/set/components/create/StepDetails.vue @@ -385,18 +385,35 @@ const emptyTip = computed(() => { }) -/** Resolve version id: prop first, else reload package current version. */ +/** Resolve version id: editing prop/local first; never replace with package EFFECT version. */ const resolvedPsvId = ref(props.psvId) watch(() => props.psvId, v => { if (v != null && v !== '') resolvedPsvId.value = v }) +function knownPsvId() { + if (props.psvId != null && props.psvId !== '') return props.psvId + if (resolvedPsvId.value != null && resolvedPsvId.value !== '') return resolvedPsvId.value + return null +} + async function resolvePsvId(force) { - if (!force && resolvedPsvId.value != null && resolvedPsvId.value !== '') { - return resolvedPsvId.value + const known = knownPsvId() + // Keep the version being edited. force must NOT switch to data.version (EFFECT). + if (known != null && !force) { + resolvedPsvId.value = known + return known } - if (!props.priceSetId) return null + if (!props.priceSetId) return known const res = await api.getPriceSet(props.priceSetId) const data = res.data || {} const versions = data.versions || [] + if (known != null) { + const still = versions.find(v => v && String(v.psvId) === String(known)) + if (still && still.psvId != null) { + resolvedPsvId.value = still.psvId + return still.psvId + } + } + // Only when no editing psvId (e.g. brand-new draft): fall back to package current. const fromData = (data.version && data.version.psvId) ? data.version : null const current = fromData || versions[0] || {} if (current.psvId != null) { @@ -594,7 +611,8 @@ async function canOpenImport() { return false } if (props.livePersist) { - const psvId = await resolvePsvId(true) + // Use the version being edited (props.psvId). Do not force-refresh to EFFECT. + const psvId = await resolvePsvId(false) if (!psvId) { proxy.$modal.msgWarning('缺少套餐版本,请先保存基本信息') return false From 17273868114847e3406b9980e2e4919a6435016f Mon Sep 17 00:00:00 2001 From: caojia <1301869380@qq.com> Date: Thu, 5 Nov 2026 14:26:36 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E6=AF=9B=E5=88=A9=E5=88=86=E6=9E=90?= =?UTF-8?q?=E7=9A=84=E5=AE=A2=E6=88=B7=E5=8C=BA=E5=9F=9F=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../price/domain/vo/PrcProfitReportQuery.java | 2 + .../mapper/price/PrcProfitReportMapper.xml | 6 ++ bms-front/src/views/report/profit/index.vue | 58 ++++++++++++++++--- 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java index 8a9b4a09..170b3f3a 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/PrcProfitReportQuery.java @@ -24,6 +24,8 @@ public class PrcProfitReportQuery extends BaseEntity private String customerCode; /** 客户代码拆分后的多值查询条件。 */ private List customerCodes; + /** 按客户当前区域筛选。 */ + private String customerArea; private String customerName; /** 客户名称拆分后的多值查询条件。 */ private List customerNames; diff --git a/bms-back/bms-system/src/main/resources/mapper/price/PrcProfitReportMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/PrcProfitReportMapper.xml index 3320fc3d..75861a98 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/PrcProfitReportMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/PrcProfitReportMapper.xml @@ -119,6 +119,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" from prc_income_bill i inner join prc_order_bill p on p.bill_id = i.bill_id + + left join ctr_customer c on c.customer_id = p.customer_id and c.del_flag = '0' + and (p.billing_fail_status is null or p.billing_fail_status not in (1, 2, 3)) + + and c.customer_area = #{customerArea} + and p.biz_date >= #{beginBizDate} diff --git a/bms-front/src/views/report/profit/index.vue b/bms-front/src/views/report/profit/index.vue index 95a8abbd..571b625e 100644 --- a/bms-front/src/views/report/profit/index.vue +++ b/bms-front/src/views/report/profit/index.vue @@ -3,6 +3,13 @@ + + + + + + +
- 搜索 + 搜索 重置
@@ -132,6 +139,7 @@ icon="Download" v-hasPermi="['report:profit:export']" :loading="exporting" + :disabled="!hasCustomerArea()" @click="handleExport" >导出当前维度 @@ -304,16 +312,19 @@ import { saveAs } from 'file-saver' // 提成功能暂停使用:import { ElMessageBox } from 'element-plus' const dimension = ref('product') +const { customer_area } = useDict('customer_area') const multiValueFilterLimit = 2000 const dateRange = ref([formatLocalDate(-30), formatLocalDate(0)]) const arBillStatus = ref('') const query = reactive({ + customerArea: '', orderNo: '', customerCode: '', belongSalerCode: '', productCode: '' }) const summaryList = ref([]) +let summaryRequestVersion = 0 const rows = ref([]) let rowsRequestVersion = 0 const loading = ref(false) @@ -397,15 +408,21 @@ function validateMultiValueFilters(showMessage = true) { return true } +function hasCustomerArea() { + return query.customerArea !== '' && query.customerArea !== null && query.customerArea !== undefined +} + function loadSummary() { - if (!validateMultiValueFilters(false)) return Promise.resolve() + if (!hasCustomerArea() || !validateMultiValueFilters(false)) return Promise.resolve() + const requestVersion = ++summaryRequestVersion return listProfitSummary(buildQuery(false)).then(res => { + if (requestVersion !== summaryRequestVersion) return summaryList.value = res.data || [] }) } function loadRows() { - if (!validateMultiValueFilters()) return Promise.resolve() + if (!hasCustomerArea() || !validateMultiValueFilters()) return Promise.resolve() const requestVersion = ++rowsRequestVersion const requestDimension = dimension.value loading.value = true @@ -419,14 +436,31 @@ function loadRows() { }) } +function clearReportResults() { + summaryRequestVersion++ + rowsRequestVersion++ + orderListRequestVersion++ + summaryList.value = [] + rows.value = [] + total.value = 0 + loading.value = false + orderListDialogVisible.value = false + orderListLoading.value = false + orderListRows.value = [] + orderListTotal.value = 0 + orderListContext.value = null +} + function handleSearch() { - if (!validateMultiValueFilters()) return + clearReportResults() + if (!hasCustomerArea() || !validateMultiValueFilters()) return pageNum.value = 1 Promise.all([loadSummary(), loadRows()]) } function handleReset() { Object.keys(query).forEach(key => { query[key] = '' }) + query.customerArea = customer_area.value[0]?.value ?? '' arBillStatus.value = '' dateRange.value = [formatLocalDate(-30), formatLocalDate(0)] handleSearch() @@ -459,7 +493,7 @@ function openOrderList(row) { function loadOrderList() { if (!orderListContext.value) return - if (!validateMultiValueFilters()) return + if (!hasCustomerArea() || !validateMultiValueFilters()) return const requestVersion = ++orderListRequestVersion orderListLoading.value = true const params = { @@ -513,7 +547,7 @@ function arBillStatusLabel(value) { } async function handleExport() { - if (!validateMultiValueFilters()) return + if (!hasCustomerArea() || !validateMultiValueFilters()) return exporting.value = true const exporter = dimension.value === 'product' ? exportProfitProducts : exportProfitOrders try { @@ -625,7 +659,17 @@ function handleDeleteRate(row) { } */ -handleSearch() +watch(customer_area, options => { + if (!options?.length) { + query.customerArea = '' + clearReportResults() + return + } + if (!options.some(area => area.value === query.customerArea)) { + query.customerArea = options[0].value + handleSearch() + } +}, { immediate: true }) diff --git a/bms-front/src/views/monitor/orderSource/index.vue b/bms-front/src/views/monitor/orderSource/index.vue index 7f57f688..f853b21f 100644 --- a/bms-front/src/views/monitor/orderSource/index.vue +++ b/bms-front/src/views/monitor/orderSource/index.vue @@ -459,12 +459,17 @@ function onCompareFillSearch(payload) { } function openFilterSync() { + // Running / just finished: reopen progress dialog (same as order-list float click). + if (syncFloat.value && (syncFloat.value.loading || syncFloat.value.finished)) { + syncDialogRef.value?.open(null, false) + return + } const q = buildFilterQuery() const identifierCount = (q.orderIdentifiers || []).length const hasIdentifier = identifierCount > 0 const hasCustomer = !!(q.customerKeywords && q.customerKeywords.length) const hasTime = !!q.beginTime && !!q.endTime - // 与查询同口径:有单号即可同步;无单号时必须客户+提货时间 + // Same as list query: identifiers alone OK; else customer + pickup time required. if (!hasIdentifier && !(hasCustomer && hasTime)) { ElMessage.warning('请输入单号,或选择客户和提货时间后再同步落库') return @@ -481,13 +486,19 @@ function openFilterSync() { }).catch(() => {}) } +let syncFloatHideTimer = null function onSyncProgress(payload) { syncFloat.value = payload + if (syncFloatHideTimer) { + clearTimeout(syncFloatHideTimer) + syncFloatHideTimer = null + } if (payload && payload.finished && !payload.loading) { - window.setTimeout(() => { + syncFloatHideTimer = window.setTimeout(() => { if (syncFloat.value && syncFloat.value.finished && !syncFloat.value.loading) { syncFloat.value = null } + syncFloatHideTimer = null }, 8000) } } From 04ce44647a770c1ef8e222dc4c28d6e376844fa2 Mon Sep 17 00:00:00 2001 From: wuweihua <88888888> Date: Thu, 5 Nov 2026 16:12:35 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E6=95=B0=E6=BA=90=E4=BA=A7=E5=93=81=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../price/oracle/TabOrderMonitorService.java | 22 +++++++++++++++++-- .../price/OracleUpstreamOrderMapper.xml | 5 +++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java index 3436f21c..151c894b 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java @@ -1309,8 +1309,9 @@ public class TabOrderMonitorService vo.setTrackId(str(row, "TRACK_ID")); vo.setCustomerCode(str(row, "CUSTOMER_CODE")); vo.setCustomerName(str(row, "CUSTOMER_NAME")); - vo.setProductCode(str(row, "PRODUCT_CODE")); - vo.setProductName(str(row, "PRODUCT_NAME")); + // Prefer LINE_CODE / LINE_NAME (billing product); list SQL aliases them as PRODUCT_*. + vo.setProductCode(firstStr(row, "LINE_CODE", "PRODUCT_CODE")); + vo.setProductName(firstStr(row, "LINE_NAME", "PRODUCT_NAME")); vo.setProductFloorCode(str(row, "PRODUCT_FLOOR_CODE")); vo.setCountry(str(row, "COUNTRY")); vo.setCountryName(str(row, "COUNTRY_NAME")); @@ -1330,6 +1331,23 @@ public class TabOrderMonitorService return v == null ? null : String.valueOf(v).trim(); } + private static String firstStr(Map row, String... keys) + { + if (keys == null) + { + return null; + } + for (String key : keys) + { + String v = str(row, key); + if (StringUtils.isNotEmpty(v)) + { + return v; + } + } + return null; + } + private static Integer integer(Map row, String key) { Object v = value(row, key); diff --git a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml index 55796df3..33d3e605 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml @@ -123,8 +123,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" o.TRACK_ID, o.CUSTOMER_CODE, o.CUSTOMER_NAME, - o.PRODUCT_CODE, - o.PRODUCT_NAME, + + o.LINE_CODE AS PRODUCT_CODE, + o.LINE_NAME AS PRODUCT_NAME, o.PRODUCT_FLOOR_CODE, o.COUNTRY, o.COUNTRY_NAME, From 36433863afa3835455d8611d112cf9da80ac3cd1 Mon Sep 17 00:00:00 2001 From: liuminghui <468701464@qq.com> Date: Thu, 5 Nov 2026 16:34:33 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../price/domain/vo/TabOrderMonitorQuery.java | 5 +++++ .../mapper/OracleUpstreamOrderMapper.java | 3 ++- .../oracle/OracleOrderKeyCollectWorker.java | 5 +++-- .../price/oracle/TabOrderMonitorService.java | 21 ++++++++++++++++--- .../price/OracleUpstreamOrderMapper.xml | 18 ++++++++++++++-- .../components/OrderSourceSyncDialog.vue | 1 + .../src/views/monitor/orderSource/index.vue | 18 ++++++++++++++-- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java index 0d712110..4b66be56 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/vo/TabOrderMonitorQuery.java @@ -43,6 +43,11 @@ public class TabOrderMonitorQuery implements Serializable * 空则服务端回落默认 3,4,5,6,7,8,11(与历史硬编码一致)。 */ private List orderStatuses; + /** + * 是否收货 BL_PICKUP。1 已收货,0 未收货。 + * 空则服务端回落 1,与历史查询一致。 + */ + private Integer blPickup; /** 分批同步计费每批条数 */ private Integer batchSize; /** Excel export field names (Java props; export only). */ diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java index c2eb2cbf..c7f23bc5 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/OracleUpstreamOrderMapper.java @@ -70,7 +70,8 @@ public interface OracleUpstreamOrderMapper List> selectMatchedTransferOrderKeys( @Param("orderTable") String orderTable, @Param("batch") List batch, - @Param("customerCodes") List customerCodes); + @Param("customerCodes") List customerCodes, + @Param("blPickup") Integer blPickup); /** 按已收集到的订单主键批量查明细(一批为一个内存分页切片)。 */ diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderKeyCollectWorker.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderKeyCollectWorker.java index 80346f6c..06cb62d8 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderKeyCollectWorker.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/OracleOrderKeyCollectWorker.java @@ -28,8 +28,9 @@ public class OracleOrderKeyCollectWorker /** 比对回填转单号专用分批(不走三列 UNION)。 */ @DataSource(DataSourceType.SLAVE) - public List> collectTransferBatch(String table, List batch, List customerCodes) + public List> collectTransferBatch(String table, List batch, List customerCodes, + Integer blPickup) { - return oracleUpstreamOrderMapper.selectMatchedTransferOrderKeys(table, batch, customerCodes); + return oracleUpstreamOrderMapper.selectMatchedTransferOrderKeys(table, batch, customerCodes, blPickup); } } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java index 151c894b..1679feb8 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/oracle/TabOrderMonitorService.java @@ -456,12 +456,13 @@ public class TabOrderMonitorService } } List customerCodes = cleanedCodes.isEmpty() ? null : cleanedCodes; + normalizeBlPickup(query); int[] page = normalizePage(pageNum, pageSize); int pn = page[0]; int ps = page[1]; String table = resolveTable(); long t0 = System.currentTimeMillis(); - List keys = doCollectTransferKeys(table, nos, customerCodes); + List keys = doCollectTransferKeys(table, nos, customerCodes, query.getBlPickup()); List rows = doPageByKeys(table, keys, pn, ps); log.info("oracle tab_order transfer-fill page transferNos={} matched={} page={}/{} rows={} costMs={}", Integer.valueOf(nos.size()), Integer.valueOf(keys.size()), @@ -795,12 +796,14 @@ public class TabOrderMonitorService * 回填转单号专用收集:只走 selectMatchedTransferOrderKeys, * 不走三列 UNION、不带提货时间。 */ - private List doCollectTransferKeys(String table, List transferNos, List customerCodes) + private List doCollectTransferKeys(String table, List transferNos, List customerCodes, + Integer blPickup) { StringBuilder fp = new StringBuilder("tf|").append(table == null ? "" : table).append('|'); appendSorted(fp, transferNos); fp.append('|'); appendSorted(fp, customerCodes); + fp.append('|').append(blPickup == null ? "" : blPickup); String fingerprint = Integer.toHexString(fp.toString().hashCode()); long now = System.currentTimeMillis(); CacheEntry cached = collectCache.get(fingerprint); @@ -821,7 +824,7 @@ public class TabOrderMonitorService new ArrayList>>>(batches.size()); for (List batch : batches) { - futures.add(collectPool.submit(() -> collectWorker.collectTransferBatch(table, batch, customerCodes))); + futures.add(collectPool.submit(() -> collectWorker.collectTransferBatch(table, batch, customerCodes, blPickup))); } Map unique = new LinkedHashMap(); @@ -1035,6 +1038,7 @@ public class TabOrderMonitorService .append('|').append(safe(q.getOrderId())).append('|').append(safe(q.getOrgOrderId())) .append('|').append(safe(q.getTransferOrderId())).append('|'); appendSortedInts(sb, q.getOrderStatuses()); + sb.append('|').append(q.getBlPickup() == null ? "" : q.getBlPickup()); return Integer.toHexString(sb.toString().hashCode()); } @@ -1207,6 +1211,7 @@ public class TabOrderMonitorService query.setOrgOrderId(trimToNull(query.getOrgOrderId())); query.setTransferOrderId(trimToNull(query.getTransferOrderId())); normalizeOrderStatuses(query); + normalizeBlPickup(query); } /** Empty/missing -> default 3,4,5,6,7,8,11 so SQL always has a status IN list. */ @@ -1227,6 +1232,16 @@ public class TabOrderMonitorService query.setOrderStatuses(cleaned.isEmpty() ? new ArrayList(DEFAULT_ORDER_STATUSES) : cleaned); } + /** Empty or anything other than 0/1 falls back to 1(已收货). */ + private static void normalizeBlPickup(TabOrderMonitorQuery query) + { + Integer blPickup = query.getBlPickup(); + if (blPickup == null || (blPickup.intValue() != 0 && blPickup.intValue() != 1)) + { + query.setBlPickup(Integer.valueOf(1)); + } + } + /** * 多行文本归一化:按换行/逗号/分号/顿号拆分(不按空格拆),trim、去空去重。 */ diff --git a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml index 33d3e605..9f8e7b6c 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/OracleUpstreamOrderMapper.xml @@ -66,7 +66,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND o.PICKUP_DATE <= TO_DATE(#{query.endTime}, 'YYYY-MM-DD HH24:MI:SS') - AND o.BL_PICKUP = 1 + + + AND o.BL_PICKUP = #{query.blPickup} + + + + + AND o.ORDER_STATUS IN @@ -274,7 +281,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{bid} - AND o.BL_PICKUP = 1 + + + AND o.BL_PICKUP = #{blPickup} + + + + + AND o.ORDER_STATUS IN (3, 4, 5, 6, 7, 8, 11) AND o.CUSTOMER_CODE IN diff --git a/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue b/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue index 47455435..f9a77c65 100644 --- a/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue +++ b/bms-front/src/views/monitor/orderSource/components/OrderSourceSyncDialog.vue @@ -240,6 +240,7 @@ function submit(skipConfirm) { orgOrderId: q.orgOrderId || undefined, transferOrderId: q.transferOrderId || undefined, orderStatuses: Array.isArray(q.orderStatuses) && q.orderStatuses.length ? q.orderStatuses : undefined, + blPickup: q.blPickup === 0 || q.blPickup === 1 ? q.blPickup : 1, batchSize: 100 }).then(res => { const asyncTaskId = res.data?.asyncTaskId || res.data diff --git a/bms-front/src/views/monitor/orderSource/index.vue b/bms-front/src/views/monitor/orderSource/index.vue index f853b21f..74a44595 100644 --- a/bms-front/src/views/monitor/orderSource/index.vue +++ b/bms-front/src/views/monitor/orderSource/index.vue @@ -191,8 +191,14 @@ const orderStatusMap = { const orderStatusOptions = Object.keys(orderStatusMap).map(k => ({ label: orderStatusMap[k], value: Number(k) })) +const blPickupOptions = [ + { label: '已收货', value: 1 }, + { label: '未收货', value: 0 } +] + const defaultParams = { - orderStatuses: [3, 4, 5, 6, 7, 8, 11] + orderStatuses: [3, 4, 5, 6, 7, 8, 11], + blPickup: 1 } const searchColumns = [ @@ -243,6 +249,13 @@ const searchColumns = [ collapseTagsTooltip: true } }, + { + label: '收货状态', + prop: 'blPickup', + component: 'select', + options: blPickupOptions, + placeholder: '请选择' + }, ] const columns = [ @@ -389,6 +402,7 @@ function queryList(params) { const customers = splitLines(src.customerKeywords) const fillQuery = { orderIdentifiers: identifiers } if (customers.length) fillQuery.customerKeywords = customers + fillQuery.blPickup = src.blPickup === 0 || src.blPickup === 1 ? src.blPickup : 1 fillQuery.pageNum = params.pageNum fillQuery.pageSize = params.pageSize return listOrderSourceByTransferNos(fillQuery) @@ -421,7 +435,7 @@ function openOrderCompare() { return } proxy.$modal.confirm( - '将按当前客户、提货时间与订单状态筛选,异步分页比对上游转单号是否已落库,确认继续?', + '将按当前客户、提货时间、订单状态和收货状态筛选,异步分页比对上游转单号是否已落库,确认继续?', '二次确认' ).then(() => { // 比对只按客户+时间;不带单号框内容(回填后可能有数千转单号,带上会把比对拖死)