diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 3cddb143..a1291388 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -24,10 +24,6 @@ "@logicflow/core": "^2.0.9", "@logicflow/extension": "^2.0.13", "@reduxjs/toolkit": "^2.0.1", - "@rjsf/antd": "^5.23.2", - "@rjsf/core": "^5.23.2", - "@rjsf/utils": "^5.23.2", - "@rjsf/validator-ajv8": "^5.23.2", "@types/recharts": "^1.8.29", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", @@ -1952,163 +1948,6 @@ "node": ">=14.0.0" } }, - "node_modules/@rjsf/antd": { - "version": "5.23.2", - "resolved": "https://registry.npmmirror.com/@rjsf/antd/-/antd-5.23.2.tgz", - "integrity": "sha512-XZG0sIiJTjxdNXAIFyM88nP7MmCLUxugm3wyJ34jQlwGThZqmsgbHqyhrTum9ZcOvMAknDeNK3MSwI0CugswtQ==", - "license": "Apache-2.0", - "dependencies": { - "classnames": "^2.5.1", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "rc-picker": "2.7.6" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@ant-design/icons": "^4.0.0 || ^5.0.0", - "@rjsf/core": "^5.23.x", - "@rjsf/utils": "^5.23.x", - "antd": "^4.24.0 || ^5.8.5", - "dayjs": "^1.8.0", - "react": "^16.14.0 || >=17" - } - }, - "node_modules/@rjsf/antd/node_modules/rc-picker": { - "version": "2.7.6", - "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-2.7.6.tgz", - "integrity": "sha512-H9if/BUJUZBOhPfWcPeT15JUI3/ntrG9muzERrXDkSoWmDj4yzmBvumozpxYrHwjcKnjyDGAke68d+whWwvhHA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "^2.2.1", - "date-fns": "2.x", - "dayjs": "1.x", - "moment": "^2.24.0", - "rc-trigger": "^5.0.4", - "rc-util": "^5.37.0", - "shallowequal": "^1.1.0" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rjsf/antd/node_modules/rc-picker/node_modules/rc-trigger": { - "version": "5.3.4", - "resolved": "https://registry.npmmirror.com/rc-trigger/-/rc-trigger-5.3.4.tgz", - "integrity": "sha512-mQv+vas0TwKcjAO2izNPkqR4j86OemLRmvL2nOzdP9OWNWA1ivoTt5hzFqYNW9zACwmTezRiN8bttrC7cZzYSw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "classnames": "^2.2.6", - "rc-align": "^4.0.0", - "rc-motion": "^2.0.0", - "rc-util": "^5.19.2" - }, - "engines": { - "node": ">=8.x" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rjsf/antd/node_modules/rc-picker/node_modules/rc-trigger/node_modules/rc-align": { - "version": "4.0.15", - "resolved": "https://registry.npmmirror.com/rc-align/-/rc-align-4.0.15.tgz", - "integrity": "sha512-wqJtVH60pka/nOX7/IspElA8gjPNQKIx/ZqJ6heATCkXpe1Zg4cPVrMD2vC96wjsFFL8WsmhPbx9tdMo1qqlIA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.10.1", - "classnames": "2.x", - "dom-align": "^1.7.0", - "rc-util": "^5.26.0", - "resize-observer-polyfill": "^1.5.1" - }, - "peerDependencies": { - "react": ">=16.9.0", - "react-dom": ">=16.9.0" - } - }, - "node_modules/@rjsf/core": { - "version": "5.23.2", - "resolved": "https://registry.npmmirror.com/@rjsf/core/-/core-5.23.2.tgz", - "integrity": "sha512-jSz3X8SOZ1xL3wMPhBt01j/cA4FszhdGTLBhHfncM9nme4SpbQ6GRAiePOBakEVhT89GAM11ML1DA888YTZfmg==", - "license": "Apache-2.0", - "dependencies": { - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "markdown-to-jsx": "^7.4.1", - "nanoid": "^3.3.7", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@rjsf/utils": "^5.23.x", - "react": "^16.14.0 || >=17" - } - }, - "node_modules/@rjsf/utils": { - "version": "5.23.2", - "resolved": "https://registry.npmmirror.com/@rjsf/utils/-/utils-5.23.2.tgz", - "integrity": "sha512-CDpZTroRE1O2lkZBNYsWCRj7moF3fqnwIo/Vf3flhoS7rGwb8kWlIHakOOBZxlqorKZB1UPzhQZn+FcwhzNldw==", - "license": "Apache-2.0", - "dependencies": { - "json-schema-merge-allof": "^0.8.1", - "jsonpointer": "^5.0.1", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21", - "react-is": "^18.2.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.14.0 || >=17" - } - }, - "node_modules/@rjsf/validator-ajv8": { - "version": "5.23.2", - "resolved": "https://registry.npmmirror.com/@rjsf/validator-ajv8/-/validator-ajv8-5.23.2.tgz", - "integrity": "sha512-EHOTZ/YxTcFHpCj2p42PD3daxJyozZ5gkIVCfbtIXgTtubt/pOMFvM2OxNcQ6OBQ+ulo96OmnDxYGsNPpZZVaw==", - "license": "Apache-2.0", - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^2.1.1", - "lodash": "^4.17.21", - "lodash-es": "^4.17.21" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@rjsf/utils": "^5.23.x" - } - }, - "node_modules/@rjsf/validator-ajv8/node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.27.4", "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.27.4.tgz", @@ -3385,27 +3224,6 @@ "resolved": "https://registry.npmmirror.com/component-indexof/-/component-indexof-0.0.3.tgz", "integrity": "sha512-puDQKvx/64HZXb4hBwIcvQLaLgux8o1CbWl39s41hrIIZDl1lJiD5jc22gj3RBeGK0ovxALDYpIbyjqDUUl0rw==" }, - "node_modules/compute-gcd": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/compute-gcd/-/compute-gcd-1.2.1.tgz", - "integrity": "sha512-TwMbxBNz0l71+8Sc4czv13h4kEqnchV9igQZBi6QUaz09dnz13juGnnaWWJTRsP3brxOoxeB4SA2WELLw1hCtg==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, - "node_modules/compute-lcm": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/compute-lcm/-/compute-lcm-1.1.2.tgz", - "integrity": "sha512-OFNPdQAXnQhDSKioX8/XYT6sdUlXwpeMjfd6ApxMJfyZ4GxmLR1xvMERctlYhlHwIiz6CSpBc2+qYKjHGZw4TQ==", - "dependencies": { - "compute-gcd": "^1.2.1", - "validate.io-array": "^1.0.3", - "validate.io-function": "^1.0.2", - "validate.io-integer-array": "^1.0.0" - } - }, "node_modules/compute-scroll-into-view": { "version": "3.1.0", "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz", @@ -3682,6 +3500,8 @@ "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -4806,29 +4626,6 @@ "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, - "node_modules/json-schema-compare": { - "version": "0.2.2", - "resolved": "https://registry.npmmirror.com/json-schema-compare/-/json-schema-compare-0.2.2.tgz", - "integrity": "sha512-c4WYmDKyJXhs7WWvAWm3uIYnfyWFoIp+JEoX34rctVvEkMYCPGhXtvmFFXiffBbxfZsvQ0RNnV5H7GvDF5HCqQ==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.4" - } - }, - "node_modules/json-schema-merge-allof": { - "version": "0.8.1", - "resolved": "https://registry.npmmirror.com/json-schema-merge-allof/-/json-schema-merge-allof-0.8.1.tgz", - "integrity": "sha512-CTUKmIlPJbsWfzRRnOXz+0MjIqvnleIXwFTzz+t9T86HnYX/Rozria6ZVGLktAU9e+NygNljveP+yxqtQp/Q4w==", - "license": "MIT", - "dependencies": { - "compute-lcm": "^1.1.2", - "json-schema-compare": "^0.2.2", - "lodash": "^4.17.20" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -4859,15 +4656,6 @@ "node": ">=6" } }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", @@ -5020,18 +4808,6 @@ "semver": "bin/semver" } }, - "node_modules/markdown-to-jsx": { - "version": "7.7.2", - "resolved": "https://registry.npmmirror.com/markdown-to-jsx/-/markdown-to-jsx-7.7.2.tgz", - "integrity": "sha512-N3AKfYRvxNscvcIH6HDnDKILp4S8UWbebp+s92Y8SwIq0CuSbLW4Jgmrbjku3CWKjTQO0OyIMS6AhzqrwjEa3g==", - "license": "MIT", - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "react": ">= 0.14.0" - } - }, "node_modules/medium-editor": { "version": "5.23.3", "resolved": "https://registry.npmmirror.com/medium-editor/-/medium-editor-5.23.3.tgz", @@ -5187,6 +4963,8 @@ "resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": "*" } @@ -5205,6 +4983,7 @@ "version": "3.3.7", "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, "funding": [ { "type": "github", @@ -7067,39 +6846,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/validate.io-array": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/validate.io-array/-/validate.io-array-1.0.6.tgz", - "integrity": "sha512-DeOy7CnPEziggrOO5CZhVKJw6S3Yi7e9e65R1Nl/RTN1vTQKnzjfvks0/8kQ40FP/dsjRAOd4hxmJ7uLa6vxkg==", - "license": "MIT" - }, - "node_modules/validate.io-function": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/validate.io-function/-/validate.io-function-1.0.2.tgz", - "integrity": "sha512-LlFybRJEriSuBnUhQyG5bwglhh50EpTL2ul23MPIuR1odjO7XaMLFV8vHGwp7AZciFxtYOeiSCT5st+XSPONiQ==" - }, - "node_modules/validate.io-integer": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/validate.io-integer/-/validate.io-integer-1.0.5.tgz", - "integrity": "sha512-22izsYSLojN/P6bppBqhgUDjCkr5RY2jd+N2a3DCAUey8ydvrZ/OkGvFPR7qfOpwR2LC5p4Ngzxz36g5Vgr/hQ==", - "dependencies": { - "validate.io-number": "^1.0.3" - } - }, - "node_modules/validate.io-integer-array": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/validate.io-integer-array/-/validate.io-integer-array-1.0.0.tgz", - "integrity": "sha512-mTrMk/1ytQHtCY0oNO3dztafHYyGU88KL+jRxWuzfOmQb+4qqnWmI+gykvGp8usKZOM0H7keJHEbRaFiYA0VrA==", - "dependencies": { - "validate.io-array": "^1.0.3", - "validate.io-integer": "^1.0.4" - } - }, - "node_modules/validate.io-number": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/validate.io-number/-/validate.io-number-1.0.3.tgz", - "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" - }, "node_modules/vanilla-picker": { "version": "2.12.3", "resolved": "https://registry.npmmirror.com/vanilla-picker/-/vanilla-picker-2.12.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 0265b9c3..f7f1952a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,10 +26,6 @@ "@logicflow/core": "^2.0.9", "@logicflow/extension": "^2.0.13", "@reduxjs/toolkit": "^2.0.1", - "@rjsf/antd": "^5.23.2", - "@rjsf/core": "^5.23.2", - "@rjsf/utils": "^5.23.2", - "@rjsf/validator-ajv8": "^5.23.2", "@types/recharts": "^1.8.29", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", diff --git a/frontend/src/layouts/BasicLayout.tsx b/frontend/src/layouts/BasicLayout.tsx index e7dd2108..ce34b7d8 100644 --- a/frontend/src/layouts/BasicLayout.tsx +++ b/frontend/src/layouts/BasicLayout.tsx @@ -10,7 +10,6 @@ import { ClockCircleOutlined, CloudOutlined } from '@ant-design/icons'; -import * as AntdIcons from '@ant-design/icons'; import {logout, setMenus} from '../store/userSlice'; import type {MenuProps} from 'antd'; import {getCurrentUserMenus} from '@/pages/System/Menu/service'; diff --git a/frontend/src/pages/Deploy/Deployment/List/components/DeploymentConfigModal.tsx b/frontend/src/pages/Deploy/Deployment/List/components/DeploymentConfigModal.tsx index 249d25da..2b869493 100644 --- a/frontend/src/pages/Deploy/Deployment/List/components/DeploymentConfigModal.tsx +++ b/frontend/src/pages/Deploy/Deployment/List/components/DeploymentConfigModal.tsx @@ -1,15 +1,12 @@ import React, {useEffect, useState} from 'react'; -import {Modal, Form, Select, Switch, InputNumber, message} from 'antd'; +import {Modal, Form, Select, message, Switch, InputNumber} from 'antd'; import type {DeploymentConfig, DeployConfigTemplate} from '../types'; import {createDeploymentConfig, updateDeploymentConfig, getDeployConfigTemplates} from '../service'; import {getApplicationList} from '../../../Application/List/service'; import type {Application} from '../../../Application/List/types'; -import {withTheme} from '@rjsf/core'; -import {Theme as AntdTheme} from '@rjsf/antd'; -import validator from '@rjsf/validator-ajv8'; -import type {IChangeEvent} from '@rjsf/utils'; - -const JsonForm = withTheme(AntdTheme); +import {BetaSchemaForm} from '@ant-design/pro-form'; +import {convertJsonSchemaToColumns} from '@/utils/jsonSchemaUtils'; +import './styles.less'; interface DeploymentConfigModalProps { visible: boolean; @@ -55,7 +52,7 @@ const DeploymentConfigModal: React.FC = ({ } }; - // 仅在模态框显示时获取数据 + // ��在模态框显示时获取数据 useEffect(() => { if (visible) { fetchApplications(); @@ -90,8 +87,11 @@ const DeploymentConfigModal: React.FC = ({ const app = applications.find(a => a.id === appId); if (app) { const template = templates.find(t => t.languageType === app.language); - setSelectedTemplate(template); - setBuildVariables({}); + if (template) { + setSelectedTemplate(template); + setBuildVariables({}); + form.setFieldValue('templateCode', template.code); + } } }; @@ -100,7 +100,6 @@ const DeploymentConfigModal: React.FC = ({ const values = await form.validateFields(); const submitData = { ...values, - templateCode: selectedTemplate?.code, buildVariables, }; @@ -120,12 +119,6 @@ const DeploymentConfigModal: React.FC = ({ } }; - const handleJsonFormChange = (e: IChangeEvent) => { - if (e.formData) { - setBuildVariables(e.formData); - } - }; - return ( = ({ }} onOk={handleSubmit} width={800} + className="deployment-config-modal" + maskClosable={false} >
= ({ sort: 0, }} > + {/* 应用选��� */} - + {/* 动态构建配置 */} {selectedTemplate && ( - - - + setBuildVariables(values)} + /> )} + {/* 状态和排序 */} - + - +
diff --git a/frontend/src/pages/Deploy/Deployment/List/components/styles.less b/frontend/src/pages/Deploy/Deployment/List/components/styles.less new file mode 100644 index 00000000..2db3025e --- /dev/null +++ b/frontend/src/pages/Deploy/Deployment/List/components/styles.less @@ -0,0 +1,98 @@ +.deployment-config-modal { + .ant-modal-body { + padding: 24px; + max-height: calc(100vh - 200px); + overflow-y: auto; + } + + .config-section { + background: #fafafa; + border-radius: 8px; + margin-bottom: 24px; + + &:last-child { + margin-bottom: 0; + } + + .ant-card-body { + padding: 20px; + } + + .section-header { + margin-bottom: 16px; + padding-bottom: 16px; + border-bottom: 1px solid #f0f0f0; + + .section-icon { + font-size: 18px; + color: #1890ff; + } + + .section-title { + font-size: 16px; + font-weight: 500; + color: #262626; + } + } + + .section-content { + .ant-form-item { + margin-bottom: 16px; + + &:last-child { + margin-bottom: 0; + } + + .ant-form-item-label { + padding-bottom: 8px; + + label { + color: #262626; + font-weight: 500; + } + } + + .ant-input, + .ant-select-selector, + .ant-input-number { + border-radius: 4px; + + &:hover, + &:focus { + border-color: #1890ff; + } + } + + .ant-switch { + background: rgba(0, 0, 0, 0.25); + + &-checked { + background: #1890ff; + } + } + } + } + } + + // Schema表单样式优化 + .ant-form-item-extra { + font-size: 12px; + color: #666; + margin-top: 4px; + } + + .ant-form-item-with-help { + margin-bottom: 24px; + } + + // 必填项标记样式 + .ant-form-item-required::before { + display: inline-block; + margin-right: 4px; + color: #ff4d4f; + font-size: 14px; + font-family: SimSun, sans-serif; + line-height: 1; + content: '*'; + } +} \ No newline at end of file diff --git a/frontend/src/pages/Deploy/Deployment/List/index.tsx b/frontend/src/pages/Deploy/Deployment/List/index.tsx index b1f51e59..68480160 100644 --- a/frontend/src/pages/Deploy/Deployment/List/index.tsx +++ b/frontend/src/pages/Deploy/Deployment/List/index.tsx @@ -120,13 +120,6 @@ const DeploymentConfigList: React.FC = () => { width: 100, align: 'center', }, - { - title: '资源配置', - dataIndex: ['deployConfig', 'resources'], - width: 200, - ellipsis: true, - render: (_, record) => renderResourceInfo(record.deployConfig?.resources), - }, ], }, { diff --git a/frontend/src/pages/System/Menu/service.ts b/frontend/src/pages/System/Menu/service.ts index 7f024d07..e095b878 100644 --- a/frontend/src/pages/System/Menu/service.ts +++ b/frontend/src/pages/System/Menu/service.ts @@ -1,7 +1,7 @@ import request from '@/utils/request'; -import type { Page } from '@/types/base/page'; import type { MenuResponse, MenuRequest } from './types'; import { MenuTypeEnum } from './types'; +import {Page} from "@/types/base"; const BASE_URL = '/api/v1/menu'; diff --git a/frontend/src/pages/System/Menu/types.ts b/frontend/src/pages/System/Menu/types.ts index fa6848c2..224da92f 100644 --- a/frontend/src/pages/System/Menu/types.ts +++ b/frontend/src/pages/System/Menu/types.ts @@ -1,6 +1,4 @@ -import {BaseRequest} from "@/types/base/request.ts"; -import {BaseResponse} from "@/types/base/response.ts"; -import {BaseQuery} from "@/types/base"; +import {BaseQuery, BaseRequest, BaseResponse} from "@/types/base"; export enum MenuTypeEnum { DIRECTORY = 1, // 目录 diff --git a/frontend/src/utils/jsonSchemaUtils.ts b/frontend/src/utils/jsonSchemaUtils.ts new file mode 100644 index 00000000..d999ebac --- /dev/null +++ b/frontend/src/utils/jsonSchemaUtils.ts @@ -0,0 +1,140 @@ +import type {ProFormColumnsType} from '@ant-design/pro-form'; + +interface JsonSchemaProperty { + type: string; + title?: string; + description?: string; + default?: any; + enum?: any[]; + enumNames?: string[]; + items?: { + type: string; + enum?: any[]; + enumNames?: string[]; + }; + minimum?: number; + maximum?: number; + minLength?: number; + maxLength?: number; + pattern?: string; +} + +interface JsonSchema { + type: string; + properties: Record; + required?: string[]; +} + +/** + * 将JSON Schema转换为ProForm的columns配置 + * @param schema JSON Schema对象 + * @returns ProForm的columns配置 + */ +export const convertJsonSchemaToColumns = (schema: JsonSchema): ProFormColumnsType[] => { + if (!schema?.properties) return []; + + return Object.entries(schema.properties).map(([key, value]: [string, JsonSchemaProperty]) => { + const baseConfig = { + title: value.title || key, + dataIndex: key, + formItemProps: { + required: schema.required?.includes(key), + help: value.description, + }, + }; + + // 根据类型处理不同的表单项 + switch (value.type) { + case 'string': + // 如果有枚举值,使用选择器 + if (value.enum) { + return { + ...baseConfig, + valueType: 'select', + fieldProps: { + options: value.enum.map((item, index) => ({ + label: value.enumNames?.[index] || item, + value: item, + })), + placeholder: `请选择${value.title || key}`, + }, + }; + } + // 否则使用文本输入框 + return { + ...baseConfig, + valueType: 'text', + fieldProps: { + placeholder: `请输入${value.title || key}`, + }, + }; + + case 'number': + case 'integer': + return { + ...baseConfig, + valueType: 'digit', + fieldProps: { + min: value.minimum, + max: value.maximum, + placeholder: `请输入${value.title || key}`, + style: { width: '100%' } + }, + }; + + case 'boolean': + return { + ...baseConfig, + valueType: 'switch', + }; + + case 'array': + // 处理数组类型的枚举值,支持两种方式: + // 1. enum 定义在 items 中 + // 2. enum 直接定义在属性上 + if (value.items?.enum || value.enum) { + const enumValues = value.items?.enum || value.enum || []; + const enumNames = value.items?.enumNames || value.enumNames; + return { + ...baseConfig, + valueType: 'select', + fieldProps: { + mode: 'multiple', + options: enumValues.map((item, index) => ({ + label: enumNames?.[index] || item, + value: item, + })), + placeholder: `请选择${value.title || key}`, + }, + }; + } + // 否则使用标签输入 + return { + ...baseConfig, + valueType: 'select', + fieldProps: { + mode: 'tags', + placeholder: `请输入${value.title || key}`, + }, + }; + + case 'object': + return { + ...baseConfig, + valueType: 'jsonCode', + fieldProps: { + placeholder: `请输入${value.title || key}`, + }, + }; + + default: + return { + ...baseConfig, + valueType: 'text', + fieldProps: { + placeholder: `请输入${value.title || key}`, + }, + }; + } + }); +}; \ No newline at end of file