From bbe701a890fbb04cace24095ba9e1a7561fe0586 Mon Sep 17 00:00:00 2001 From: mairuiming Date: Wed, 30 Jul 2025 19:51:19 +0800 Subject: [PATCH] 1 1 --- src/App.tsx | 1975 ++++++++++++++++++--------------------------------- 1 file changed, 699 insertions(+), 1276 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index fd84de5..3537baa 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,1305 +1,728 @@ -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 React, { useEffect, useState } from 'react'; +import { bitable, ITable, IRecord, FieldType, ISingleSelectField, IMultiSelectField } from '@lark-base-open/js-sdk'; +import { Card, Table, Typography, Button, Spin, Empty, Toast, Modal, Select, Dropdown } from '@douyinfe/semi-ui'; +import { IconPlus } from '@douyinfe/semi-icons'; import './App.css'; -// 客户配置类型定义 -interface CustomerOptionGroup { - title: string; // 客户名称 - options: CustomerTagGroup[]; // 客户专属标签组 - isDefault?: boolean; // 是否为默认客户 -} - -// 客户标签组类型定义 -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 客户配置 - { - title: 'PDS', - options: [ - { - 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: ['翻单', '有变动需要修改', '无变动不需要修改'] - }, - { - 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: true, - level: 5, - parentOption: '加色', - condition: (checkedList) => checkedList.includes('加色'), - resetOn: ['首单', '无变动不需要修改', '需要打板', '不需要打板'] - }, - { - title: '品类', - options: ['牛仔', '时装'], - required: true - }, - { - title: '复杂度', - options: ['简单款', '基础款', '复杂款'], - required: true - }, - { - title: '二次工艺', - options: ['绣花', '印花'], - multiple: true, - 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 - } - ] - }, - - // LWH 客户配置 - { - title: 'LWH', - options: [ - { - 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: ['绣花', '印花'], - multiple: true, - 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 - } - ] - }, - - // PLT 客户配置 - { - title: 'PLT', - options: [ - { - title: '单据类型', - options: ['首单', '翻单'], - required: true, - level: 2 - }, - { - title: '打板类型(多选)', - options: ['复版', '拍照版','开货版需打版','开货版不打版'], - 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: ['简单工艺(普通缝制、基础款T恤、常规裤装)', '中等工艺', '复杂工艺(立体裁剪、特殊刺绣、多色渐变印染、立体剪裁、特殊压褶)'], - required: true - }, - { - title: '订单量', - options: ['<500', '500-2000', '>2000'], - required: true - }, - { - title: '二次工艺', - options: ['绣花', '印花','压胶','烫标'], - multiple: true, - 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: true - } - ] - }, - - // RBE 客户配置 - 简化示例 - { - title: 'BE', - options: [ - { - title: '单据类型', - options: ['首单', '翻单'], - required: true, - level: 2 - }, - { - title: '打板类型(多选)', - options: ['复版', '拍照版','开货版需打版','开货版不打版'], - 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: ['绣花', '印花'], - multiple: true, - 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 - } - ] - }, - // RBE 客户配置 - 简化示例 - { - title: 'RIVER ISLAND', - options: [ - { - title: '单据类型', - options: ['首单', '翻单'], - required: true, - level: 2 - }, - { - title: '打板类型(多选)', - options: ['复版', '拍照版','测试版','开货版需打版','开货版不打版'], - 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: true, - multiple: true, - level: 5, - parentOption: '换料重新打板', - condition: (checkedList) => checkedList.includes('换料重新打板'), - resetOn: ['首单', '无变动不需要修改','换料重新打板'] - }, - { - title: '打版类型', - options: ['复版','拍照版','测试版'], - required: true, - multiple: true, - 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: ['面料寄SGS测试', '辅料寄SGS测试', '样衣寄SGS测试','无'], - required: true, - multiple: true - }, - { - title: '二次工艺', - options: ['绣花', '印花'], - required: false, - multiple: true - }, - { - 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 - } - ] - } -]; - -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('不需要打板') - }; +// 常量定义 +const CONSTANTS = { + POS_TABLE_NAME: 'pos_订单基础信息明细', + PROCESS_TABLE_NAME: '订单流程表', + POS_RECORD_ID_FIELD_NAME: 'POS表recordid', + TARGET_VIEW_NAME: '插件专用', + TEMPLATE_FIELD_NAME: '流程模板', + PROCESS_ORDER_FIELD: '流程顺序', + CURRENT_PROGRESS_FIELD: '当前进度', + PROCESS_NAME_FIELD: '流程名称', + FEISHU_CALLBACK_URL: 'https://open.feishu.cn/anycross/trigger/callback/MDgzNzk1ZTE1MGVhOWEzZTcyZDFjOTliZmJmOTNiYTZk', + DEFAULT_COLUMNS: ['操作', '款式SKC', '流程顺序', '流程名称', '实际开始时间', '实际完成时间'] }; -// 优化:使用memo包装OptionGroup组件 -interface OptionGroupProps { - group: CustomerTagGroup; - checkedList: string[]; - customer: string; - onChange: (newList: string[]) => void; - lockedOptions?: string[]; - level?: number; +// 类型定义 +interface ProcessRecord { + recordId: string; + fields: Record; + displayData: Record; } -const OptionGroup = memo(({ - group, - checkedList, - customer, - onChange, - lockedOptions = [], - level = 1 -}) => { - // 使用配置中的 multiple 属性,默认为 false(单选) - const isMulti = group.multiple || false; - - // 优化:使用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) { - // 多选模式:保留所有选中项 - newList = [...others, ...list]; - } else { - // 单选模式:只保留最后选中的一项 - newList = [...others, list.slice(-1)[0]].filter(Boolean); - } - onChange(newList); - }, [checkedList, group.options, isMulti, onChange]); - - return ( -
-
- {group.title} - {group.required && *} -
- -
- ); -}); - -// 客户选择器组件 - 添加变更时清空选项的功能 -const CustomerSelector = memo(({ customers, selectedCustomer, onChange, onCustomerChange }) => { - return ( -
-
选择客户:
-
- {customers.map(customer => ( - - ))} -
-
- ); -}); - -// 优化:使用memo包装OrderConfigSelector组件 -interface OrderConfigSelectorProps { - selectedRecordId: string | null; - checkedList: string[]; - setCheckedList: (list: string[]) => void; - selectedCustomer: string; - setSelectedCustomer: (customer: string) => void; - onSubmit: (options: string[]) => void; - onCancel: () => void; +interface AppState { + selectedRecordId?: string; + processRecords: ProcessRecord[]; loading: boolean; + error: string | null; + showAllColumns: boolean; + currentProgress: string | null; + nextProgress: string | null; + parallelProgress: string[]; } -const OrderConfigSelector = memo(({ - selectedRecordId, - checkedList, - setCheckedList, - selectedCustomer, - setSelectedCustomer, - onSubmit, - onCancel, - loading -}) => { - // 查找当前选中客户的配置 - const customerConfig = useMemo(() => - CUSTOMER_CONFIG.find(c => c.title === selectedCustomer) || CUSTOMER_CONFIG[0], - [selectedCustomer] - ); - - // 优化:使用useMemo缓存可见的选项组 - const visibleGroups = useMemo(() => { - if (!customerConfig) return []; - - // 筛选出可见的选项组 - return customerConfig.options.filter(group => { - // 如果没有定义显示条件,默认为可见 - if (!group.condition) { - return true; - } - - // 有显示条件的,检查条件是否满足 - return group.condition(checkedList); - }); - }, [checkedList, customerConfig]); - - // 当客户变更时清空选项 - const handleCustomerChange = useCallback((newCustomer: string) => { - console.log(`客户变更为: ${newCustomer},清空当前选项`); - setCheckedList([]); - }, [setCheckedList]); - - // 优化:使用useCallback缓存事件处理函数 - const handleCheckedListChange = useCallback((newList: string[]) => { - const addedOptions = newList.filter(opt => !checkedList.includes(opt)); - - if (addedOptions.length > 0) { - const resetGroups = customerConfig?.options.filter(group => - group.resetOn?.some(resetOpt => addedOptions.includes(resetOpt)) - ) || []; - - if (resetGroups.length > 0) { - const resetGroupsSet = new Set(resetGroups); - const filteredOptions = newList.filter(opt => { - const group = customerConfig?.options.find(g => g.options.includes(opt)); - return !(group && resetGroupsSet.has(group)); - }); - setCheckedList(filteredOptions); - return; - } +interface InsertState { + modalVisible: boolean; + currentRecord: ProcessRecord | null; + direction: 'up' | 'down' | null; + selectedTemplate: string[]; + templateOptions: { label: string; value: string }[]; +} + +interface TableState { + posTable: ITable | null; + processTable: ITable | null; + posRecordIdFieldId: string | null; + tableColumns: any[]; + allTableColumns: any[]; +} + +export default function App() { + // 状态管理 + const [appState, setAppState] = useState({ + processRecords: [], + loading: false, + error: null, + showAllColumns: false, + currentProgress: null, + nextProgress: null, + parallelProgress: [] + }); + + const [insertState, setInsertState] = useState({ + modalVisible: false, + currentRecord: null, + direction: null, + selectedTemplate: [], + templateOptions: [] + }); + + const [tableState, setTableState] = useState({ + posTable: null, + processTable: null, + posRecordIdFieldId: null, + tableColumns: [], + allTableColumns: [] + }); + + // 工具函数 + const formatDateTime = (value: any): string => { + if (!value || value === '-') return '-'; + try { + const timestamp = typeof value === 'string' && /^\d+$/.test(value) ? parseInt(value) : value; + const date = new Date(timestamp > 1000000000000 ? timestamp : timestamp * 1000); + if (isNaN(date.getTime())) return value; + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit' + }).replace(/\//g, '-'); + } catch { + return value; } - - setCheckedList(newList); - }, [checkedList, setCheckedList, customerConfig]); - - // 优化:使用useCallback缓存验证函数 - const validateRequired = useCallback(() => { - if (!customerConfig) { - message.error('请选择客户'); - return false; + }; + + const isDateField = (fieldName: string): boolean => { + return ['时间', '日期', 'time', 'date'].some(keyword => + fieldName.toLowerCase().includes(keyword.toLowerCase()) + ); + }; + + const updateAppState = (updates: Partial) => { + setAppState(prev => ({ ...prev, ...updates })); + }; + + const updateInsertState = (updates: Partial) => { + setInsertState(prev => ({ ...prev, ...updates })); + }; + + const updateTableState = (updates: Partial) => { + setTableState(prev => ({ ...prev, ...updates })); + }; + + // 初始化表格 + const initializeTables = async () => { + try { + updateAppState({ loading: true, error: null }); + + const tableList = await bitable.base.getTableList(); + const tables = await Promise.all( + tableList.map(async table => ({ table, name: await table.getName() })) + ); + + const posTable = tables.find(t => t.name === CONSTANTS.POS_TABLE_NAME)?.table; + const processTable = tables.find(t => t.name === CONSTANTS.PROCESS_TABLE_NAME)?.table; + + if (!posTable) throw new Error(`未找到表格: ${CONSTANTS.POS_TABLE_NAME}`); + if (!processTable) throw new Error(`未找到表格: ${CONSTANTS.PROCESS_TABLE_NAME}`); + + const processFields = await processTable.getFieldMetaList(); + const posRecordIdField = processFields.find(field => field.name === CONSTANTS.POS_RECORD_ID_FIELD_NAME); + + if (!posRecordIdField) { + throw new Error(`在表格 ${CONSTANTS.PROCESS_TABLE_NAME} 中未找到字段: ${CONSTANTS.POS_RECORD_ID_FIELD_NAME}`); + } + + // 设置表格列 + const actionColumn = { + title: '操作', + key: 'action', + width: 80, + fixed: 'left' as const, + render: (_: any, record: ProcessRecord) => renderInsertButton(record) + }; + + const dataColumns = processFields.map(field => ({ + title: field.name, + dataIndex: field.id, + key: field.id, + render: (value: any, record: ProcessRecord) => { + const displayValue = record.displayData[field.id] || '-'; + return isDateField(field.name) && displayValue !== '-' + ? formatDateTime(displayValue) + : displayValue; + } + })); + + const allColumns = [actionColumn, ...dataColumns]; + const visibleColumns = allColumns.filter(col => + appState.showAllColumns || CONSTANTS.DEFAULT_COLUMNS.includes(col.title) + ); + + updateTableState({ + posTable, + processTable, + posRecordIdFieldId: posRecordIdField.id, + allTableColumns: allColumns, + tableColumns: visibleColumns + }); + + } catch (error) { + const message = error instanceof Error ? error.message : '初始化失败'; + updateAppState({ error: message }); + Toast.error('初始化表格失败'); + } finally { + updateAppState({ loading: false }); } - - // 验证可见的必填项 - for (const group of visibleGroups) { - if (group.required) { - const has = checkedList.some(v => group.options.includes(v)); - if (!has) { - message.error(`请至少选择一项【${group.title}】`); - return false; + }; + + // 加载订单流程记录 + const loadProcessRecords = async (posRecordId: string) => { + const { processTable, posRecordIdFieldId } = tableState; + if (!processTable || !posRecordIdFieldId) { + Toast.error('系统未初始化完成,请稍后重试'); + return; + } + + try { + updateAppState({ loading: true }); + + const viewList = await processTable.getViewList(); + const targetView = await Promise.all( + viewList.map(async view => ({ view, meta: await view.getMeta() })) + ).then(views => views.find(v => v.meta.name === CONSTANTS.TARGET_VIEW_NAME)); + + if (!targetView) { + throw new Error(`未找到名为"${CONSTANTS.TARGET_VIEW_NAME}"的视图`); + } + + // 清理并设置筛选条件 + const currentFilterInfo = await targetView.view.getFilterInfo(); + if (currentFilterInfo?.conditions) { + await Promise.all( + currentFilterInfo.conditions.map(condition => + targetView.view.deleteFilterCondition(condition.conditionId) + ) + ); + } + + await targetView.view.addFilterCondition({ + fieldId: posRecordIdFieldId, + operator: 'is', + value: posRecordId + }); + + await targetView.view.setFilterConjunction('and'); + await targetView.view.applySetting(); + await new Promise(resolve => setTimeout(resolve, 500)); + + const recordsResponse = await processTable.getRecords({ + pageSize: 1000, + viewId: targetView.meta.id + }); + + const processedRecords = await Promise.all( + recordsResponse.records.map(async record => { + const fields = await record.fields; + const displayData: Record = {}; + + Object.entries(fields).forEach(([fieldId, value]) => { + if (value == null) { + displayData[fieldId] = '-'; + } else if (Array.isArray(value)) { + displayData[fieldId] = value.map(item => + typeof item === 'object' && item.text ? item.text : String(item) + ).join(', '); + } else if (typeof value === 'object' && value.text) { + displayData[fieldId] = value.text; + } else { + displayData[fieldId] = String(value); + } + }); + + return { recordId: record.recordId, fields, displayData }; + }) + ); + + // 计算进度信息和排序 + const { sortedRecords, progressInfo } = await processRecordsWithProgress( + processedRecords, processTable + ); + + updateAppState({ + processRecords: sortedRecords, + ...progressInfo + }); + + Toast.success(`找到 ${sortedRecords.length} 条匹配的订单流程记录`); + + } catch (error) { + const message = error instanceof Error ? error.message : '未知错误'; + Toast.error(`加载订单流程记录失败: ${message}`); + updateAppState({ processRecords: [] }); + } finally { + updateAppState({ loading: false }); + } + }; + + // 处理记录排序和进度计算 + const processRecordsWithProgress = async (records: ProcessRecord[], processTable: ITable) => { + const processFields = await processTable.getFieldMetaList(); + const orderField = processFields.find(f => f.name === CONSTANTS.PROCESS_ORDER_FIELD); + const currentProgressField = processFields.find(f => f.name === CONSTANTS.CURRENT_PROGRESS_FIELD); + const processNameField = processFields.find(f => f.name === CONSTANTS.PROCESS_NAME_FIELD); + + let progressInfo = { + currentProgress: null as string | null, + nextProgress: null as string | null, + parallelProgress: [] as string[] + }; + + // 计算进度信息 + if (currentProgressField && processNameField && orderField) { + const currentProgressRecord = records.find(record => { + const progressValue = record.fields[currentProgressField.id]; + return progressValue != null && progressValue !== ''; + }); + + if (currentProgressRecord) { + progressInfo.currentProgress = currentProgressRecord.displayData[processNameField.id]; + const currentOrder = Number(currentProgressRecord.fields[orderField.id]); + + const nextRecords = records + .filter(record => { + const order = Number(record.fields[orderField.id]); + return Number.isInteger(order) && order > currentOrder; + }) + .sort((a, b) => Number(a.fields[orderField.id]) - Number(b.fields[orderField.id])); + + if (nextRecords.length > 0) { + const nextRecord = nextRecords[0]; + progressInfo.nextProgress = nextRecord.displayData[processNameField.id]; + + const nextOrder = Number(nextRecord.fields[orderField.id]); + progressInfo.parallelProgress = records + .filter(record => { + const order = Number(record.fields[orderField.id]); + return !Number.isInteger(order) && Math.floor(order) === nextOrder && order > nextOrder; + }) + .sort((a, b) => Number(a.fields[orderField.id]) - Number(b.fields[orderField.id])) + .map(record => record.displayData[processNameField.id]); + } else { + progressInfo.nextProgress = '已完成所有流程'; } } } + + // 排序记录 + const sortedRecords = orderField ? records.sort((a, b) => { + const aNum = Number(a.fields[orderField.id]); + const bNum = Number(b.fields[orderField.id]); + if (!isNaN(aNum) && !isNaN(bNum)) return aNum - bNum; + if (isNaN(aNum) && !isNaN(bNum)) return 1; + if (!isNaN(aNum) && isNaN(bNum)) return -1; + return String(a.fields[orderField.id]).localeCompare(String(b.fields[orderField.id])); + }) : records; + + return { sortedRecords, progressInfo }; + }; + + // 加载模板选项 + const loadTemplateOptions = async () => { + let { posTable } = tableState; - // 特殊验证:如果选择了"不需要打板",必须选择是否批色样 - if (checkedList.includes('首单') && checkedList.includes('不需要打板')) { - const hasColorSample = checkedList.some(v => v === '要批色样' || v === '不要批色样'); - if (!hasColorSample) { - message.error('请选择是否要批色样'); - return false; + if (!posTable) { + try { + const tableList = await bitable.base.getTableList(); + const tables = await Promise.all( + tableList.map(async table => ({ table, name: await table.getName() })) + ); + posTable = tables.find(t => t.name === CONSTANTS.POS_TABLE_NAME)?.table || null; + if (!posTable) throw new Error('POS表未找到'); + updateTableState({ posTable }); + } catch (error) { + Toast.error('POS表初始化失败'); + return; } } - - return true; - }, [checkedList, customerConfig, visibleGroups]); - - const needFabricTestDialog = useCallback(() => { - return !(checkedList.includes('翻单') && checkedList.includes('无变动不需要修改')); - }, [checkedList]); - - const [showFabricTestModal, setShowFabricTestModal] = useState(false); - const [fabricTestSelection, setFabricTestSelection] = useState([]); - const [isSubmitting, setIsSubmitting] = useState(false); - const [finalOptions, setFinalOptions] = useState([]); - - const handleSubmit = useCallback(() => { - if (!validateRequired()) return; - - setFinalOptions([...checkedList]); - - if (needFabricTestDialog()) { - setFabricTestSelection([]); - setShowFabricTestModal(true); - } else { - onSubmit([...checkedList]); + + try { + const posFields = await posTable.getFieldMetaList(); + const templateField = posFields.find(field => field.name === CONSTANTS.TEMPLATE_FIELD_NAME); + + if (!templateField) { + Toast.error('未找到[流程模板]字段'); + return; + } + + let options: { label: string; value: string }[] = []; + + if (templateField.type === FieldType.MultiSelect) { + const field = await posTable.getField(templateField.id); + const fieldOptions = await field.getOptions(); + options = fieldOptions.map(option => ({ label: option.name, value: option.id })); + } else if (templateField.type === FieldType.SingleSelect) { + const field = await posTable.getField(templateField.id); + const fieldOptions = await field.getOptions(); + options = fieldOptions.map(option => ({ label: option.name, value: option.id })); + } else { + const records = await posTable.getRecords({ pageSize: 1000 }); + const uniqueTemplates = new Set(); + + for (const record of records.records) { + const fields = await record.fields; + const templateValue = fields[templateField.id]; + + if (typeof templateValue === 'string') { + uniqueTemplates.add(templateValue); + } else if (Array.isArray(templateValue)) { + templateValue.forEach(value => { + const text = typeof value === 'object' && value.text ? value.text : String(value); + if (text) uniqueTemplates.add(text); + }); + } else if (templateValue?.text) { + uniqueTemplates.add(templateValue.text); + } + } + + options = Array.from(uniqueTemplates).map(template => ({ + label: template, + value: template + })); + } + + updateInsertState({ templateOptions: options }); + } catch (error) { + Toast.error(`获取流程模板选项失败: ${error instanceof Error ? error.message : '未知错误'}`); } - }, [validateRequired, checkedList, needFabricTestDialog, onSubmit]); - - const handleFabricTestSubmit = useCallback(() => { - if (fabricTestSelection.length === 0) { - message.error('请选择是否需要面料测试'); + }; + + // 处理插入确认 + const handleInsertConfirm = async () => { + const { selectedTemplate, currentRecord, direction } = insertState; + + if (!selectedTemplate.length) { + Toast.warning('请选择一个或多个流程模板'); 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([]); + if (!currentRecord) { + Toast.error('系统状态不完整,无法执行操作'); + return; } - }, []); - - useEffect(() => { - if (!showFabricTestModal && isSubmitting) { - setIsSubmitting(false); + + try { + updateAppState({ loading: true }); + + const processFields = await tableState.processTable!.getFieldMetaList(); + const processOrderField = processFields.find(field => field.name === CONSTANTS.PROCESS_ORDER_FIELD); + + if (!processOrderField) throw new Error('未找到"流程顺序"字段'); + + const currentOrder = currentRecord.fields[processOrderField.id]; + if (currentOrder == null) throw new Error('当前记录缺少"流程顺序"值'); + + const newOrder = Number(currentOrder) + (direction === 'up' ? -0.1 : 0.1); + + const callbackData = { + selectedTemplates: selectedTemplate, + processOrder: currentOrder, + insertDirection: direction, + newProcessOrder: newOrder, + recordId: appState.selectedRecordId, + timestamp: new Date().toISOString() + }; + + await fetch(CONSTANTS.FEISHU_CALLBACK_URL, { + method: 'POST', + mode: 'no-cors', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(callbackData) + }); + + Toast.success('数据已发送到飞书回调'); + + } catch (error) { + Toast.error(`操作失败: ${error instanceof Error ? error.message : '未知错误'}`); + } finally { + updateAppState({ loading: false }); + resetInsertState(); } - }, [showFabricTestModal, isSubmitting]); - - return ( - <> - - - - {/* 只有选择了客户才显示标签组 */} - {selectedCustomer && customerConfig && ( -
- {visibleGroups.map(group => ( - + }; + + // 重置插入状态 + const resetInsertState = () => { + updateInsertState({ + modalVisible: false, + currentRecord: null, + direction: null, + selectedTemplate: [], + templateOptions: [] + }); + }; + + // 渲染插入按钮 + const renderInsertButton = (record: ProcessRecord) => { + const handleDirectionSelect = (direction: 'up' | 'down') => { + updateInsertState({ + direction, + currentRecord: record, + modalVisible: true + }); + loadTemplateOptions(); + }; + + return ( + + {['up', 'down'].map(dir => ( +
handleDirectionSelect(dir as 'up' | 'down')} + style={{ padding: '8px 16px', cursor: 'pointer' }} + > + {dir === 'up' ? '向上插入' : '向下插入'} +
))}
+ } + > + + + ); + }; + + // 切换列显示 + const toggleColumns = () => { + const newShowAll = !appState.showAllColumns; + const columnsToShow = newShowAll + ? tableState.allTableColumns + : tableState.allTableColumns.filter(col => CONSTANTS.DEFAULT_COLUMNS.includes(col.title)); + + updateAppState({ showAllColumns: newShowAll }); + updateTableState({ tableColumns: columnsToShow }); + }; + + // Effects + useEffect(() => { + initializeTables(); + }, []); + + useEffect(() => { + let cleanup: (() => void) | undefined; + + const setupSelectionListener = async () => { + const { posTable, processTable, posRecordIdFieldId } = tableState; + if (!posTable || !processTable || !posRecordIdFieldId) return; + + try { + const meta = await posTable.getMeta(); + cleanup = bitable.base.onSelectionChange(async (event) => { + if (event.data?.tableId === meta.id && event.data?.recordId) { + updateAppState({ selectedRecordId: event.data.recordId }); + await loadProcessRecords(event.data.recordId); + } + }); + } catch (error) { + console.error('设置选择监听失败:', error); + } + }; + + setupSelectionListener(); + return () => cleanup?.(); + }, [tableState.posTable, tableState.processTable, tableState.posRecordIdFieldId]); + + // 渲染组件 + const renderProgressInfo = () => { + const { currentProgress, nextProgress, parallelProgress } = appState; + if (!currentProgress && !nextProgress) return null; + + return ( + + + 进度信息 + +
+ {currentProgress && ( +
+ + 当前进度 + + + {currentProgress} + +
+ )} + {nextProgress && ( +
+ + 下个进度 + + + {nextProgress} + +
+ )} + {parallelProgress.length > 0 && ( +
+ + 下个进度-并行进度 + + + {parallelProgress.join(', ')} + +
+ )} +
+
+ ); + }; + + const renderUsageInstructions = () => ( + + + 使用说明 + + + 1. 在 {CONSTANTS.POS_TABLE_NAME} 表中点击选择任意单元格
+ 2. 系统将自动获取该记录的ID
+ 3. 在 {CONSTANTS.PROCESS_TABLE_NAME} 表中筛选 {CONSTANTS.POS_RECORD_ID_FIELD_NAME} 字段匹配的记录
+ 4. 在下方表格中展示筛选结果
+ 5. 点击"展开所有字段"按钮可查看完整信息 +
+
+ ); + + return ( +
+ 订单流程查询 + + {/* 当前选中记录信息 */} + + + 当前选中记录 + + {appState.selectedRecordId ? ( + + 记录ID: {appState.selectedRecordId} + + ) : ( + + 请在 {CONSTANTS.POS_TABLE_NAME} 表中选择一条记录 + + )} + + + {/* 筛选结果 */} + {appState.selectedRecordId && ( + <> + {renderProgressInfo()} + + +
+ + 匹配的订单流程记录 + +
+ + {appState.loading && } +
+
+ + {appState.processRecords.length > 0 ? ( + `共 ${total} 条记录` + }} + rowKey="recordId" + size="small" + scroll={{ x: 'max-content' }} + style={{ marginTop: 16 }} + /> + ) : ( + !appState.loading && ( + + 未找到匹配的订单流程记录 + + } + style={{ marginTop: 20 }} + /> + ) + )} + + + )} + + {/* 使用说明 */} + {!appState.selectedRecordId && renderUsageInstructions()} + + {/* 流程模板选择弹窗 */} + +
+ 请选择要插入的流程模板: +
+ + + + {insertState.selectedTemplate.length > 0 && ( +
+ + 已选择: {insertState.selectedTemplate.map(id => + insertState.templateOptions.find(opt => opt.value === id)?.label + ).filter(Boolean).join(', ')} + +
)}
- - setShowFabricTestModal(false)} - okText="确定" - cancelText="取消" - confirmLoading={isSubmitting} - > -
-

