From 72a874516bd8c0a17a815c6671896c238f23cb5f Mon Sep 17 00:00:00 2001 From: sunqh <253801736@qq.com> Date: Tue, 14 Apr 2026 11:14:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Config/index.tsx | 337 ++++++++++++++++++++++++++++++------- 1 file changed, 278 insertions(+), 59 deletions(-) diff --git a/src/pages/Config/index.tsx b/src/pages/Config/index.tsx index 480491b..fdd37f7 100644 --- a/src/pages/Config/index.tsx +++ b/src/pages/Config/index.tsx @@ -1,4 +1,4 @@ -import { FileTextOutlined, UploadOutlined } from '@ant-design/icons'; +import { DeleteOutlined, FileTextOutlined } from '@ant-design/icons'; import { Button, Checkbox, @@ -10,14 +10,49 @@ import { Modal, message, Select, + Space, Switch, Table, Tag, - Upload, } from 'antd'; import dayjs from 'dayjs'; import { useEffect, useState } from 'react'; +const EditableForm = ({ value = [], onChange, schema }: any) => { + // 兼容性处理:从 columns 中提取字段定义 + const fields = schema?.columns || []; + + // 假设 form 模式操作的是数组的第一个对象 + const data = value[0] || {}; + + const handleFieldChange = (dataIndex: string, val: any) => { + const newData = [{ ...data, [dataIndex]: val }]; + onChange?.(newData); // 保持数据结构依然是 [{...}] + }; + + return ( +
+ {fields.map((col: any) => ( +
+
{col.title}
+ handleFieldChange(col.dataIndex, e.target.value)} + /> +
+ ))} +
+ ); +}; + // --- 复杂类型:可编辑表格组件 (用于分段价格等 array + table 模式) --- interface EditableTableProps { value?: any[]; @@ -31,19 +66,18 @@ interface EditableTableProps { }; } const EditableTable = ({ value = [], onChange, schema }: EditableTableProps) => { - const columns = (schema?.columns || []).map((col: any) => ({ + // --- 1. 字段定义 --- + const baseColumns = (schema?.columns || []).map((col: any) => ({ title: col.title, dataIndex: col.dataIndex, render: (text: any, record: any, index: number) => { const inputProps = { value: text, - // 这里 val 可能是 Event 对象也可能是数值,antd 的 InputNumber 直接返回 val - // 普通 Input 返回 e.target.value onChange: (e: any) => { const val = e?.target ? e.target.value : e; const newData = [...value]; newData[index] = { ...newData[index], [col.dataIndex]: val }; - onChange?.(newData); // 使用可选链调用,安全消灭波浪线 + onChange?.(newData); }, }; @@ -51,25 +85,51 @@ const EditableTable = ({ value = [], onChange, schema }: EditableTableProps) => }, })); + // --- 2. 操作列 (删除) --- + const columns = [ + { + title: '操作', + width: 70, + align: 'center' as const, + render: (_: any, __: any, index: number) => ( + + + 共 {value.length} 条记录 + + + {/* --- 4. 表格主体 --- */} i.toString()} + scroll={{ y: 300 }} /> - ); }; @@ -110,12 +170,12 @@ const ConfigList = () => { label: '通知方式', type: 'array', value: [1, 2], - array_config: '{"mode":"checkbox"}', + array_config: '{"mode":"checkbox", "multiple":"true"}', options: '[{"label":"短信","value":1},{"label":"邮件","value":2}]', }, { id: 8, config_key: 'birth_date', label: '日期', type: 'date', value: '2026-01-01' }, { id: 9, config_key: 'expire_time', label: '时间', type: 'datetime', value: '2026-01-01 12:00:00' }, - { id: 10, config_key: 'logo', label: 'Logo', type: 'file', value: [{ url: '/logo.png', name: 'logo.png' }] }, + //{ id: 10, config_key: 'logo', label: 'Logo', type: 'file', value: [{ url: '/logo.png', name: 'logo.png' }] }, { id: 11, config_key: 'price', @@ -130,6 +190,45 @@ const ConfigList = () => { schema: '{"columns":[{"title":"最小","dataIndex":"min","type":"int"},{"title":"最大","dataIndex":"max","type":"int"},{"title":"价格","dataIndex":"price","type":"int"}]}', }, + { + id: 12, + config_key: 'admin_info', + label: '管理员信息', + type: 'array', + value: [{ name: '张三', phone: '李四' }], + array_config: '{"mode":"form"}', + schema: + '{"columns":[{"title":"管理员姓名","dataIndex":"name","type":"string","placeholder":"请输入姓名"},{"title":"管理员手机号","dataIndex":"phone","type":"string","placeholder":"请输入手机号"}]}', + }, + { + id: 13, + config_key: 'audit_status', + label: '审核状态', + type: 'select', + value: 1, + options: '[{"label":"待审核","value":1},{"label":"通过","value":2},{"label":"驳回","value":3}]', + props: '{"placeholder":"请选择状态"}', + }, + { + id: 14, + config_key: 'user_roles', + label: '关联角色', + type: 'array', + value: ['admin'], // 初始选中的值 + array_config: '{"mode":"select", "multiple": true}', // 核心标志位 + options: + '[{"label":"超级管理员","value":"admin"},{"label":"运营","value":"editor"},{"label":"财务","value":"finance"}]', + }, + { + id: 15, + config_key: 'single_check', + label: '单选确认', + type: 'array', + value: [1], + // 增加 single 属性 + array_config: '{"mode":"checkbox", "multiple":"false"}', + options: '[{"label":"选项A","value":1},{"label":"选项B","value":2}]', + }, ]; setData( @@ -153,7 +252,7 @@ const ConfigList = () => { const { type, props, options, array_config, schema } = item; // 1. 获取该配置项当前的实时值 (用于 tags 模式下合并临时选项) - const currentValue = form.getFieldValue(item.config_key) || []; + //const currentValue = form.getFieldValue(item.config_key) || []; switch (type) { case 'string': @@ -162,18 +261,20 @@ const ConfigList = () => { return ; case 'int': return ; + case 'select': + return { + form.setFieldsValue({ [item.config_key]: val }); + }} /> ); } + // 2. 处理复选框模式 (Checkbox) + if (mode === 'checkbox') { + //return ; + return ( + { + if (array_config?.multiple === 'false') { + if (checkedValues.length === 0) return; + + const nextValue = [checkedValues[checkedValues.length - 1]]; + form.setFieldValue(item.config_key, nextValue); + } else { + // 普通多选模式 + form.setFieldValue(item.config_key, checkedValues); + } + }} + /> + ); + } + + // 3. 处理下拉选择与标签模式 (Select / Tags) + // if (mode === 'select' || mode === 'tags') { + // // 【关键】始终以原始 options 为基准,防止预设选项丢失 + // const mergedOptions = [...(options || [])]; + + // // 如果是 tags 模式,需要把当前已输入但不在 options 里的值临时加入下拉列表 + // // 这样可以保证“已选即显示”,但不会影响原始 options 的持久性 + // if (mode === 'tags' && Array.isArray(currentValue)) { + // currentValue.forEach((v) => { + // const exists = mergedOptions.some((opt) => opt.value === v); + // if (!exists) { + // // 如果是用户新输入的,动态补全到当前渲染列表里 + // mergedOptions.push({ label: String(v), value: v }); + // } + // }); + // } + + // return ( + // + ); + } // 如果没有任何匹配的模式,默认返回普通 Select return