Merge branch 'test'

This commit is contained in:
caojia
2026-11-04 18:32:28 +08:00
16 changed files with 227 additions and 88 deletions
@@ -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=停用")
@@ -45,10 +45,10 @@ public class BmsCustomerLogServiceImpl implements IBmsCustomerLogService
private static final ThreadLocal<SimpleDateFormat> 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 的 &lt;if test="x!=null and x!=''"&gt;,
* 其余动态字段仅在新值非 null 时落库;业务员/结算员/客服、区域类型为无条件写入。
* 其余动态字段仅在新值非 null 时落库;业务员/结算员/客服、客户区域为无条件写入。
*/
private static final List<FieldDef> 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;
}
@@ -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,
@@ -43,6 +43,4 @@ public class PrcProfitReportProductRow implements Serializable
@Excel(name = "未计算提成订单数", width = 20)
private Long commissionMissingOrderCount;
*/
@Excel(name = "产品价或价格缺失订单数", width = 22)
private Long incompleteOrderCount;
}
@@ -35,6 +35,6 @@ public class PrcProfitReportQuery extends BaseEntity
private String arBillStatus;
/** 是否按产品维度分组值下钻订单明细,允许分组字段为空。 */
private Boolean productDrilldown;
/** 订单明细弹窗的筛选类型:ALL、INCOMPLETE;COMMISSION_MISSING 暂停使用。 */
/** 仅用于拒绝已暂停的提成未计算订单下钻请求。 */
private String detailType;
}
@@ -11,7 +11,6 @@ public class PrcProfitReportSummary implements Serializable
private static final long serialVersionUID = 1L;
private Long orderCount;
private Long incompleteOrderCount;
private String currency;
private BigDecimal costAmount;
private BigDecimal redlineAmount;
@@ -11,7 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="customerCodeDw" column="customer_code_dw" />
<result property="creditCode" column="credit_code" />
<result property="customerType" column="customer_type" />
<result property="areaType" column="area_type" />
<result property="customerArea" column="customer_area" />
<result property="isEnable" column="is_enable" />
<result property="salesUserId" column="sales_user_id" />
<result property="salesUser" column="sales_user" />
@@ -45,7 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 账户余额/外币余额统一取 ctr_customer_account 余额表(CNY 为本币,其余为外币),不取 ctr_customer 冗余列 -->
<!-- 信用额度=总额度+额外额度-已用额度-->
<sql id="selectBmsCustomerVo">
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"
</if>
<if test="creditCode != null and creditCode != ''"> and c.credit_code = #{creditCode}</if>
<if test="customerType != null and customerType != ''"> and c.customer_type = #{customerType}</if>
<if test="areaType != null and areaType != ''"> and c.area_type = #{areaType}</if>
<if test="customerArea != null and customerArea != ''"> and c.customer_area = #{customerArea}</if>
<if test="isEnable != null and isEnable != ''"> and c.is_enable = #{isEnable}</if>
<if test="salesUserId != null and salesUserId != ''"> and c.sales_user_id = #{salesUserId}</if>
<if test="salesUser != null and salesUser != ''"> and su.nick_name = #{salesUser}</if>
@@ -317,7 +317,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="customerCodeDw != null">customer_code_dw,</if>
<if test="creditCode != null">credit_code,</if>
<if test="customerType != null">customer_type,</if>
<if test="areaType != null">area_type,</if>
<if test="customerArea != null">customer_area,</if>
<if test="isEnable != null">is_enable,</if>
<if test="salesUserId != null">sales_user_id,</if>
<if test="salesUser != null">sales_user,</if>
@@ -350,7 +350,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="customerCodeDw != null">#{customerCodeDw},</if>
<if test="creditCode != null">#{creditCode},</if>
<if test="customerType != null">#{customerType},</if>
<if test="areaType != null">#{areaType},</if>
<if test="customerArea != null">#{customerArea},</if>
<if test="isEnable != null">#{isEnable},</if>
<if test="salesUserId != null">#{salesUserId},</if>
<if test="salesUser != null">#{salesUser},</if>
@@ -387,7 +387,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="customerCodeDw != null">customer_code_dw = #{customerCodeDw},</if>
<if test="creditCode != null">credit_code = #{creditCode},</if>
<if test="customerType != null">customer_type = #{customerType},</if>
area_type = #{areaType},
customer_area = #{customerArea},
<if test="isEnable != null">is_enable = #{isEnable},</if>
sales_user_id = #{salesUserId},
sales_user = #{salesUser},
@@ -30,6 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
del_flag, create_by, sales_user_id, source_sales_code
<if test="customerCodeDw != null">, customer_code_dw</if>
<if test="customerType != null">, customer_type</if>
<if test="customerArea != null">, customer_area</if>
<if test="salesUser != null">, sales_user</if>
<if test="settlementUser != null">, settlement_user</if>
<if test="serviceUser != null">, service_user</if>
@@ -46,6 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
'0', #{createBy}, #{salesUserId}, #{sourceSalesCode}
<if test="customerCodeDw != null">, #{customerCodeDw}</if>
<if test="customerType != null">, #{customerType}</if>
<if test="customerArea != null">, #{customerArea}</if>
<if test="salesUser != null">, #{salesUser}</if>
<if test="settlementUser != null">, #{settlementUser}</if>
<if test="serviceUser != null">, #{serviceUser}</if>
@@ -66,6 +68,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="customerName != null">, customer_name = #{customerName}</if>
<if test="customerCodeDw != null">, customer_code_dw = #{customerCodeDw}</if>
<if test="customerType != null">, customer_type = #{customerType}</if>
<if test="customerArea != null">, customer_area = #{customerArea}</if>
, sales_user_id = #{salesUserId}
, source_sales_code = #{sourceSalesCode}
<if test="salesUser != null">, sales_user = #{salesUser}</if>
@@ -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
</select>
@@ -98,12 +98,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="commissionAmount" column="commission_amount"/>
<result property="commissionMissingOrderCount" column="commission_missing_order_count"/>
-->
<result property="incompleteOrderCount" column="incomplete_order_count"/>
</resultMap>
<resultMap type="PrcProfitReportSummary" id="PrcProfitReportSummaryResult">
<result property="orderCount" column="order_count"/>
<result property="incompleteOrderCount" column="incomplete_order_count"/>
<result property="currency" column="currency"/>
<result property="costAmount" column="cost_amount"/>
<result property="redlineAmount" column="redline_amount"/>
@@ -193,16 +191,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if>
</otherwise>
</choose>
<choose>
<!-- 提成未计算订单下钻暂停使用。
<when test="detailType == 'COMMISSION_MISSING'">
and (cr.commission_rate is null or i.product_amount is null or i.sales_amount is null)
</when>
-->
<when test="detailType == 'INCOMPLETE'">
and (i.product_amount is null or i.redline_amount is null or i.sales_amount is null)
</when>
</choose>
</where>
</sql>
@@ -271,15 +259,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
then i.sales_amount - i.product_amount else null end) * 100 /
sum(case when i.product_amount is not null and i.sales_amount is not null
then i.sales_amount else null end), 4)
end as sales_gross_margin_rate,
end as sales_gross_margin_rate
<!-- 提成金额与未计算订单数暂停使用。
sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
then (i.sales_amount - i.product_amount) * cr.commission_rate / 100 else null end) as commission_amount,
sum(case when cr.commission_rate is null or i.product_amount is null or i.sales_amount is null
then 1 else 0 end) as commission_missing_order_count,
-->
sum(case when i.product_amount is null or i.redline_amount is null or i.sales_amount is null
then 1 else 0 end) as incomplete_order_count
<include refid="profitReportFromAndWhere"/>
group by p.product_code, p.product_name, p.country_code, p.country_name, i.currency
order by p.product_code, p.country_code, i.currency
@@ -287,8 +273,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectSummary" resultMap="PrcProfitReportSummaryResult">
select i.currency, count(*) as order_count,
sum(case when i.product_amount is null or i.redline_amount is null or i.sales_amount is null
then 1 else 0 end) as incomplete_order_count,
sum(i.product_amount) as cost_amount,
sum(i.redline_amount) as redline_amount,
sum(case when i.product_amount is not null and i.redline_amount is not null
+1 -1
View File
@@ -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 '客户同步源业务员工号(内部字段)',
@@ -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;
@@ -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;
@@ -63,10 +63,10 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="区域类型" prop="areaType">
<el-select v-model="form.areaType" placeholder="请选择区域类型" clearable style="width: 100%;">
<el-form-item label="客户区域" prop="customerArea">
<el-select v-model="form.customerArea" placeholder="请选择客户区域" clearable style="width: 100%;">
<el-option
v-for="dict in data_area_type"
v-for="dict in customer_area"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@@ -739,7 +739,7 @@ const router = useRouter()
const { settlement_type } = useDict('settlement_type')
const { customer_type } = useDict('customer_type')
const { data_area_type } = useDict('data_area_type')
const { customer_area } = useDict('customer_area')
const { ensureProducts, findProduct } = useProducts()
@@ -765,7 +765,7 @@ function buildEmptyForm() {
customerCodeDw: null,
creditCode: null,
customerType: null,
areaType: null,
customerArea: null,
isEnable: null,
salesUserId: null,
salesUser: null,
@@ -30,16 +30,16 @@
/>
</el-select>
</el-form-item>
<el-form-item label="区域类型" prop="areaType">
<el-form-item label="客户区域" prop="customerArea">
<el-select
v-model="queryParams.areaType"
placeholder="请选择区域类型"
v-model="queryParams.customerArea"
placeholder="请选择客户区域"
clearable
style="width: 160px"
@change="handleQuery"
>
<el-option
v-for="dict in data_area_type"
v-for="dict in customer_area"
:key="dict.value"
:label="dict.label"
:value="dict.value"
@@ -167,9 +167,9 @@
<dict-tag :options="customer_type" :value="scope.row.customerType" />
</template>
</el-table-column>
<el-table-column v-if="isColVisible('areaType')" label="区域类型" align="center" prop="areaType" width="110">
<el-table-column v-if="isColVisible('customerArea')" label="客户区域" align="center" prop="customerArea" width="110">
<template #default="scope">
<dict-tag :options="data_area_type" :value="scope.row.areaType" />
<dict-tag :options="customer_area" :value="scope.row.customerArea" />
</template>
</el-table-column>
<el-table-column v-if="isColVisible('isEnable')" label="启用状态" align="center" prop="isEnable">
@@ -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,
+14 -23
View File
@@ -16,16 +16,6 @@
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="业务员编码" class="filter-item">
<el-input v-model="query.belongSalerCode" clearable placeholder="输入业务员编码" class="filter-control" @keyup.enter="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="产品代码" class="filter-item">
<el-input v-model="query.productCode" clearable placeholder="输入产品代码" class="filter-control" @keyup.enter="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="客户名称" class="filter-item">
<customer-select
@@ -39,6 +29,16 @@
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="业务员编码" class="filter-item">
<el-input v-model="query.belongSalerCode" clearable placeholder="输入业务员编码" class="filter-control" @keyup.enter="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="产品代码" class="filter-item">
<el-input v-model="query.productCode" clearable placeholder="输入产品代码" class="filter-control" @keyup.enter="handleSearch" />
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :lg="8">
<el-form-item label="订单号" class="filter-item">
<el-input
@@ -98,9 +98,6 @@
<div class="metric-item"><div class="metric-label">提成金额</div><div class="metric-value">{{ money(summary.commissionAmount) }}</div></div>
</el-col>
-->
<el-col :xs="12" :sm="8" :md="6">
<div class="metric-item"><div class="metric-label">价格缺失订单</div><div class="metric-value">{{ summary.incompleteOrderCount || 0 }}</div></div>
</el-col>
<!-- 提成功能暂停使用。
<el-col :xs="12" :sm="8" :md="6">
<div class="metric-item"><div class="metric-label">提成未计算订单</div><div class="metric-value">{{ summary.commissionMissingOrderCount || 0 }}</div></div>
@@ -149,7 +146,7 @@
<el-table-column prop="countryCode" label="国家代码" width="100" align="center" />
<el-table-column prop="currency" label="币种" width="80" align="center" />
<el-table-column prop="orderCount" label="订单数" width="100" align="right">
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.orderCount }" @click.stop="openOrderList(row, 'ALL', '订单数')">{{ row.orderCount }}</span></template>
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.orderCount }" @click.stop="openOrderList(row)">{{ row.orderCount }}</span></template>
</el-table-column>
<el-table-column prop="costAmount" label="产品价" min-width="130" align="right"><template #default="{ row }">{{ money(row.costAmount) }}</template></el-table-column>
<el-table-column prop="redlineAmount" label="红线价" min-width="130" align="right"><template #default="{ row }">{{ money(row.redlineAmount) }}</template></el-table-column>
@@ -164,9 +161,6 @@
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.commissionMissingOrderCount }" @click.stop="openOrderList(row, 'COMMISSION_MISSING', '提成未计算订单')">{{ row.commissionMissingOrderCount }}</span></template>
</el-table-column>
-->
<el-table-column prop="incompleteOrderCount" label="价格缺失订单" width="130" align="right">
<template #default="{ row }"><span class="success-value order-count-link" :class="{ 'is-disabled': !row.incompleteOrderCount }" @click.stop="openOrderList(row, 'INCOMPLETE', '价格缺失订单')">{{ row.incompleteOrderCount }}</span></template>
</el-table-column>
</template>
<template v-else>
<el-table-column prop="bizDate" label="计费时间" width="170" align="center"><template #default="{ row }">{{ parseTime(row.bizDate) }}</template></el-table-column>
@@ -446,15 +440,12 @@ function handleDimensionChange() {
Promise.all([loadSummary(), loadRows()])
}
function openOrderList(row, detailType, label) {
function openOrderList(row) {
if (!validateMultiValueFilters()) return
// 提成未计算订单下钻暂停使用:detailType === 'COMMISSION_MISSING' ? row.commissionMissingOrderCount
const count = detailType === 'ALL' ? row.orderCount : row.incompleteOrderCount
if (!count) return
orderListTitle.value = `${label}订单列表`
if (!row.orderCount) return
orderListTitle.value = '订单列表'
orderListContext.value = {
productDrilldown: true,
detailType,
productCode: row.productCode,
countryCode: row.countryCode,
currency: row.currency