请选择是否需要面料测试:

- -
-
- - ); -}); - -// 优化:主应用组件 -const App: React.FC = () => { - const [selectedRecordId, setSelectedRecordId] = useState(null); - const [checkedList, setCheckedList] = useState([]); - const [loading, setLoading] = useState(false); - const [currentSelection, setCurrentSelection] = useState<{ - tableId: string | null; - recordId: string | null; - }>({ tableId: null, recordId: null }); - - // 新增:当前选中的客户 - const [selectedCustomer, setSelectedCustomer] = useState(null); - - // 优化:缓存字段选项映射,避免重复查找 - const [fieldOptionsMap, setFieldOptionsMap] = useState>(new Map()); - - // 优化:使用useCallback缓存函数 - const resetOptions = useCallback(() => { - setSelectedRecordId(null); - setCheckedList([]); - setSelectedCustomer(null); // 重置时也重置客户选择 - }, []); - - const saveOptions = useCallback(async () => { - if (!selectedRecordId || !currentSelection.tableId) { - message.warning('没有有效的选中记录或表格信息'); - return; - } - - if (!selectedCustomer) { - message.error('请选择客户'); - return; - } - - 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); - - // 检查字段类型是否为多选或单选字段 - let fieldOptions = []; - if (fieldMeta.type === FieldType.MultiSelect || fieldMeta.type === FieldType.SingleSelect) { - fieldOptions = (fieldMeta.property as any).options || []; - } - - 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 }); - } - }, [selectedRecordId, currentSelection.tableId, checkedList, fieldOptionsMap, resetOptions, selectedCustomer]); - - 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([]); - } - - // 尝试从选中的选项中推断客户 - const firstOption = checkedList[0]; - const customer = CUSTOMER_CONFIG.find(c => c.options.some(g => g.options.includes(firstOption))); - if (customer) { - setSelectedCustomer(customer.title); - } - } - } catch (e: any) { - message.error('获取选中记录失败: ' + (e.message || e)); - } - }); - return unsubscribe; - }, [currentSelection, resetOptions]); - - return ( -
- -
请先在多维表格中点击一个单元格以加载配置。
-
- -
); -}; - -export default App; \ No newline at end of file +} \ No newline at end of file