2025-06-17 19:07:13 +08:00
|
|
|
|
import React, { useState, useEffect, useMemo, useCallback, memo } from 'react';
|
|
|
|
|
import { bitable, CurrencyCode, FieldType, ICurrencyField, ICurrencyFieldMeta } from '@lark-base-open/js-sdk';
|
|
|
|
|
import { Card, Modal, Checkbox, message } from 'antd';
|
|
|
|
|
import './App.css';
|
|
|
|
|
|
2025-07-02 11:46:27 +08:00
|
|
|
|
// 客户配置类型定义
|
|
|
|
|
interface CustomerOptionGroup {
|
|
|
|
|
title: string; // 客户名称
|
|
|
|
|
options: CustomerTagGroup[]; // 客户专属标签组
|
|
|
|
|
isDefault?: boolean; // 是否为默认客户
|
2025-06-17 19:07:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:46:27 +08:00
|
|
|
|
// 客户标签组类型定义
|
|
|
|
|
interface CustomerTagGroup {
|
|
|
|
|
title: string; // 标签组标题
|
|
|
|
|
options: string[]; // 标签选项
|
|
|
|
|
required: boolean; // 是否必填
|
|
|
|
|
level?: number; // 层级
|
|
|
|
|
parentOption?: string; // 父选项
|
|
|
|
|
condition?: (checkedList: string[]) => boolean; // 显示条件
|
|
|
|
|
resetOn?: string[]; // 重置条件
|
|
|
|
|
multiple?: boolean; // 是否支持多选
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 客户配置 - 按客户分组管理标签
|
|
|
|
|
const CUSTOMER_CONFIG: CustomerOptionGroup[] = [
|
|
|
|
|
// PDS 客户配置
|
2025-06-27 16:17:24 +08:00
|
|
|
|
{
|
2025-07-02 11:46:27 +08:00
|
|
|
|
title: 'PDS',
|
2025-06-27 16:17:24 +08:00
|
|
|
|
options: [
|
2025-07-02 11:46:27 +08:00
|
|
|
|
{
|
|
|
|
|
title: '单据类型',
|
|
|
|
|
options: ['首单', '翻单'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '是否要打板',
|
|
|
|
|
options: ['需要打板', '不需要打板'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '首单',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('首单'),
|
|
|
|
|
resetOn: ['翻单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '批色样',
|
|
|
|
|
options: ['要批色样', '不要批色样'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '不需要打板',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('首单') && checkedList.includes('不需要打板'),
|
|
|
|
|
resetOn: ['翻单', '有变动需要修改', '无变动不需要修改']
|
|
|
|
|
},
|
2025-07-09 18:14:13 +08:00
|
|
|
|
{
|
|
|
|
|
title: '翻单变动',
|
|
|
|
|
options: ['无变动不需要修改', '有变动需要修改'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '翻单',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('翻单'),
|
|
|
|
|
resetOn: ['首单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '特殊订单',
|
2025-07-09 19:30:27 +08:00
|
|
|
|
options: ['换料寄面料样', '换料重新打板', '改尺寸重新打板','改尺寸不打版','加色'],
|
2025-07-09 18:14:13 +08:00
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '有变动需要修改',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('有变动需要修改'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改']
|
|
|
|
|
},
|
2025-07-09 19:30:27 +08:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
title: '批色样',
|
|
|
|
|
options: ['需要打板','要批色样','不要批色样'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 5,
|
|
|
|
|
parentOption: '加色',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('加色'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改', '需要打板', '不需要打板']
|
|
|
|
|
},
|
2025-07-02 11:46:27 +08:00
|
|
|
|
{
|
|
|
|
|
title: '品类',
|
|
|
|
|
options: ['牛仔', '时装'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '复杂度',
|
|
|
|
|
options: ['简单款', '基础款', '复杂款'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '二次工艺',
|
|
|
|
|
options: ['绣花', '印花'],
|
|
|
|
|
required: false
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '是否需要批船样',
|
|
|
|
|
options: ['不需要批船样', '需要批船样'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '运输方式',
|
|
|
|
|
options: ['美国', '澳大利亚', '英国'],
|
|
|
|
|
required: false,
|
|
|
|
|
resetOn: ['PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '英国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'英国-海运',
|
|
|
|
|
'英国-空运 (直飞)',
|
|
|
|
|
'英国-空运 (转机)',
|
|
|
|
|
'英国-铁路(中欧班列)',
|
|
|
|
|
'英国-卡航',
|
|
|
|
|
'英国-卡空',
|
|
|
|
|
'英国-卡车联运',
|
|
|
|
|
'英国-海空联运'
|
|
|
|
|
],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '英国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('英国'),
|
|
|
|
|
resetOn: ['美国', '澳大利亚', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '美国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'美国-海运慢船',
|
|
|
|
|
'美国-海运快船',
|
|
|
|
|
'美国-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '美国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('美国'),
|
|
|
|
|
resetOn: ['英国', '澳大利亚', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '澳大利亚运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'澳大利亚-海运',
|
|
|
|
|
'澳大利亚-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '澳大利亚',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('澳大利亚'),
|
|
|
|
|
resetOn: ['美国', '英国', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '面料特性',
|
|
|
|
|
options: [
|
|
|
|
|
'普通面料(纯棉、常规化纤)',
|
|
|
|
|
'特殊面料(真丝、皮革、功能性面料)',
|
|
|
|
|
'易损面料(薄纱、蕾丝)'
|
|
|
|
|
],
|
|
|
|
|
required: false
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-06-27 16:17:24 +08:00
|
|
|
|
},
|
2025-07-02 11:46:27 +08:00
|
|
|
|
|
|
|
|
|
// LWH 客户配置
|
2025-06-27 16:17:24 +08:00
|
|
|
|
{
|
2025-07-02 11:46:27 +08:00
|
|
|
|
title: 'LWH',
|
2025-06-27 16:17:24 +08:00
|
|
|
|
options: [
|
2025-07-02 11:46:27 +08:00
|
|
|
|
{
|
|
|
|
|
title: '单据类型',
|
|
|
|
|
options: ['首单', '翻单'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '打板类型(多选)',
|
|
|
|
|
options: ['复版', 'PP版','不用打版'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '首单',
|
|
|
|
|
multiple: true,
|
|
|
|
|
condition: (checkedList) => checkedList.includes('首单'),
|
|
|
|
|
resetOn: ['翻单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '翻单变动',
|
|
|
|
|
options: ['无变动不需要修改', '有变动需要修改'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '翻单',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('翻单'),
|
|
|
|
|
resetOn: ['首单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '特殊订单',
|
|
|
|
|
options: ['换料寄面料样', '换料重新打板', '加色', '改尺寸重新打板','改尺寸不打版'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '有变动需要修改',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('有变动需要修改'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '特殊订单',
|
|
|
|
|
options: ['批大货布'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '无变动不需要修改',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('无变动不需要修改'),
|
|
|
|
|
resetOn: ['首单', '有变动需要修改']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '批色样',
|
|
|
|
|
options: ['寄成衣','寄色样'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 5,
|
|
|
|
|
parentOption: '加色',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('加色'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改', '需要打板', '不需要打板']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '品类',
|
|
|
|
|
options: ['牛仔', '时装'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '复杂度',
|
|
|
|
|
options: ['简单款', '基础款', '复杂款'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '二次工艺',
|
|
|
|
|
options: ['绣花', '印花'],
|
|
|
|
|
required: false
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '是否需要批船样',
|
|
|
|
|
options: ['不需要批船样', '需要批船样'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '运输方式',
|
|
|
|
|
options: ['美国', '澳大利亚', '英国'],
|
|
|
|
|
required: false,
|
|
|
|
|
resetOn: ['PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '英国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'英国-海运',
|
|
|
|
|
'英国-空运 (直飞)',
|
|
|
|
|
'英国-空运 (转机)',
|
|
|
|
|
'英国-铁路(中欧班列)',
|
|
|
|
|
'英国-卡航',
|
|
|
|
|
'英国-卡空',
|
|
|
|
|
'英国-卡车联运',
|
|
|
|
|
'英国-海空联运'
|
|
|
|
|
],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '英国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('英国'),
|
|
|
|
|
resetOn: ['美国', '澳大利亚', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '美国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'美国-海运慢船',
|
|
|
|
|
'美国-海运快船',
|
|
|
|
|
'美国-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '美国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('美国'),
|
|
|
|
|
resetOn: ['英国', '澳大利亚', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '澳大利亚运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'澳大利亚-海运',
|
|
|
|
|
'澳大利亚-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '澳大利亚',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('澳大利亚'),
|
|
|
|
|
resetOn: ['美国', '英国', 'PLT', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '面料特性',
|
|
|
|
|
options: [
|
|
|
|
|
'普通面料(纯棉、常规化纤)',
|
|
|
|
|
'特殊面料(真丝、皮革、功能性面料)',
|
|
|
|
|
'易损面料(薄纱、蕾丝)'
|
|
|
|
|
],
|
|
|
|
|
required: false
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-06-27 16:17:24 +08:00
|
|
|
|
},
|
2025-07-02 11:46:27 +08:00
|
|
|
|
|
|
|
|
|
// PLT 客户配置
|
2025-06-27 16:17:24 +08:00
|
|
|
|
{
|
2025-07-02 11:46:27 +08:00
|
|
|
|
title: 'PLT',
|
2025-06-27 16:17:24 +08:00
|
|
|
|
options: [
|
2025-07-02 11:46:27 +08:00
|
|
|
|
{
|
|
|
|
|
title: '单据类型',
|
|
|
|
|
options: ['首单', '翻单'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '打板类型(多选)',
|
2025-07-04 12:33:37 +08:00
|
|
|
|
options: ['复版', '拍照版','开货版需打版','不用打版'],
|
2025-07-02 11:46:27 +08:00
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '首单',
|
|
|
|
|
multiple: true,
|
|
|
|
|
condition: (checkedList) => checkedList.includes('首单'),
|
|
|
|
|
resetOn: ['翻单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '寄样方式',
|
|
|
|
|
options: ['寄裤筒', '寄成衣'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '不用打版',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('首单') && checkedList.includes('不用打版'),
|
|
|
|
|
resetOn: ['翻单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '翻单变动',
|
|
|
|
|
options: ['无变动不需要修改', '有变动需要修改'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 3,
|
|
|
|
|
parentOption: '翻单',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('翻单'),
|
|
|
|
|
resetOn: ['首单']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '特殊订单',
|
|
|
|
|
options: ['换料寄面料样', '换料重新打板', '改尺寸重新打板','改尺寸不打版'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '有变动需要修改',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('有变动需要修改'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '打版类型',
|
|
|
|
|
options: ['复版','拍照版'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 5,
|
|
|
|
|
parentOption: '换料重新打板',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('换料重新打板'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改','换料重新打板']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '打版类型',
|
|
|
|
|
options: ['复版','拍照版'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 5,
|
|
|
|
|
parentOption: '改尺寸重新打板',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('改尺寸重新打板'),
|
|
|
|
|
resetOn: ['首单', '无变动不需要修改','换料重新打板']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '特殊订单',
|
|
|
|
|
options: ['批大货布'],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 4,
|
|
|
|
|
parentOption: '无变动不需要修改',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('无变动不需要修改'),
|
|
|
|
|
resetOn: ['首单', '有变动需要修改']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '品类',
|
|
|
|
|
options: ['牛仔', '时装'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '复杂度',
|
|
|
|
|
options: ['简单款', '基础款', '复杂款'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '二次工艺',
|
|
|
|
|
options: ['绣花', '印花'],
|
|
|
|
|
required: false
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '是否需要批船样',
|
|
|
|
|
options: ['不需要批船样', '需要批船样'],
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '运输方式',
|
|
|
|
|
options: ['美国', '澳大利亚', '英国'],
|
|
|
|
|
required: false,
|
|
|
|
|
resetOn: ['RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '英国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'英国-海运',
|
|
|
|
|
'英国-空运 (直飞)',
|
|
|
|
|
'英国-空运 (转机)',
|
|
|
|
|
'英国-铁路(中欧班列)',
|
|
|
|
|
'英国-卡航',
|
|
|
|
|
'英国-卡空',
|
|
|
|
|
'英国-卡车联运',
|
|
|
|
|
'英国-海空联运'
|
|
|
|
|
],
|
|
|
|
|
required: false,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '英国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('英国'),
|
|
|
|
|
resetOn: ['美国', '澳大利亚', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '美国运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'美国-海运慢船',
|
|
|
|
|
'美国-海运快船',
|
|
|
|
|
'美国-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '美国',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('美国'),
|
|
|
|
|
resetOn: ['英国', '澳大利亚', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '澳大利亚运输方式',
|
|
|
|
|
options: [
|
|
|
|
|
'澳大利亚-海运',
|
|
|
|
|
'澳大利亚-空运(直飞)'
|
|
|
|
|
],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2,
|
|
|
|
|
parentOption: '澳大利亚',
|
|
|
|
|
condition: (checkedList) => checkedList.includes('澳大利亚'),
|
|
|
|
|
resetOn: ['美国', '英国', 'RBE']
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '面料特性',
|
|
|
|
|
options: [
|
|
|
|
|
'普通面料(纯棉、常规化纤)',
|
|
|
|
|
'特殊面料(真丝、皮革、功能性面料)',
|
|
|
|
|
'易损面料(薄纱、蕾丝)'
|
|
|
|
|
],
|
|
|
|
|
required: false
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-06-27 16:17:24 +08:00
|
|
|
|
},
|
2025-07-02 11:46:27 +08:00
|
|
|
|
|
|
|
|
|
// RBE 客户配置 - 简化示例
|
2025-06-27 16:17:24 +08:00
|
|
|
|
{
|
2025-07-02 11:46:27 +08:00
|
|
|
|
title: 'RBE',
|
2025-06-27 16:17:24 +08:00
|
|
|
|
options: [
|
2025-07-02 11:46:27 +08:00
|
|
|
|
{
|
|
|
|
|
title: '特殊订单类型',
|
|
|
|
|
options: ['紧急订单', '常规订单'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: '运输优先级',
|
|
|
|
|
options: ['标准运输', '加急运输', '特快运输'],
|
|
|
|
|
required: true,
|
|
|
|
|
level: 3
|
|
|
|
|
}
|
|
|
|
|
]
|
2025-06-17 19:07:13 +08:00
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const FABRIC_TEST_OPTIONS = ['需要面料测试', '不需要面料测试'];
|
|
|
|
|
|
|
|
|
|
// 优化:预计算选项集合,避免重复includes操作
|
|
|
|
|
const createOptionSets = (checkedList: string[]) => {
|
|
|
|
|
const checkedSet = new Set(checkedList);
|
|
|
|
|
return {
|
|
|
|
|
checkedSet,
|
|
|
|
|
hasFirstOrder: checkedSet.has('首单'),
|
|
|
|
|
hasReorder: checkedSet.has('翻单'),
|
|
|
|
|
hasNoChange: checkedSet.has('无变动不需要修改'),
|
|
|
|
|
hasChange: checkedSet.has('有变动需要修改'),
|
|
|
|
|
hasAddColor: checkedSet.has('加色'),
|
|
|
|
|
hasNoPlate: checkedSet.has('不需要打板')
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 优化:使用memo包装OptionGroup组件
|
|
|
|
|
interface OptionGroupProps {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
group: CustomerTagGroup;
|
2025-06-17 19:07:13 +08:00
|
|
|
|
checkedList: string[];
|
2025-07-02 11:46:27 +08:00
|
|
|
|
customer: string;
|
2025-06-17 19:07:13 +08:00
|
|
|
|
onChange: (newList: string[]) => void;
|
|
|
|
|
lockedOptions?: string[];
|
|
|
|
|
level?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const OptionGroup = memo<OptionGroupProps>(({
|
|
|
|
|
group,
|
|
|
|
|
checkedList,
|
2025-07-02 11:46:27 +08:00
|
|
|
|
customer,
|
2025-06-17 19:07:13 +08:00
|
|
|
|
onChange,
|
|
|
|
|
lockedOptions = [],
|
|
|
|
|
level = 1
|
|
|
|
|
}) => {
|
2025-06-27 16:17:24 +08:00
|
|
|
|
// 使用配置中的 multiple 属性,默认为 false(单选)
|
|
|
|
|
const isMulti = group.multiple || false;
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
// 优化:使用useMemo缓存计算结果
|
|
|
|
|
const groupChecked = useMemo(() =>
|
|
|
|
|
checkedList.filter(v => group.options.includes(v)),
|
|
|
|
|
[checkedList, group.options]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const indentStyle = useMemo(() => ({
|
|
|
|
|
marginLeft: level > 1 ? (level - 1) * 24 : 0,
|
|
|
|
|
marginTop: level > 1 ? 8 : 0,
|
|
|
|
|
borderLeft: level > 1 ? `${level > 2 ? 'dashed' : 'solid'} 2px #eee` : 'none',
|
|
|
|
|
paddingLeft: level > 1 ? 12 : 0
|
|
|
|
|
}), [level]);
|
|
|
|
|
|
|
|
|
|
const titleColor = useMemo(() => {
|
|
|
|
|
switch(level) {
|
|
|
|
|
case 1: return '#000';
|
|
|
|
|
case 2: return '#888';
|
|
|
|
|
case 3: return '#b36d00';
|
|
|
|
|
default: return '#888';
|
|
|
|
|
}
|
|
|
|
|
}, [level]);
|
|
|
|
|
|
|
|
|
|
const options = useMemo(() =>
|
|
|
|
|
group.options.map(opt => ({
|
|
|
|
|
label: opt,
|
|
|
|
|
value: opt,
|
|
|
|
|
disabled: lockedOptions.includes(opt)
|
|
|
|
|
})),
|
|
|
|
|
[group.options, lockedOptions]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleChange = useCallback((list: string[]) => {
|
|
|
|
|
const others = checkedList.filter(v => !group.options.includes(v));
|
|
|
|
|
let newList;
|
|
|
|
|
if (isMulti) {
|
2025-06-27 16:17:24 +08:00
|
|
|
|
// 多选模式:保留所有选中项
|
2025-06-17 19:07:13 +08:00
|
|
|
|
newList = [...others, ...list];
|
|
|
|
|
} else {
|
2025-06-27 16:17:24 +08:00
|
|
|
|
// 单选模式:只保留最后选中的一项
|
2025-06-17 19:07:13 +08:00
|
|
|
|
newList = [...others, list.slice(-1)[0]].filter(Boolean);
|
|
|
|
|
}
|
|
|
|
|
onChange(newList);
|
|
|
|
|
}, [checkedList, group.options, isMulti, onChange]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div key={group.title} style={{ ...indentStyle, marginBottom: 12 }}>
|
|
|
|
|
<div style={{ fontWeight: 'bold', marginBottom: 4, color: titleColor }}>
|
|
|
|
|
{group.title}
|
|
|
|
|
{group.required && <span style={{ color: 'red', marginLeft: 4 }}>*</span>}
|
|
|
|
|
</div>
|
|
|
|
|
<Checkbox.Group
|
|
|
|
|
options={options}
|
|
|
|
|
value={groupChecked}
|
|
|
|
|
onChange={handleChange}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
2025-07-02 11:46:27 +08:00
|
|
|
|
// 客户选择器组件 - 添加变更时清空选项的功能
|
|
|
|
|
const CustomerSelector = memo(({ customers, selectedCustomer, onChange, onCustomerChange }) => {
|
|
|
|
|
return (
|
|
|
|
|
<div style={{ marginBottom: 16 }}>
|
|
|
|
|
<div style={{ fontWeight: 'bold', marginBottom: 8 }}>选择客户:</div>
|
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
|
|
|
|
|
{customers.map(customer => (
|
|
|
|
|
<button
|
|
|
|
|
key={customer.title}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
if (customer.title !== selectedCustomer) {
|
|
|
|
|
onCustomerChange(customer.title);
|
|
|
|
|
}
|
|
|
|
|
onChange(customer.title);
|
|
|
|
|
}}
|
|
|
|
|
style={{
|
|
|
|
|
padding: '8px 16px',
|
|
|
|
|
borderRadius: 4,
|
|
|
|
|
border: selectedCustomer === customer.title ? '2px solid #1677ff' : '1px solid #d9d9d9',
|
|
|
|
|
backgroundColor: selectedCustomer === customer.title ? '#e6f7ff' : '#fff',
|
|
|
|
|
cursor: 'pointer',
|
|
|
|
|
fontWeight: selectedCustomer === customer.title ? 'bold' : 'normal'
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{customer.title}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
2025-06-17 19:07:13 +08:00
|
|
|
|
// 优化:使用memo包装OrderConfigSelector组件
|
|
|
|
|
interface OrderConfigSelectorProps {
|
|
|
|
|
selectedRecordId: string | null;
|
|
|
|
|
checkedList: string[];
|
|
|
|
|
setCheckedList: (list: string[]) => void;
|
2025-07-02 11:46:27 +08:00
|
|
|
|
selectedCustomer: string;
|
|
|
|
|
setSelectedCustomer: (customer: string) => void;
|
2025-06-17 19:07:13 +08:00
|
|
|
|
onSubmit: (options: string[]) => void;
|
|
|
|
|
onCancel: () => void;
|
|
|
|
|
loading: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const OrderConfigSelector = memo<OrderConfigSelectorProps>(({
|
|
|
|
|
selectedRecordId,
|
|
|
|
|
checkedList,
|
|
|
|
|
setCheckedList,
|
2025-07-02 11:46:27 +08:00
|
|
|
|
selectedCustomer,
|
|
|
|
|
setSelectedCustomer,
|
2025-06-17 19:07:13 +08:00
|
|
|
|
onSubmit,
|
|
|
|
|
onCancel,
|
|
|
|
|
loading
|
|
|
|
|
}) => {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
// 查找当前选中客户的配置
|
|
|
|
|
const customerConfig = useMemo(() =>
|
|
|
|
|
CUSTOMER_CONFIG.find(c => c.title === selectedCustomer) || CUSTOMER_CONFIG[0],
|
|
|
|
|
[selectedCustomer]
|
|
|
|
|
);
|
|
|
|
|
|
2025-06-17 19:07:13 +08:00
|
|
|
|
// 优化:使用useMemo缓存可见的选项组
|
|
|
|
|
const visibleGroups = useMemo(() => {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
if (!customerConfig) return [];
|
|
|
|
|
|
|
|
|
|
// 筛选出可见的选项组
|
|
|
|
|
return customerConfig.options.filter(group => {
|
|
|
|
|
// 如果没有定义显示条件,默认为可见
|
|
|
|
|
if (!group.condition) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 有显示条件的,检查条件是否满足
|
2025-06-17 19:07:13 +08:00
|
|
|
|
return group.condition(checkedList);
|
|
|
|
|
});
|
2025-07-02 11:46:27 +08:00
|
|
|
|
}, [checkedList, customerConfig]);
|
|
|
|
|
|
|
|
|
|
// 当客户变更时清空选项
|
|
|
|
|
const handleCustomerChange = useCallback((newCustomer: string) => {
|
|
|
|
|
console.log(`客户变更为: ${newCustomer},清空当前选项`);
|
|
|
|
|
setCheckedList([]);
|
|
|
|
|
}, [setCheckedList]);
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
// 优化:使用useCallback缓存事件处理函数
|
|
|
|
|
const handleCheckedListChange = useCallback((newList: string[]) => {
|
|
|
|
|
const addedOptions = newList.filter(opt => !checkedList.includes(opt));
|
|
|
|
|
|
|
|
|
|
if (addedOptions.length > 0) {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
const resetGroups = customerConfig?.options.filter(group =>
|
2025-06-17 19:07:13 +08:00
|
|
|
|
group.resetOn?.some(resetOpt => addedOptions.includes(resetOpt))
|
2025-07-02 11:46:27 +08:00
|
|
|
|
) || [];
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
if (resetGroups.length > 0) {
|
|
|
|
|
const resetGroupsSet = new Set(resetGroups);
|
|
|
|
|
const filteredOptions = newList.filter(opt => {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
const group = customerConfig?.options.find(g => g.options.includes(opt));
|
|
|
|
|
return !(group && resetGroupsSet.has(group));
|
2025-06-17 19:07:13 +08:00
|
|
|
|
});
|
|
|
|
|
setCheckedList(filteredOptions);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setCheckedList(newList);
|
2025-07-02 11:46:27 +08:00
|
|
|
|
}, [checkedList, setCheckedList, customerConfig]);
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
// 优化:使用useCallback缓存验证函数
|
|
|
|
|
const validateRequired = useCallback(() => {
|
2025-07-02 11:46:27 +08:00
|
|
|
|
if (!customerConfig) {
|
|
|
|
|
message.error('请选择客户');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证可见的必填项
|
|
|
|
|
for (const group of visibleGroups) {
|
|
|
|
|
if (group.required) {
|
2025-06-17 19:07:13 +08:00
|
|
|
|
const has = checkedList.some(v => group.options.includes(v));
|
|
|
|
|
if (!has) {
|
|
|
|
|
message.error(`请至少选择一项【${group.title}】`);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 特殊验证:如果选择了"不需要打板",必须选择是否批色样
|
|
|
|
|
if (checkedList.includes('首单') && checkedList.includes('不需要打板')) {
|
|
|
|
|
const hasColorSample = checkedList.some(v => v === '要批色样' || v === '不要批色样');
|
|
|
|
|
if (!hasColorSample) {
|
|
|
|
|
message.error('请选择是否要批色样');
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2025-07-02 11:46:27 +08:00
|
|
|
|
}, [checkedList, customerConfig, visibleGroups]);
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
const needFabricTestDialog = useCallback(() => {
|
|
|
|
|
return !(checkedList.includes('翻单') && checkedList.includes('无变动不需要修改'));
|
|
|
|
|
}, [checkedList]);
|
|
|
|
|
|
|
|
|
|
const [showFabricTestModal, setShowFabricTestModal] = useState(false);
|
|
|
|
|
const [fabricTestSelection, setFabricTestSelection] = useState<string[]>([]);
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
|
const [finalOptions, setFinalOptions] = useState<string[]>([]);
|
|
|
|
|
|
|
|
|
|
const handleSubmit = useCallback(() => {
|
|
|
|
|
if (!validateRequired()) return;
|
|
|
|
|
|
|
|
|
|
setFinalOptions([...checkedList]);
|
|
|
|
|
|
|
|
|
|
if (needFabricTestDialog()) {
|
|
|
|
|
setFabricTestSelection([]);
|
|
|
|
|
setShowFabricTestModal(true);
|
|
|
|
|
} else {
|
|
|
|
|
onSubmit([...checkedList]);
|
|
|
|
|
}
|
|
|
|
|
}, [validateRequired, checkedList, needFabricTestDialog, onSubmit]);
|
|
|
|
|
|
|
|
|
|
const handleFabricTestSubmit = useCallback(() => {
|
|
|
|
|
if (fabricTestSelection.length === 0) {
|
|
|
|
|
message.error('请选择是否需要面料测试');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
onSubmit([...finalOptions, ...fabricTestSelection]);
|
|
|
|
|
setShowFabricTestModal(false);
|
|
|
|
|
}, [fabricTestSelection, finalOptions, onSubmit]);
|
|
|
|
|
|
|
|
|
|
const handleCancel = useCallback(() => {
|
|
|
|
|
onCancel();
|
|
|
|
|
setCheckedList([]);
|
|
|
|
|
}, [onCancel, setCheckedList]);
|
|
|
|
|
|
|
|
|
|
const handleFabricTestChange = useCallback((values: string[]) => {
|
|
|
|
|
if (values.length > 0) {
|
|
|
|
|
setFabricTestSelection([values[values.length - 1]]);
|
|
|
|
|
} else {
|
|
|
|
|
setFabricTestSelection([]);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!showFabricTestModal && isSubmitting) {
|
|
|
|
|
setIsSubmitting(false);
|
|
|
|
|
}
|
|
|
|
|
}, [showFabricTestModal, isSubmitting]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<Modal
|
|
|
|
|
title="订单配置"
|
|
|
|
|
open={!!selectedRecordId}
|
|
|
|
|
onOk={handleSubmit}
|
|
|
|
|
onCancel={handleCancel}
|
|
|
|
|
okText="确定"
|
|
|
|
|
cancelText="取消"
|
|
|
|
|
confirmLoading={loading}
|
2025-07-02 11:46:27 +08:00
|
|
|
|
width={768}
|
2025-06-17 19:07:13 +08:00
|
|
|
|
>
|
2025-07-02 11:46:27 +08:00
|
|
|
|
<CustomerSelector
|
|
|
|
|
customers={CUSTOMER_CONFIG}
|
|
|
|
|
selectedCustomer={selectedCustomer}
|
|
|
|
|
onChange={setSelectedCustomer}
|
|
|
|
|
onCustomerChange={handleCustomerChange}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{/* 只有选择了客户才显示标签组 */}
|
|
|
|
|
{selectedCustomer && customerConfig && (
|
|
|
|
|
<div>
|
|
|
|
|
{visibleGroups.map(group => (
|
|
|
|
|
<OptionGroup
|
|
|
|
|
key={group.title}
|
|
|
|
|
group={group}
|
|
|
|
|
checkedList={checkedList}
|
|
|
|
|
customer={selectedCustomer}
|
|
|
|
|
onChange={handleCheckedListChange}
|
|
|
|
|
level={group.level}
|
|
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-06-17 19:07:13 +08:00
|
|
|
|
</Modal>
|
|
|
|
|
|
|
|
|
|
<Modal
|
|
|
|
|
title="面料测试"
|
|
|
|
|
open={showFabricTestModal}
|
|
|
|
|
onOk={handleFabricTestSubmit}
|
|
|
|
|
onCancel={() => setShowFabricTestModal(false)}
|
|
|
|
|
okText="确定"
|
|
|
|
|
cancelText="取消"
|
|
|
|
|
confirmLoading={isSubmitting}
|
|
|
|
|
>
|
|
|
|
|
<div>
|
2025-06-17 19:35:59 +08:00
|
|
|
|
<p>请选择是否需要面料测试:</p>
|
2025-06-17 19:07:13 +08:00
|
|
|
|
<Checkbox.Group
|
|
|
|
|
options={FABRIC_TEST_OPTIONS}
|
|
|
|
|
value={fabricTestSelection}
|
|
|
|
|
onChange={handleFabricTestChange}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</Modal>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 优化:主应用组件
|
|
|
|
|
const App: React.FC = () => {
|
|
|
|
|
const [selectedRecordId, setSelectedRecordId] = useState<string | null>(null);
|
|
|
|
|
const [checkedList, setCheckedList] = useState<string[]>([]);
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
const [currentSelection, setCurrentSelection] = useState<{
|
|
|
|
|
tableId: string | null;
|
|
|
|
|
recordId: string | null;
|
|
|
|
|
}>({ tableId: null, recordId: null });
|
|
|
|
|
|
2025-07-02 11:46:27 +08:00
|
|
|
|
// 新增:当前选中的客户
|
|
|
|
|
const [selectedCustomer, setSelectedCustomer] = useState<string | null>(null);
|
|
|
|
|
|
2025-06-17 19:07:13 +08:00
|
|
|
|
// 优化:缓存字段选项映射,避免重复查找
|
|
|
|
|
const [fieldOptionsMap, setFieldOptionsMap] = useState<Map<string, {id: string, name: string}>>(new Map());
|
|
|
|
|
|
|
|
|
|
// 优化:使用useCallback缓存函数
|
|
|
|
|
const resetOptions = useCallback(() => {
|
|
|
|
|
setSelectedRecordId(null);
|
|
|
|
|
setCheckedList([]);
|
2025-07-02 11:46:27 +08:00
|
|
|
|
setSelectedCustomer(null); // 重置时也重置客户选择
|
2025-06-17 19:07:13 +08:00
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const saveOptions = useCallback(async () => {
|
|
|
|
|
if (!selectedRecordId || !currentSelection.tableId) {
|
|
|
|
|
message.warning('没有有效的选中记录或表格信息');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-02 11:46:27 +08:00
|
|
|
|
if (!selectedCustomer) {
|
|
|
|
|
message.error('请选择客户');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-17 19:07:13 +08:00
|
|
|
|
setLoading(true);
|
|
|
|
|
const FIELD_ID_TO_SAVE = 'fldTtRHwlo';
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const table = await bitable.base.getTableById(currentSelection.tableId);
|
|
|
|
|
if (!table) {
|
|
|
|
|
message.error('无法获取表格对象');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const field = await table.getFieldById(FIELD_ID_TO_SAVE);
|
|
|
|
|
if (!field) {
|
|
|
|
|
message.error('无法获取字段对象');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 优化:只在字段选项映射为空时才重新获取
|
|
|
|
|
let optionsMap = fieldOptionsMap;
|
|
|
|
|
if (optionsMap.size === 0) {
|
|
|
|
|
const fieldMeta = await field.getMeta();
|
|
|
|
|
console.log('字段元数据:', fieldMeta);
|
2025-06-17 19:48:14 +08:00
|
|
|
|
|
|
|
|
|
// 检查字段类型是否为多选或单选字段
|
|
|
|
|
let fieldOptions = [];
|
|
|
|
|
if (fieldMeta.type === FieldType.MultiSelect || fieldMeta.type === FieldType.SingleSelect) {
|
|
|
|
|
fieldOptions = (fieldMeta.property as any).options || [];
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-17 19:07:13 +08:00
|
|
|
|
optionsMap = new Map(fieldOptions.map(opt => [opt.name, opt]));
|
|
|
|
|
setFieldOptionsMap(optionsMap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let dataToSave = null;
|
|
|
|
|
if (checkedList.length > 0) {
|
|
|
|
|
console.log('字段中的所有选项:', Array.from(optionsMap.keys()));
|
|
|
|
|
console.log('要保存的选项:', checkedList);
|
|
|
|
|
|
|
|
|
|
// 优化:使用Map查找,O(1)时间复杂度
|
|
|
|
|
dataToSave = checkedList.map(optionText => {
|
|
|
|
|
const matchedOption = optionsMap.get(optionText);
|
|
|
|
|
if (!matchedOption) {
|
|
|
|
|
console.warn(`未找到选项 "${optionText}" 对应的ID`);
|
|
|
|
|
console.log('可能的匹配选项:', Array.from(optionsMap.keys()).filter(key =>
|
|
|
|
|
key.includes(optionText) || optionText.includes(key)
|
|
|
|
|
));
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
console.log(`找到匹配: "${optionText}" -> ID: ${matchedOption.id}`);
|
|
|
|
|
return {
|
|
|
|
|
id: matchedOption.id,
|
|
|
|
|
text: matchedOption.name
|
|
|
|
|
};
|
|
|
|
|
}).filter(Boolean);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log('准备保存的数据:', dataToSave);
|
|
|
|
|
await field.setValue(selectedRecordId, dataToSave);
|
|
|
|
|
|
|
|
|
|
const savedValue = await field.getValue(selectedRecordId);
|
|
|
|
|
console.log('保存后的字段值:', savedValue);
|
|
|
|
|
|
|
|
|
|
if (savedValue) {
|
|
|
|
|
console.log('数据成功写入单元格');
|
|
|
|
|
message.success('已保存选项');
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('数据写入后未能读取到值');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
console.error('保存失败:', e);
|
|
|
|
|
message.error(`保存失败: ${e.message || '未知错误'}`);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
resetOptions();
|
|
|
|
|
setCurrentSelection({ tableId: null, recordId: null });
|
|
|
|
|
}
|
2025-07-02 11:46:27 +08:00
|
|
|
|
}, [selectedRecordId, currentSelection.tableId, checkedList, fieldOptionsMap, resetOptions, selectedCustomer]);
|
2025-06-17 19:07:13 +08:00
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const unsubscribe = bitable.base.onSelectionChange(async (event: any) => {
|
|
|
|
|
try {
|
|
|
|
|
const { data } = event;
|
|
|
|
|
if (data && data.tableId && data.recordId) {
|
|
|
|
|
const isNewCell = (
|
|
|
|
|
data.tableId !== currentSelection.tableId ||
|
|
|
|
|
data.recordId !== currentSelection.recordId
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (isNewCell) {
|
|
|
|
|
resetOptions();
|
|
|
|
|
setCurrentSelection({
|
|
|
|
|
tableId: data.tableId,
|
|
|
|
|
recordId: data.recordId
|
|
|
|
|
});
|
|
|
|
|
// 优化:切换单元格时清空字段选项缓存
|
|
|
|
|
setFieldOptionsMap(new Map());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const table = await bitable.base.getTableById(data.tableId);
|
|
|
|
|
const cellValue = await table.getCellValue('fldTtRHwlo', data.recordId);
|
|
|
|
|
setSelectedRecordId(data.recordId);
|
|
|
|
|
|
|
|
|
|
if (typeof cellValue === 'string' && cellValue.trim() !== '') {
|
|
|
|
|
setCheckedList(cellValue.split(',').map(item => item.trim()));
|
|
|
|
|
} else if (Array.isArray(cellValue)) {
|
|
|
|
|
setCheckedList(cellValue.map(item => String(item)));
|
|
|
|
|
} else {
|
|
|
|
|
setCheckedList([]);
|
|
|
|
|
}
|
2025-07-02 11:46:27 +08:00
|
|
|
|
|
|
|
|
|
// 尝试从选中的选项中推断客户
|
|
|
|
|
const firstOption = checkedList[0];
|
|
|
|
|
const customer = CUSTOMER_CONFIG.find(c => c.options.some(g => g.options.includes(firstOption)));
|
|
|
|
|
if (customer) {
|
|
|
|
|
setSelectedCustomer(customer.title);
|
|
|
|
|
}
|
2025-06-17 19:07:13 +08:00
|
|
|
|
}
|
|
|
|
|
} catch (e: any) {
|
|
|
|
|
message.error('获取选中记录失败: ' + (e.message || e));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return unsubscribe;
|
|
|
|
|
}, [currentSelection, resetOptions]);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div style={{ padding: '16px' }}>
|
|
|
|
|
<Card>
|
|
|
|
|
<div>请先在多维表格中点击一个单元格以加载配置。</div>
|
|
|
|
|
</Card>
|
|
|
|
|
|
|
|
|
|
<OrderConfigSelector
|
|
|
|
|
selectedRecordId={selectedRecordId}
|
|
|
|
|
checkedList={checkedList}
|
|
|
|
|
setCheckedList={setCheckedList}
|
2025-07-02 11:46:27 +08:00
|
|
|
|
selectedCustomer={selectedCustomer || ''}
|
|
|
|
|
setSelectedCustomer={setSelectedCustomer}
|
2025-06-17 19:07:13 +08:00
|
|
|
|
onSubmit={saveOptions}
|
|
|
|
|
onCancel={resetOptions}
|
|
|
|
|
loading={loading}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default App;
|