123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- import React, { useEffect } from "react";
- import { EditableProTable, ProColumns } from "@ant-design/pro-components";
- import type { ColumnItem } from "@/type";
- import { createColumn } from "@/utils";
- import { DataType } from "@/enum";
- import { DATA_TYPE_OPTIONS } from "@/constants";
- import {
- Button,
- Input,
- InputNumber,
- message,
- Switch,
- Tooltip,
- Upload,
- UploadFile,
- } from "antd";
- import LangInput from "./LangInput";
- import { validateColumnCode } from "@/utils/validator";
- import VariableModal from "./VariableModal";
- import ColumnVariableModal from "./ColumnVariableModal";
- import { FormInstance } from "antd/lib";
- import {
- DownloadOutlined,
- InfoCircleOutlined,
- UploadOutlined,
- } from "@ant-design/icons";
- import { parseExcel } from "@/utils/parseExcel";
- import ImportResultModal from "./ImportResultModal";
- export default function TableEdit(props: {
- tableId?: string;
- data: any[];
- modelId?: string;
- onChange?: (data: readonly ColumnItem[]) => void;
- }) {
- const [editableKeys, setEditableRowKeys] = React.useState<React.Key[]>([]);
- const [dataSource, setDataSource] = React.useState<readonly ColumnItem[]>(
- props.data
- );
- const boxRef = React.useRef<HTMLDivElement>(null);
- const importResultRef = React.useRef<{
- open: (data: any[], columns: readonly ColumnItem[]) => void;
- }>();
- useEffect(() => {
- props.onChange?.(dataSource);
- }, [dataSource]);
- const DefaultValueComp = ({
- value,
- onChange,
- }: {
- value?: string;
- onChange?: (value: string) => void;
- }) => {
- return (
- <div className="flex gap-2px">
- <Input
- placeholder="默认值"
- value={value}
- onChange={(e) => {
- onChange?.(e.target.value);
- }}
- />
- <div>
- <VariableModal
- trigger={
- <Button
- size="small"
- style={{ width: 40, fontSize: 12 }}
- type="text"
- >
- +变量
- </Button>
- }
- onOk={(val) => onChange?.(val)}
- />
- <ColumnVariableModal
- trigger={
- <Button
- size="small"
- style={{ width: 40, fontSize: 12 }}
- type="text"
- >
- +字段
- </Button>
- }
- onOk={(val) => onChange?.(val)}
- />
- </div>
- </div>
- );
- };
- const LengthComp = ({
- value,
- onChange,
- model,
- form,
- rowKey,
- }: {
- value?: string;
- onChange?: (value: string) => void;
- model: ColumnItem;
- form: FormInstance;
- rowKey?: React.Key | React.Key[];
- }) => {
- return (
- <span className="flex gap-2px">
- <InputNumber
- min={0}
- placeholder="总长度"
- defaultValue={model.precision}
- onChange={(value) =>
- form.setFieldValue([rowKey || "", "precision"], value)
- }
- />
- <InputNumber
- min={0}
- placeholder="小数位数"
- defaultValue={model.scale}
- onChange={(value) =>
- form.setFieldValue([rowKey || "", "scale"], value)
- }
- />
- </span>
- );
- };
- const columns: ProColumns[] = [
- {
- title: "字段代码",
- dataIndex: "schemaName",
- valueType: "text",
- width: 150,
- formItemProps: {
- rules: [
- {
- required: true,
- message: "请输入字段名称",
- },
- {
- max: 50,
- message: "字段名称不能超过50个字符",
- },
- validateColumnCode,
- ],
- },
- },
- {
- title: "字段名称",
- dataIndex: "langName",
- valueType: "text",
- width: 150,
- render: (_dom, entity) => {
- return (
- entity.langNameList?.find(
- (item: Record<string, string>) => item.name === "zh-CN"
- )?.value || "-"
- );
- },
- renderFormItem: (_schema, config, form) => {
- const model = config.record;
- const rowKey = config.recordKey;
- console.log(model);
- return (
- <span>
- <LangInput
- style={{ width: 150 }}
- value={model.langNameList}
- onChange={(langValue, key) => {
- form.setFieldValue([rowKey || "", "langNameList"], langValue);
- form.setFieldValue([rowKey || "", "langName"], "");
- }}
- />
- </span>
- );
- },
- },
- {
- title: "类型",
- dataIndex: "type",
- valueType: "select",
- width: 120,
- fieldProps: (form, { rowKey }) => {
- return {
- options: DATA_TYPE_OPTIONS,
- onChange: () => {
- form.setFieldValue([rowKey || "", "maxLength"], undefined);
- form.setFieldValue([rowKey || "", "scale"], undefined);
- form.setFieldValue([rowKey || "", "precision"], undefined);
- },
- };
- },
- formItemProps: {
- rules: [
- {
- required: true,
- message: "请选择类型",
- },
- ],
- },
- },
- {
- title: "长度",
- dataIndex: "maxLength",
- valueType: "digit",
- width: 120,
- fieldProps: {
- precision: 0,
- },
- render: (text, record) => {
- return record.type === DataType.Decimal
- ? `${record.precision},${record.scale}`
- : text;
- },
- renderFormItem: (_schema, config, form) => {
- const model = config.record;
- const rowKey = config.recordKey;
- return model.type === DataType.Nvarchar ? (
- <InputNumber min={0} max={4000} placeholder="字符长度" />
- ) : model.type === DataType.Decimal ? (
- <LengthComp model={model} form={form} rowKey={rowKey} />
- ) : (
- "-"
- );
- },
- },
- {
- title: "必填",
- dataIndex: "isRequired",
- valueType: "switch",
- render: (text, record) => {
- return <Switch disabled checked={record.isRequired} />;
- },
- width: 80,
- },
- {
- title: "唯一",
- dataIndex: "isUnique",
- valueType: "switch",
- render: (text, record) => {
- return <Switch disabled checked={record.isUnique} />;
- },
- width: 80,
- },
- {
- title: "默认值",
- dataIndex: "defaultValue",
- valueType: "text",
- width: 150,
- renderFormItem() {
- return <DefaultValueComp />;
- },
- },
- {
- title: "字符集",
- dataIndex: "chartset",
- valueType: "text",
- width: 120,
- renderFormItem: (_schema, config) => {
- return config.record.type === DataType.Nvarchar ? (
- <Input placeholder="字符集" />
- ) : null;
- },
- },
- {
- title: "内容",
- dataIndex: "whereInputContent",
- valueType: "text",
- width: 120,
- renderFormItem: (_schema, config) => {
- return config.record.type === DataType.Nvarchar ? (
- <Input.TextArea placeholder="内容..." />
- ) : null;
- },
- },
- {
- title: "描述",
- dataIndex: "memo",
- valueType: "textarea",
- width: 120,
- renderFormItem: () => {
- return <Input.TextArea placeholder="描述..." />;
- },
- },
- {
- title: "预定义字段",
- dataIndex: "isPreDefined",
- renderText: (text, record) => {
- return record.isPreDefined ? "是" : "否";
- },
- },
- {
- title: "操作",
- valueType: "option",
- width: 120,
- render: (_text, record, _, action) =>
- record.isPreDefined
- ? []
- : [
- <a
- key="editable"
- onClick={() => {
- action?.startEditable?.(record.id);
- }}
- >
- 编辑
- </a>,
- <a
- key="delete"
- onClick={() => {
- setDataSource(
- dataSource.filter((item) => item.id !== record.id)
- );
- }}
- >
- 删除
- </a>,
- ],
- },
- ];
- const handleAdd = () => {
- return createColumn(props?.tableId, dataSource.length + 1);
- };
- // 上传字段模版文件
- const handleUpload = (file: UploadFile) => {
- message.loading("正在解析文件...", 0);
- parseExcel<any>(file)
- .then((res) => {
- console.log("加载数据:", res);
- const list = res?.["表单字段"];
- message.destroy();
- if (!list || !list.length) {
- message.warning("当前文件无字段数据,请检查");
- } else {
- importResultRef.current?.open(list, dataSource);
- }
- })
- .catch((err) => {
- console.error("加载数据失败:", err);
- message.error("文件解析失败");
- message.destroy();
- });
- };
- const handleChangeColumn = (list: ColumnItem[]) => {
- setDataSource(list);
- };
- return (
- <div className="w-full h-full overflow-auto" ref={boxRef}>
- <ImportResultModal
- ref={importResultRef}
- tableId={props?.tableId}
- onChange={handleChangeColumn}
- />
- <EditableProTable
- columns={columns}
- rowKey="id"
- value={dataSource}
- onChange={setDataSource}
- recordCreatorProps={{
- record: handleAdd,
- }}
- editable={{
- type: "multiple",
- editableKeys,
- onChange: setEditableRowKeys,
- }}
- toolBarRender={() => [
- <Tooltip
- key="info"
- title={
- <div>
- <p>填写规范:</p>
- <p>
- 1、字段名第一位必须为大写字母,之后的对象可以字母大小写,数字或下划线;
- </p>
- <p>2、Nvarchar类型长度最大不可以超过4000;</p>
- <p>
- 3、Decimal类型精度的填写方式:总精度,有效小数位,eg: 18,6;
- </p>
- <p>4、Int、Datetime等类型长度需填写为0;</p>
- </div>
- }
- >
- <InfoCircleOutlined />
- </Tooltip>,
- <Button key="download" icon={<DownloadOutlined />}>
- <a
- download={"BusinessTableColumnsImportTemplate.xlsx"}
- href="/Content/Template/BusinessTableColumnsImportTemplate.xlsx"
- >
- 下载模版
- </a>
- </Button>,
- <Upload
- key="upload"
- accept=".xlsx"
- showUploadList={false}
- beforeUpload={(file) => handleUpload(file)}
- >
- <Button
- type="primary"
- icon={<UploadOutlined />}
- onClick={() => {
- handleAdd();
- }}
- >
- 导入字段
- </Button>
- </Upload>,
- ]}
- />
- </div>
- );
- }
|