// 【重要】必须使用 const Component 作为组件变量名 // ONEOS-web - CRM 客户管理(建档字段、列表、标签、筛选) const Component = function () { var useState = React.useState; var antd = window.antd; var Table = antd.Table; var Button = antd.Button; var Space = antd.Space; var Input = antd.Input; var Select = antd.Select; var DatePicker = antd.DatePicker; var Form = antd.Form; var Row = antd.Row; var Col = antd.Col; var Divider = antd.Divider; var Breadcrumb = antd.Breadcrumb; var Layout = antd.Layout; var message = antd.message; var Tag = antd.Tag; var Tooltip = antd.Tooltip; var Card = antd.Card; var Modal = antd.Modal; var Tabs = antd.Tabs; var Cascader = antd.Cascader; var Radio = antd.Radio; var Content = Layout.Content; var _modalOpen = useState(false); var modalOpen = _modalOpen[0]; var setModalOpen = _modalOpen[1]; /** 筛选默认 2 行(每行 3 个 span:8);超出部分展开/收起 */ var _filterExpand = useState(false); var filterExpanded = _filterExpand[0]; var setFilterExpanded = _filterExpand[1]; var FILTER_COLS_PER_ROW = 3; var FILTER_VISIBLE_ROWS = 2; var filterFieldCount = 8; var filterRowCount = Math.ceil(filterFieldCount / FILTER_COLS_PER_ROW); var showFilterExpandToggle = filterRowCount > FILTER_VISIBLE_ROWS; var _form = Form.useForm(); var customerForm = _form[0]; var _filterFormInst = Form.useForm(); var filterForm = _filterFormInst[0]; var _filterDeptSel = useState([]); var filterDeptSelection = _filterDeptSel[0]; var setFilterDeptSelection = _filterDeptSel[1]; /** * 客户编号规则(集团多子公司) * - 总长度 7,仅含大写字母 A–Z 与数字 0–9。 * - 结构:第 1 位 = 签约/归属子公司代码;第 2–7 位 = 6 位数字流水号(000001–999999,不足左补 0)。 * - 流水号在「同一子公司代码」下递增;不同字母下可各自从 000001 起编。 * - 校验正则:/^[A-Z][0-9]{6}$/ * 示例映射(可按主数据调整):A华东 B华南 C华北 D西南 E华中 F西北 G集团总部 … */ /** 客户标签枚举(筛选 + 列表展示,多选) */ var customerLabelOptions = [ { label: '逾期预警', value: '逾期预警' }, { label: '严重拖欠', value: '严重拖欠' }, { label: '频繁改账期', value: '频繁改账期' }, { label: '资质存疑', value: '资质存疑' }, { label: '涉诉/仲裁', value: '涉诉/仲裁' }, { label: '制裁/高风险地区', value: '制裁/高风险地区' }, { label: '频繁争议', value: '频繁争议' }, { label: '车辆/资产高风险', value: '车辆/资产高风险' }, { label: '信息不实', value: '信息不实' }, { label: '开票异常', value: '开票异常' }, { label: '多头签约', value: '多头签约' } ]; var customerLabelTagStyle = { margin: 0, background: '#fff', border: '1px solid #f77234', color: '#1d2129', borderRadius: 4, lineHeight: '20px', padding: '0 7px' }; var customerLabelCountTagStyle = { margin: 0, background: '#fff', border: '1px solid #c9cdd4', color: '#4e5969', borderRadius: 4, lineHeight: '20px', padding: '0 7px', cursor: 'default' }; /** PDF:区域 — 省-市级联(示例数据,可对接字典) */ var regionOptions = [ { value: 'zj', label: '浙江省', children: [ { value: 'zj-hz', label: '杭州市' }, { value: 'zj-jx', label: '嘉兴市' }, { value: 'zj-nb', label: '宁波市' } ] }, { value: 'sh', label: '上海市', children: [ { value: 'sh-pu', label: '上海市' } ] }, { value: 'js', label: '江苏省', children: [ { value: 'js-nj', label: '南京市' }, { value: 'js-sz', label: '苏州市' } ] } ]; // 自定义 SVG 图标(高保真还原 Arco 风格) var SearchIcon = function() { return React.createElement('svg', { viewBox: '0 0 1024 1024', width: 14, height: 14, fill: 'currentColor' }, React.createElement('path', { d: 'M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z' })); }; var ResetIcon = function() { return React.createElement('svg', { viewBox: '0 0 1024 1024', width: 14, height: 14, fill: 'currentColor' }, React.createElement('path', { d: 'M793 242H366v-74c0-6.7-7.7-10.4-12.9-6.3l-142 112a8 8 0 000 12.6l142 112c5.2 4.1 12.9.4 12.9-6.3v-74h415v470H175c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h618c35.3 0 64-28.7 64-64V306c0-35.3-28.7-64-64-64z' })); }; var PlusIcon = function() { return React.createElement('svg', { viewBox: '0 0 1024 1024', width: 14, height: 14, fill: 'currentColor' }, React.createElement('path', { d: 'M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z' }), React.createElement('path', { d: 'M192 474h672q8 0 8 8v60q0 8-8 8H192q-8 0-8-8v-60q0-8 8-8z' })); }; var DownloadIcon = function() { return React.createElement('svg', { viewBox: '0 0 1024 1024', width: 16, height: 16, fill: 'currentColor' }, React.createElement('path', { d: 'M505.7 661a8 8 0 0012.6 0l112-141.7c4.1-5.2.4-12.9-6.3-12.9h-74.1V168c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v338.3H400c-6.7 0-10.4 7.7-6.3 12.9l112 141.8zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z' })); }; var ListIcon = function() { return React.createElement('svg', { viewBox: '0 0 48 48', width: 14, height: 14, fill: 'none', stroke: 'currentColor', strokeWidth: 4, strokeLinecap: 'butt', strokeLinejoin: 'miter' }, React.createElement('path', { d: 'M17 12H42' }), React.createElement('path', { d: 'M17 24H42' }), React.createElement('path', { d: 'M17 36H42' }), React.createElement('path', { d: 'M8 12H9' }), React.createElement('path', { d: 'M8 24H9' }), React.createElement('path', { d: 'M8 36H9' })); }; /** 与 Ant Design Select 后缀箭头同形(DownOutlined 路径,收起态旋转 180° 与展开动画一致) */ var SelectSuffixArrowIcon = function (props) { var up = props && props.up; return React.createElement('span', { className: 'ant-select-arrow', style: { display: 'inline-flex', alignItems: 'center', lineHeight: 0, marginLeft: 4, flexShrink: 0, color: 'inherit', fontSize: 12, transform: up ? 'rotate(180deg)' : 'none', transformOrigin: '50% 50%', transition: 'transform 0.3s' }, 'aria-hidden': true }, React.createElement('svg', { viewBox: '64 64 896 896', focusable: 'false', width: '1em', height: '1em', fill: 'currentColor' }, React.createElement('path', { d: 'M884 256h-75c-5.1 0-9.9 2.5-12.6 6.5L512 654.6 227.9 262.6c-2.7-4-7.5-6.5-12.6-6.5h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z' }) ) ); }; var renderLabelTooltipContent = function (tags) { return React.createElement(Space, { direction: 'vertical', size: 6, style: { padding: '2px 0' } }, tags.map(function (t) { return React.createElement(Tag, { key: t, style: customerLabelTagStyle }, t); }) ); }; /** 多标签:仅展示第一个 +「+N」;悬浮数量展示全部 */ var renderCustomerLabels = function (tags) { if (!tags || !tags.length) return React.createElement('span', { style: { color: '#86909c' } }, '—'); if (tags.length === 1) { return React.createElement(Space, { size: 4, wrap: false, style: { maxWidth: '100%', overflow: 'hidden' } }, React.createElement(Tag, { style: customerLabelTagStyle }, tags[0]) ); } var rest = tags.length - 1; var countEl = React.createElement(Tag, { style: customerLabelCountTagStyle }, '+' + String(rest)); return React.createElement(Space, { size: 4, wrap: false, style: { maxWidth: '100%', overflow: 'hidden' } }, React.createElement(Tag, { style: customerLabelTagStyle }, tags[0]), React.createElement(Tooltip, { title: renderLabelTooltipContent(tags) }, React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', verticalAlign: 'middle' } }, countEl) ) ); }; var renderCustomerStatus = function (text) { var dot = '#86909c'; if (text === '正常') dot = '#00b42a'; else if (text === '黑名单') dot = '#f53f3f'; return React.createElement(Space, { size: 6 }, React.createElement('span', { style: { display: 'inline-block', width: 6, height: 6, borderRadius: '50%', backgroundColor: dot } }), React.createElement('span', null, text) ); }; var columns = [ { title: '客户编号', dataIndex: 'code', key: 'code', width: 132, fixed: 'left' }, { title: '客户名称', dataIndex: 'name', key: 'name', width: 200, ellipsis: true }, { title: '标签', dataIndex: 'labels', key: 'labels', width: 120, className: 'customer-col-labels', render: renderCustomerLabels }, { title: '客户区域', dataIndex: 'region', key: 'region', width: 100, ellipsis: true }, { title: '客户状态', dataIndex: 'status', key: 'status', width: 100, render: renderCustomerStatus }, { title: '业务部门', dataIndex: 'department', key: 'department', width: 110, ellipsis: true }, { title: '业务负责人', dataIndex: 'manager', key: 'manager', width: 110, ellipsis: true }, { title: '客户类型', dataIndex: 'customerType', key: 'customerType', width: 100 }, { title: '所属行业', dataIndex: 'industry', key: 'industry', width: 100, ellipsis: true }, { title: '统一社会信用代码', dataIndex: 'creditCode', key: 'creditCode', width: 200, ellipsis: true }, { title: '法人', dataIndex: 'legalPerson', key: 'legalPerson', width: 88 }, { title: '注册资本', dataIndex: 'regCapital', key: 'regCapital', width: 104 }, { title: '经营状态', dataIndex: 'operateStatus', key: 'operateStatus', width: 88 }, { title: '详细地址', dataIndex: 'address', key: 'address', width: 240, ellipsis: true }, { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 176, className: 'customer-col-create-time', ellipsis: true }, { title: '操作', key: 'action', fixed: 'right', width: 168, render: function (_, record) { return React.createElement(Space, { size: 0, split: React.createElement('span', { style: { color: '#e5e6eb' } }, '|') }, React.createElement(Button, { type: 'link', size: 'small', style: { padding: '0 4px' }, onClick: function () { message.info('详情:' + record.name); } }, '详情'), React.createElement(Button, { type: 'link', size: 'small', style: { padding: '0 4px' }, onClick: function () { message.info('编辑:' + record.name); } }, '编辑'), React.createElement(Button, { type: 'link', size: 'small', style: { padding: '0 4px' }, onClick: function () { message.info('删除:' + record.name); } }, '删除') ); } } ]; var data = [ { key: '1', code: 'C000001', name: '北京华宇科技有限公司', labels: ['资质存疑'], region: '华北地区', status: '正常', department: '销售一部', manager: '张伟', customerType: '企业客户', industry: '互联网', creditCode: '91110108MA01D2XY89', legalPerson: '李明', regCapital: '1000万元', operateStatus: '在业', address: '北京市海淀区中关村大街18号科创大厦8层', createTime: '2023-10-25 14:30:00' }, { key: '2', code: 'A000001', name: '上海诚新贸易有限公司', labels: ['频繁改账期'], region: '华东地区', status: '正常', department: '销售一部', manager: '王芳', customerType: '企业客户', industry: '零售', creditCode: '91310115MA1K3NBC12', legalPerson: '陈强', regCapital: '500万元', operateStatus: '在业', address: '上海市浦东新区张江路1288号科技园3号楼', createTime: '2023-11-02 09:15:00' }, { key: '3', code: 'B000001', name: '深圳智联信息技术有限公司', labels: [], region: '华南地区', status: '正常', department: '市场开拓部', manager: '刘洋', customerType: '企业客户', industry: '互联网', creditCode: '91440300MA5F8QWE45', legalPerson: '赵敏', regCapital: '2000万元', operateStatus: '在业', address: '广东省深圳市南山区科技园南区科苑路15号', createTime: '2023-11-18 16:20:00' }, { key: '4', code: 'A000002', name: '杭州云帆智能制造股份有限公司', labels: ['逾期预警'], region: '华东地区', status: '正常', department: '大客户部', manager: '李强', customerType: '企业客户', industry: '制造业', creditCode: '91330106MA2B7HJK01', legalPerson: '周杰', regCapital: '5000万元', operateStatus: '存续', address: '浙江省杭州市滨江区物联网街451号', createTime: '2023-12-05 11:00:00' }, { key: '5', code: 'D000001', name: '成都天府医疗健康集团', labels: ['信息不实'], region: '西南地区', status: '正常', department: '大客户部', manager: '陈静', customerType: '企业客户', industry: '医疗保健', creditCode: '91510100MA6C9RST78', legalPerson: '吴磊', regCapital: '3000万元', operateStatus: '在业', address: '四川省成都市高新区天府大道北段966号', createTime: '2024-01-08 10:45:00' }, { key: '6', code: 'B000002', name: '广州粤海金融服务有限公司', labels: ['严重拖欠', '多头签约'], region: '华南地区', status: '黑名单', department: '销售二部', manager: '孙丽', customerType: '企业客户', industry: '金融', creditCode: '91440101MA5D1UVW23', legalPerson: '郑华', regCapital: '8000万元', operateStatus: '在业', address: '广东省广州市天河区珠江东路30号金融中心16层', createTime: '2024-01-22 13:10:00' }, { key: '7', code: 'E000001', name: '武汉长江物流供应链有限公司', labels: [], region: '华中地区', status: '正常', department: '销售一部', manager: '张伟', customerType: '企业客户', industry: '物流', creditCode: '91420100MA4K2PQR56', legalPerson: '冯涛', regCapital: '1500万元', operateStatus: '在业', address: '湖北省武汉市东西湖区物流大道88号', createTime: '2024-02-01 08:50:00' }, { key: '8', code: 'A000003', name: '南京金陵软件科技有限公司', labels: [], region: '华东地区', status: '正常', department: '市场开拓部', manager: '王芳', customerType: '企业客户', industry: '互联网', creditCode: '91320105MA1P5XYZ99', legalPerson: '韩雪', regCapital: '800万元', operateStatus: '在业', address: '江苏省南京市雨花台区软件大道101号', createTime: '2024-02-14 15:25:00' }, { key: '9', code: 'C000002', name: '天津市滨海新区港口设备制造厂', labels: ['涉诉/仲裁'], region: '华北地区', status: '正常', department: '销售二部', manager: '刘洋', customerType: '企业客户', industry: '制造业', creditCode: '91120116MA07NMLM34', legalPerson: '曹阳', regCapital: '2200万元', operateStatus: '存续', address: '天津市滨海新区临港经济区渤海路36号', createTime: '2024-03-03 09:40:00' }, { key: '10', code: 'B000003', name: '厦门海峡跨境电商有限公司', labels: [], region: '华南地区', status: '正常', department: '市场开拓部', manager: '赵敏', customerType: '企业客户', industry: '零售', creditCode: '91350200MA8F3CDE77', legalPerson: '许晴', regCapital: '600万元', operateStatus: '在业', address: '福建省厦门市湖里区象屿路97号国际航运中心', createTime: '2024-03-20 14:05:00' }, { key: '11', code: 'F000001', name: '西安市教育局机关服务中心', labels: [], region: '西北地区', status: '正常', department: '大客户部', manager: '李强', customerType: '政府机构', industry: '公共服务', creditCode: '91610103MB1T2ABC88', legalPerson: '何伟', regCapital: '—', operateStatus: '在业', address: '陕西省西安市碑林区盐店街28号', createTime: '2024-04-02 11:30:00' }, { key: '12', code: 'A000004', name: '青岛海洋生物医药研究院有限公司', labels: ['开票异常'], region: '华东地区', status: '正常', department: '销售一部', manager: '陈静', customerType: '企业客户', industry: '医疗保健', creditCode: '91370212MA3U5FGH22', legalPerson: '罗斌', regCapital: '3500万元', operateStatus: '在业', address: '山东省青岛市崂山区松岭路238号', createTime: '2024-04-18 16:00:00' }, { key: '13', code: 'E000002', name: '郑州中原新能源汽车销售有限公司', labels: ['严重拖欠', '涉诉/仲裁', '多头签约'], region: '华中地区', status: '黑名单', department: '销售二部', manager: '孙丽', customerType: '企业客户', industry: '制造业', creditCode: '91410105MA9L6NOP44', legalPerson: '丁凯', regCapital: '1200万元', operateStatus: '注销', address: '河南省郑州市金水区经三路66号(已迁出)', createTime: '2024-05-06 10:15:00' }, { key: '14', code: 'A000005', name: '个体工商户·林晓峰五金经营部', labels: [], region: '华东地区', status: '正常', department: '销售一部', manager: '周杰', customerType: '个人客户', industry: '零售', creditCode: '92330102MA2HY67890', legalPerson: '林晓峰', regCapital: '50万元', operateStatus: '在业', address: '浙江省温州市鹿城区车站大道789号', createTime: '2024-05-22 09:20:00' }, { key: '15', code: 'D000002', name: '重庆山城火锅餐饮管理有限公司', labels: [], region: '西南地区', status: '正常', department: '市场开拓部', manager: '吴磊', customerType: '企业客户', industry: '零售', creditCode: '91500105MA60QRS111', legalPerson: '黄丽', regCapital: '300万元', operateStatus: '在业', address: '重庆市渝中区解放碑民族路188号', createTime: '2024-06-01 12:45:00' }, { key: '16', code: 'A000006', name: '苏州工业园区精密模具厂', labels: ['车辆/资产高风险', '制裁/高风险地区'], region: '华东地区', status: '黑名单', department: '大客户部', manager: '郑华', customerType: '企业客户', industry: '制造业', creditCode: '91320594MA1W2TUV55', legalPerson: '马军', regCapital: '1800万元', operateStatus: '在业', address: '江苏省苏州市工业园区星龙街428号', createTime: '2024-06-15 15:50:00' }, { key: '17', code: 'E000003', name: '长沙湘江科创投资基金(有限合伙)', labels: ['频繁争议'], region: '华中地区', status: '正常', department: '大客户部', manager: '冯涛', customerType: '企业客户', industry: '金融', creditCode: '91430100MA4L8XYZ66', legalPerson: '谢文', regCapital: '10000万元', operateStatus: '在业', address: '湖南省长沙市岳麓区麓谷大道658号', createTime: '2024-07-03 08:30:00' }, { key: '18', code: 'C000003', name: '石家庄市桥西区智慧城市运营中心', labels: [], region: '华北地区', status: '正常', department: '市场开拓部', manager: '韩雪', customerType: '政府机构', industry: '互联网', creditCode: '91130104MB0X9DEF12', legalPerson: '邓伟', regCapital: '—', operateStatus: '在业', address: '河北省石家庄市桥西区中华南大街172号', createTime: '2024-07-20 14:10:00' }, { key: '19', code: 'A000007', name: '合肥徽风电子元器件有限公司', labels: ['频繁改账期'], region: '华东地区', status: '正常', department: '销售二部', manager: '曹阳', customerType: '企业客户', industry: '制造业', creditCode: '91340100MA2U1BCD33', legalPerson: '蒋欣', regCapital: '900万元', operateStatus: '在业', address: '安徽省合肥市高新区望江西路800号', createTime: '2024-08-08 11:55:00' }, { key: '20', code: 'D000003', name: '昆明滇池生态旅游开发有限公司', labels: ['制裁/高风险地区', '多头签约', '开票异常'], region: '西南地区', status: '正常', department: '销售一部', manager: '许晴', customerType: '企业客户', industry: '公共服务', creditCode: '91530100MA6N7KLM88', legalPerson: '潘越', regCapital: '4500万元', operateStatus: '存续', address: '云南省昆明市西山区滇池路1318号', createTime: '2024-08-25 17:00:00' } ]; var deptManagerMap = {}; data.forEach(function (r) { if (!r.department) return; if (!deptManagerMap[r.department]) deptManagerMap[r.department] = []; if (r.manager && deptManagerMap[r.department].indexOf(r.manager) < 0) { deptManagerMap[r.department].push(r.manager); } }); var departmentOptions = []; var seenDept = {}; data.forEach(function (r) { if (r.department && !seenDept[r.department]) { seenDept[r.department] = true; departmentOptions.push({ label: r.department, value: r.department }); } }); var customerCodeFilterOptions = []; var seenCode = {}; data.forEach(function (r) { if (r.code && !seenCode[r.code]) { seenCode[r.code] = true; customerCodeFilterOptions.push({ label: r.code + ' · ' + r.name, value: r.code }); } }); var customerNameFilterOptions = []; var seenName = {}; data.forEach(function (r) { if (r.name && !seenName[r.name]) { seenName[r.name] = true; customerNameFilterOptions.push({ label: r.name, value: r.name }); } }); var fuzzyFilterOption = function (input, option) { if (input == null || String(input).trim() === '') return true; var s = String(input).toLowerCase(); var label = (option && option.label != null ? String(option.label) : '') + ''; var value = (option && option.value != null ? String(option.value) : '') + ''; return label.toLowerCase().indexOf(s) >= 0 || value.toLowerCase().indexOf(s) >= 0; }; var getManagerFilterOptions = function (deptVals) { if (!deptVals || deptVals.length === 0) { var all = {}; Object.keys(deptManagerMap).forEach(function (d) { (deptManagerMap[d] || []).forEach(function (m) { all[m] = true; }); }); return Object.keys(all).sort().map(function (m) { return { label: m, value: m }; }); } var pick = {}; deptVals.forEach(function (d) { (deptManagerMap[d] || []).forEach(function (m) { pick[m] = true; }); }); return Object.keys(pick).sort().map(function (m) { return { label: m, value: m }; }); }; var handleFilterDeptChange = function (vals) { var v = vals || []; setFilterDeptSelection(v); var allowed = getManagerFilterOptions(v).map(function (o) { return o.value; }); var curM = filterForm.getFieldValue('filterManagers') || []; filterForm.setFieldsValue({ filterManagers: curM.filter(function (m) { return allowed.indexOf(m) >= 0; }) }); }; var formItemLayout = { labelAlign: 'left', colon: false, labelCol: { flex: '0 0 100px' }, wrapperCol: { flex: '1 1 0' } }; var TextArea = Input.TextArea; var tabCustomerBase = React.createElement(Row, { gutter: 16 }, React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '客户类型', name: 'customerType', rules: [{ required: true, message: '请选择客户类型' }] }, React.createElement(Radio.Group, null, React.createElement(Radio, { value: '企业' }, '企业'), React.createElement(Radio, { value: '个人' }, '个人'), React.createElement(Radio, { value: '事业单位' }, '事业单位') ) ) ), React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '客户分级', name: 'abcLevel', rules: [{ required: true, message: '请选择分级' }] }, React.createElement(Radio.Group, null, React.createElement(Radio, { value: 'A' }, 'A'), React.createElement(Radio, { value: 'B' }, 'B'), React.createElement(Radio, { value: 'C' }, 'C') ) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '客户全称', name: 'name', rules: [{ required: true, message: '请输入客户全称' }] }, React.createElement(Input, { placeholder: '与客户证照一致' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '客户简称', name: 'shortName' }, React.createElement(Input, { placeholder: '选填' }) ) ), React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '所属城市', name: 'region', rules: [{ required: true, message: '请选择省-市' }] }, React.createElement(Cascader, { options: regionOptions, placeholder: '省 - 市(级联)', style: { width: '100%' } }) ) ), React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '通讯地址', name: 'address' }, React.createElement(TextArea, { rows: 2, placeholder: '通讯地址' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '业务部门', name: 'department', rules: [{ required: true, message: '请填写业务部门' }] }, React.createElement(Input, { placeholder: '业务部门' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '业务负责人', name: 'manager', rules: [{ required: true, message: '请填写业务负责人' }] }, React.createElement(Input, { placeholder: '业务负责人' }) ) ), React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '备注', name: 'remark' }, React.createElement(TextArea, { rows: 2, placeholder: '备注' }) ) ) ); var tabContact = React.createElement(Row, { gutter: 16 }, React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { label: '姓名', name: 'contactName' }, React.createElement(Input, { placeholder: '联系人姓名' }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { label: '手机号', name: 'contactPhone' }, React.createElement(Input, { placeholder: '手机号' }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { label: '职位', name: 'contactTitle' }, React.createElement(Input, { placeholder: '职位' }) ) ) ); var tabInvoice = React.createElement(Row, { gutter: 16 }, React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '发票抬头', name: 'invoiceTitle', rules: [{ required: true, message: '请填写发票抬头' }], extra: '建议与客户全称保持一致' }, React.createElement(Input, { placeholder: '与客户名称一致' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '纳税人识别号', name: 'taxId', rules: [{ required: true, message: '请填写纳税人识别号' }] }, React.createElement(Input, { placeholder: '纳税人识别号' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '注册电话', name: 'regPhone' }, React.createElement(Input, { placeholder: '注册电话' }) ) ), React.createElement(Col, { span: 24 }, React.createElement(Form.Item, { label: '注册地址', name: 'regAddress' }, React.createElement(TextArea, { rows: 2, placeholder: '注册地址' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '开户银行', name: 'bankName', rules: [{ required: true, message: '请填写开户银行' }] }, React.createElement(Input, { placeholder: '开户银行' }) ) ), React.createElement(Col, { span: 12 }, React.createElement(Form.Item, { label: '账号', name: 'bankAccount', rules: [{ required: true, message: '请填写银行账号' }] }, React.createElement(Input, { placeholder: '银行账号' }) ) ) ); var customerModal = React.createElement(Modal, { title: '新增客户', open: modalOpen, width: 720, onCancel: function () { setModalOpen(false); }, onOk: function () { customerForm.validateFields().then(function () { message.success('已保存(示例,请对接保存接口)'); setModalOpen(false); }).catch(function () {}); }, okText: '保存', cancelText: '取消', destroyOnClose: true }, React.createElement(Form, { form: customerForm, layout: 'vertical', style: { marginTop: 4 }, initialValues: { customerType: '企业', abcLevel: 'B' } }, React.createElement(Tabs, { defaultActiveKey: 'base', items: [ { key: 'base', label: '客户信息', children: tabCustomerBase }, { key: 'contact', label: '联系人信息', children: tabContact }, { key: 'invoice', label: '付款及开票信息', children: tabInvoice } ] }) ) ); return React.createElement(Layout, { className: 'arco-theme-overrides', style: { minHeight: '100vh', background: '#f2f3f5', fontFamily: 'Inter, Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif' } }, // 内联 CSS 以实现最高保真度的 Arco UI React.createElement('style', null, ` .arco-theme-overrides .ant-btn { border-radius: 4px; } .arco-theme-overrides .ant-btn-primary { background-color: #165dff; border-color: #165dff; } .arco-theme-overrides .ant-btn-primary:hover { background-color: #4080ff; border-color: #4080ff; } .arco-theme-overrides .ant-btn-link { color: #165dff; } .arco-theme-overrides .ant-btn-link:hover { background-color: transparent; color: #4080ff; } /* 表头对齐 Arco .arco-table-th-title:14px / #909399,标题区 22px 行高,整行仍 40px */ .arco-theme-overrides .ant-table-thead > tr > th { background-color: #f2f3f5; color: #909399; font-weight: 400; font-size: 14px; height: 40px; padding: 9px 16px; line-height: 22px; box-sizing: border-box; border-bottom: 1px solid #e5e6eb; border-top: none; vertical-align: middle; } .arco-theme-overrides .ant-table-thead > tr > th .ant-table-column-title { font-size: 14px; color: #909399; line-height: 22px; min-height: 22px; white-space: nowrap; } .arco-theme-overrides .ant-table-thead > tr > th::before { display: none !important; } .arco-theme-overrides .ant-table-tbody > tr > td { border-bottom: 1px solid #e5e6eb; padding: 13px 16px; color: #4e5969; vertical-align: middle; line-height: 22px; } .arco-theme-overrides .ant-table-tbody > tr { height: 52px; } .arco-theme-overrides .ant-table-cell.customer-col-create-time { white-space: nowrap; } .arco-theme-overrides .ant-table-cell.customer-col-labels .ant-space { max-width: 100%; } .arco-theme-overrides .customer-table-scroll-wrap { width: 100%; min-width: 0; max-width: 100%; } .arco-theme-overrides .ant-table-wrapper { border: none; } .arco-theme-overrides .ant-table { border: none; } .arco-theme-overrides .ant-table-container { border: none; } .arco-theme-overrides .ant-table-pagination.ant-pagination { margin: 16px 0 0 0; } .arco-theme-overrides .ant-card { border: none; border-radius: 4px; } .arco-theme-overrides .customer-page-card.ant-card { border: 1px solid #e5e6eb !important; border-radius: 4px; box-shadow: 0 1px 2px rgba(0,0,0,0.06); background: #fff; } .arco-theme-overrides .customer-page-card .ant-card-body { padding: 20px 24px 24px; } /* 筛选组件(Input/Select/DatePicker)的默认、Hover、Focus样式复刻 */ .arco-theme-overrides .ant-input, .arco-theme-overrides .ant-select-selector, .arco-theme-overrides .ant-picker { border-radius: 2px; border: 1px solid #e5e6eb; background-color: #fff; transition: all 0.1s cubic-bezier(0, 0, 1, 1); } .arco-theme-overrides .ant-input:hover, .arco-theme-overrides .ant-select:not(.ant-select-disabled):hover .ant-select-selector, .arco-theme-overrides .ant-picker:hover { background-color: #fff; border-color: #165dff; } .arco-theme-overrides .ant-input:focus, .arco-theme-overrides .ant-input-focused, .arco-theme-overrides .ant-select-focused .ant-select-selector, .arco-theme-overrides .ant-picker-focused { background-color: #fff; border: 1px solid #165dff !important; box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.2) !important; outline: 0; } .arco-theme-overrides .ant-input-affix-wrapper:focus, .arco-theme-overrides .ant-input-affix-wrapper-focused { background-color: #fff; border-color: #165dff !important; box-shadow: 0 0 0 2px rgba(22, 93, 255, 0.2) !important; } .arco-theme-overrides .ant-input-affix-wrapper > input.ant-input, .arco-theme-overrides .ant-input-affix-wrapper > input.ant-input:focus, .arco-theme-overrides .ant-input-affix-wrapper > input.ant-input:hover { height: 100%; padding: 0; border: none !important; box-shadow: none !important; outline: none !important; background-color: transparent !important; } /* 日期选择器展开面板(Dropdown/Panel)的样式复刻 */ .arco-theme-overrides .ant-picker-dropdown .ant-picker-panel-container { border-radius: 4px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); border: 1px solid #e5e6eb; background: #fff; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-header { border-bottom: 1px solid #e5e6eb; color: #1d2129; padding: 0 8px; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-content th { color: #86909c; font-weight: 400; font-size: 14px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner { background: #165dff; color: #fff; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner, .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner { background: #165dff; color: #fff; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-in-range::before { background: #e8f3ff; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::before { border: 1px solid transparent; border-radius: 2px; position: relative; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::after { content: ""; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background-color: #165dff; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today.ant-picker-cell-selected .ant-picker-cell-inner::after { background-color: #fff; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end) .ant-picker-cell-inner { background: #f2f3f5; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-inner { border-radius: 2px; font-size: 14px; color: #4e5969; width: 24px; height: 24px; line-height: 24px; } /* 日期选择器展开面板(Dropdown/Panel)的样式复刻 */ .arco-theme-overrides .ant-picker-dropdown .ant-picker-panel-container { border-radius: 4px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); border: 1px solid #e5e6eb; background: #fff; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-header { border-bottom: 1px solid #e5e6eb; color: #1d2129; padding: 0 8px; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-content th { color: #86909c; font-weight: 400; font-size: 14px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-selected .ant-picker-cell-inner { background: #165dff; color: #fff; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-range-start .ant-picker-cell-inner, .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-range-end .ant-picker-cell-inner { background: #165dff; color: #fff; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-in-range::before { background: #e8f3ff; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::before { border: 1px solid transparent; border-radius: 2px; position: relative; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today .ant-picker-cell-inner::after { content: ""; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background-color: #165dff; } .arco-theme-overrides .ant-picker-cell-in-view.ant-picker-cell-today.ant-picker-cell-selected .ant-picker-cell-inner::after { background-color: #fff; } .arco-theme-overrides .ant-picker-dropdown .ant-picker-cell:hover:not(.ant-picker-cell-selected):not(.ant-picker-cell-range-start):not(.ant-picker-cell-range-end) .ant-picker-cell-inner { background: #f2f3f5; border-radius: 2px; } .arco-theme-overrides .ant-picker-cell-inner { border-radius: 2px; font-size: 14px; color: #4e5969; width: 24px; height: 24px; line-height: 24px; } .arco-theme-overrides .ant-breadcrumb { color: #86909c; font-size: 14px; white-space: nowrap; flex-shrink: 0; } .arco-theme-overrides .customer-page-header-row { display: flex; align-items: center; flex-wrap: nowrap; gap: 0; margin-bottom: 20px; } .arco-theme-overrides .ant-breadcrumb a { color: #4e5969; } .arco-theme-overrides .ant-breadcrumb a:hover { color: #165dff; background-color: transparent; } .arco-theme-overrides .ant-form-item-label { padding: 0 16px 0 0 !important; line-height: 32px; height: 32px; display: flex; align-items: center; } .arco-theme-overrides .ant-form-item-control { display: flex; align-items: center; line-height: 32px; min-height: 32px; } .arco-theme-overrides .ant-form-item-control-input { min-height: 32px; width: 100%; display: flex; align-items: center; } .arco-theme-overrides .ant-form-item-control-input-content { display: flex; align-items: center; width: 100%; height: 100%; } .arco-theme-overrides .ant-select { width: 100%; height: 32px; } .arco-theme-overrides .ant-select-selector { height: 32px !important; min-height: 32px !important; display: flex; align-items: center; width: 100%; padding: 0 12px; } .arco-theme-overrides .ant-select-multiple .ant-select-selector { padding: 0 4px; align-items: center; } .arco-theme-overrides .ant-select-selection-item { line-height: 30px !important; margin-top: 0 !important; margin-bottom: 0 !important; } .arco-theme-overrides .ant-select-selection-overflow { align-items: center; } .arco-theme-overrides .customer-filter-manager-select.ant-select-multiple .ant-select-selector { overflow: hidden; } .arco-theme-overrides .customer-filter-manager-select.ant-select-multiple .ant-select-selection-overflow { flex-wrap: nowrap; overflow: hidden; } .arco-theme-overrides .ant-input { height: 32px; padding: 4px 12px; } .arco-theme-overrides .ant-picker { height: 32px !important; min-height: 32px !important; display: flex; align-items: center; padding: 4px 12px; width: 100%; } .arco-theme-overrides .ant-form-item-label > label { color: #4e5969; white-space: nowrap; } .arco-theme-overrides .ant-form-item-label > label::after { display: none !important; content: "" !important; margin: 0 !important; } /* 多选标签及下拉菜单 Checkbox 样式复刻 (模拟 Arco) */ .arco-theme-overrides .ant-select-multiple .ant-select-selection-item { background: #f2f3f5; border: none; border-radius: 2px; } .arco-theme-overrides .ant-select-multiple.ant-select-show-arrow .ant-select-selection-item { padding-inline-end: 24px; } .arco-theme-overrides .ant-select-multiple .ant-select-item-option { padding-left: 36px; position: relative; } .arco-theme-overrides .ant-select-multiple .ant-select-item-option::before { content: ""; position: absolute; left: 12px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; border: 1px solid #e5e6eb; border-radius: 2px; transition: all 0.1s; background: #fff; box-sizing: border-box; } .arco-theme-overrides .ant-select-multiple .ant-select-item-option-selected::before { background-color: #165dff; border-color: #165dff; } .arco-theme-overrides .ant-select-multiple .ant-select-item-option-selected::after { content: ""; position: absolute; left: 16px; top: 50%; transform: translateY(-70%) rotate(45deg); width: 4px; height: 8px; border: 2px solid #fff; border-top: 0; border-left: 0; box-sizing: content-box; z-index: 1; } .arco-theme-overrides .ant-select-multiple .ant-select-item-option-state { display: none; } `), // 仅保留客户管理主内容区(无顶栏、无侧栏);面包屑在卡片外,标题+筛选+列表在白卡片内 React.createElement(Content, { style: { marginLeft: 0, padding: '16px 20px 24px', minHeight: '100vh', display: 'flex', flexDirection: 'column', background: '#f2f3f5' } }, React.createElement('div', { className: 'customer-page-header-row', style: { marginBottom: 12, flexShrink: 0 } }, React.createElement(Breadcrumb, { separator: React.createElement('span', { style: { color: '#c9cdd4' } }, '/'), items: [ { title: React.createElement(ListIcon, { style: { display: 'inline-flex', alignItems: 'center', fontSize: 14, transform: 'translate(-2px, 1px)' } }) }, { title: '业务管理' } ] }) ), React.createElement(Card, { className: 'customer-page-card', bordered: false }, React.createElement('div', { style: { fontSize: 18, fontWeight: 600, color: '#1d2129', lineHeight: '26px', marginBottom: 20 } }, '客户管理'), // 搜索表单区域 React.createElement('div', { style: { marginBottom: 0 } }, React.createElement(Row, { style: { flexWrap: 'nowrap', alignItems: 'stretch' } }, React.createElement(Col, { flex: 1, style: { minWidth: 0, paddingRight: 40 } }, React.createElement(Form, Object.assign({ layout: 'horizontal', form: filterForm }, formItemLayout), React.createElement(Row, { gutter: 24, style: { rowGap: 0 } }, React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterCode', label: '客户编号', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { allowClear: true, showSearch: true, filterOption: fuzzyFilterOption, placeholder: '请选择或搜索客户编号', options: customerCodeFilterOptions }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterName', label: '客户名称', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { allowClear: true, showSearch: true, filterOption: fuzzyFilterOption, placeholder: '请选择或搜索客户名称', options: customerNameFilterOptions }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterTags', label: '标签', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { mode: 'multiple', allowClear: true, maxTagCount: 'responsive', placeholder: '请选择标签', options: customerLabelOptions }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterRegion', label: '区域', style: { marginBottom: 16, height: 32 } }, React.createElement(Cascader, { style: { width: '100%' }, options: regionOptions, placeholder: '请选择客户区域', changeOnSelect: false }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterStatus', label: '客户状态', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { mode: 'multiple', allowClear: true, maxTagCount: 'responsive', placeholder: '请选择客户状态', options: [ { label: '正常', value: '正常' }, { label: '黑名单', value: '黑名单' } ] }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterDepts', label: '业务部门', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { mode: 'multiple', allowClear: true, maxTagCount: 'responsive', placeholder: '请选择业务部门', options: departmentOptions, onChange: handleFilterDeptChange }) ) ) ), filterExpanded ? React.createElement(Row, { gutter: 24, style: { rowGap: 0, marginTop: 0 } }, React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterManagers', label: '业务负责人', style: { marginBottom: 16, height: 32 } }, React.createElement(Select, { mode: 'multiple', allowClear: true, maxTagCount: 'responsive', className: 'customer-filter-manager-select', placeholder: '请选择业务负责人', options: getManagerFilterOptions(filterDeptSelection) }) ) ), React.createElement(Col, { span: 8 }, React.createElement(Form.Item, { name: 'filterDateRange', label: '创建时间', style: { marginBottom: 16, height: 32 } }, React.createElement(DatePicker.RangePicker, { style: { width: '100%' }, placeholder: ['开始时间', '结束时间'] }) ) ) ) : null ) ), React.createElement(Divider, { type: 'vertical', style: { alignSelf: 'stretch', height: 'auto', minHeight: filterExpanded ? 132 : 100, borderLeftColor: 'rgb(229, 230, 235)', borderLeftStyle: 'dashed', marginLeft: 20, marginRight: 20 } }), React.createElement(Col, { flex: 'none', style: { textAlign: 'right', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', minWidth: 100, maxWidth: 168 } }, React.createElement(Space, { direction: 'vertical', size: 12, style: { width: '100%', alignItems: 'flex-end' } }, React.createElement(Button, { type: 'primary', icon: React.createElement(SearchIcon, null), style: { display: 'flex', alignItems: 'center', gap: 6, justifyContent: 'center', width: 86 } }, '查询'), React.createElement(Button, { icon: React.createElement(ResetIcon, null), style: { display: 'flex', alignItems: 'center', gap: 6, justifyContent: 'center', width: 86 }, onClick: function () { filterForm.resetFields(); setFilterDeptSelection([]); } }, '重置'), showFilterExpandToggle ? React.createElement(Button, { type: 'link', size: 'small', style: { padding: '0 4px', height: 'auto', lineHeight: 1.4, color: '#165dff', whiteSpace: 'normal', textAlign: 'right' }, onClick: function () { setFilterExpanded(!filterExpanded); } }, React.createElement('span', { style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'flex-end', width: '100%' } }, filterExpanded ? '收起' : '更多筛选', React.createElement(SelectSuffixArrowIcon, { up: filterExpanded }) ) ) : null ) ) ) ), React.createElement(Divider, { style: { margin: '16px 0 20px', borderColor: '#e5e6eb' } }), // 工具栏 + 表格 React.createElement('div', { style: { display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0 } }, React.createElement(Row, { justify: 'space-between', align: 'middle', style: { marginBottom: 16 } }, React.createElement(Col, null, React.createElement(Space, { size: 12 }, React.createElement(Button, { type: 'primary', icon: React.createElement(PlusIcon, null), style: { display: 'flex', alignItems: 'center', gap: 6 }, onClick: function () { customerForm.resetFields(); setModalOpen(true); } }, '新增客户'), React.createElement(Button, null, '批量导入') ) ), React.createElement(Col, null, React.createElement(Button, { style: { padding: '4px 10px', height: 32, display: 'flex', alignItems: 'center', gap: 6, color: '#4e5969' }, title: '批量导出', onClick: function () { message.info('批量导出(示例)'); } }, React.createElement(DownloadIcon, null), React.createElement('span', null, '批量导出')) ) ), // 表格区域(横向超出出现滚动条;操作列 fixed 右侧) React.createElement('div', { className: 'customer-table-scroll-wrap', style: { flex: 1, minHeight: 0, minWidth: 0 } }, React.createElement(Table, { rowSelection: { type: 'checkbox', columnWidth: 48 }, columns: columns, dataSource: data, pagination: { defaultPageSize: 10, showSizeChanger: true, pageSizeOptions: ['10', '20', '50', '100'], showTotal: function (total) { return '共 ' + total + ' 条'; } }, scroll: { x: 2242 } }) ) ) ) ), customerModal ); }; if (typeof module !== 'undefined' && module.exports) module.exports = Component;