优化评查详情,新增信息提示框组件
This commit is contained in:
+441
-180
@@ -1,11 +1,12 @@
|
||||
import { json, redirect, type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction } from "@remix-run/node";
|
||||
import { redirect, type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction } from "@remix-run/node";
|
||||
import { Form, useActionData, useLoaderData, useNavigation } from "@remix-run/react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { Button } from "~/components/ui/Button";
|
||||
import { Card } from "~/components/ui/Card";
|
||||
import { ConfigModule, MODULE_LABELS, ENVIRONMENT_LABELS } from "./config-lists._index";
|
||||
import { ENVIRONMENT_LABELS } from "./config-lists._index";
|
||||
import { getConfigOptions, getConfigDetail, createConfig, updateConfig } from "~/api/system_setting/config-lists";
|
||||
import configNewStyles from "~/styles/pages/config-lists_new.css?url";
|
||||
import { toastService } from "~/components/ui/Toast";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: configNewStyles }
|
||||
@@ -39,6 +40,7 @@ export const EXTENDED_ENVIRONMENT_LABELS: Record<string, string> = {
|
||||
[ExtendedConfigEnvironment.COMMON]: '通用'
|
||||
};
|
||||
|
||||
// 新增配置表单数据
|
||||
interface ConfigData {
|
||||
id: number;
|
||||
name: string;
|
||||
@@ -49,41 +51,16 @@ interface ConfigData {
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
// 加载器数据类型
|
||||
interface LoaderData {
|
||||
config?: ConfigData;
|
||||
isEdit: boolean;
|
||||
types: string[];
|
||||
environments: string[];
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const url = new URL(request.url);
|
||||
const id = url.searchParams.get("id");
|
||||
let config: ConfigData | undefined = undefined;
|
||||
|
||||
// 获取配置选项
|
||||
const optionsResponse = await getConfigOptions();
|
||||
if (optionsResponse.error) {
|
||||
throw new Error(optionsResponse.error);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
// 获取配置详情
|
||||
const detailResponse = await getConfigDetail(id);
|
||||
if (detailResponse.error) {
|
||||
throw new Error(detailResponse.error);
|
||||
}
|
||||
config = detailResponse.data;
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
config,
|
||||
isEdit: !!config,
|
||||
types: optionsResponse.data?.types || [],
|
||||
environments: optionsResponse.data?.environments || []
|
||||
});
|
||||
}
|
||||
|
||||
// 新增配置表单数据
|
||||
interface ActionData {
|
||||
success?: boolean;
|
||||
errors?: {
|
||||
@@ -93,81 +70,7 @@ interface ActionData {
|
||||
config?: string;
|
||||
general?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const id = formData.get("id") as string;
|
||||
const name = formData.get("name") as string;
|
||||
const type = formData.get("type") as string;
|
||||
const environment = formData.get("environment") as string;
|
||||
const config = formData.get("config") as string;
|
||||
const is_active = formData.get("is_active") === "true";
|
||||
const remark = formData.get("remark") as string;
|
||||
|
||||
const errors: ActionData["errors"] = {};
|
||||
|
||||
// 表单验证
|
||||
if (!name || name.trim() === "") {
|
||||
errors.name = "配置名称不能为空";
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
errors.type = "请选择所属模块";
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
errors.environment = "请选择环境";
|
||||
}
|
||||
|
||||
if (!config || config.trim() === "") {
|
||||
errors.config = "配置数据不能为空";
|
||||
} else {
|
||||
try {
|
||||
JSON.parse(config);
|
||||
} catch (e) {
|
||||
errors.config = "配置数据必须是有效的JSON格式";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) {
|
||||
return Response.json({ errors });
|
||||
}
|
||||
|
||||
try {
|
||||
const configData = {
|
||||
name,
|
||||
type,
|
||||
environment,
|
||||
config: JSON.parse(config),
|
||||
is_active,
|
||||
remark
|
||||
};
|
||||
|
||||
if (id) {
|
||||
// 更新配置
|
||||
const response = await updateConfig(id, configData);
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
} else {
|
||||
// 创建配置
|
||||
const response = await createConfig(configData);
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect("/config-lists");
|
||||
} catch (error) {
|
||||
console.error("保存配置失败:", error);
|
||||
return Response.json({
|
||||
success: false,
|
||||
errors: {
|
||||
general: "保存配置失败,请稍后重试"
|
||||
}
|
||||
});
|
||||
}
|
||||
values?: Record<string, string>;
|
||||
}
|
||||
|
||||
// 配置模板常量
|
||||
@@ -205,29 +108,212 @@ const CONFIG_TEMPLATES = {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const url = new URL(request.url);
|
||||
const id = url.searchParams.get("id");
|
||||
let config: ConfigData | undefined = undefined;
|
||||
|
||||
try {
|
||||
// 获取配置选项
|
||||
const optionsResponse = await getConfigOptions();
|
||||
if (optionsResponse.error) {
|
||||
throw new Error(optionsResponse.error);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
// 获取配置详情
|
||||
const detailResponse = await getConfigDetail(id);
|
||||
if (detailResponse.error) {
|
||||
throw new Error(detailResponse.error);
|
||||
}
|
||||
config = detailResponse.data;
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
config,
|
||||
isEdit: !!config,
|
||||
types: optionsResponse.data?.types || [],
|
||||
environments: optionsResponse.data?.environments || [],
|
||||
error: undefined
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("加载配置数据失败:", error);
|
||||
return Response.json({
|
||||
config: undefined,
|
||||
isEdit: false,
|
||||
types: [],
|
||||
environments: [],
|
||||
error: error instanceof Error ? error.message : "加载配置数据失败"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const id = formData.get("id") as string;
|
||||
const name = formData.get("name") as string;
|
||||
const type = formData.get("type") as string;
|
||||
const environment = formData.get("environment") as string;
|
||||
const config = formData.get("config") as string;
|
||||
const is_active = formData.get("is_active") === "true";
|
||||
const remark = formData.get("remark") as string;
|
||||
|
||||
const errors: ActionData["errors"] = {};
|
||||
|
||||
// 表单验证
|
||||
if (!name || name.trim() === "") {
|
||||
errors.name = "配置名称不能为空";
|
||||
}else if(/^[a-zA-Z_]+$/.test(name)){
|
||||
errors.name = "配置名称只能包含英文字母和下划线";
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
errors.type = "请选择或输入所属模块";
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
errors.environment = "请选择环境";
|
||||
}
|
||||
|
||||
if (!config || config.trim() === "") {
|
||||
errors.config = "配置数据不能为空";
|
||||
} else {
|
||||
try {
|
||||
JSON.parse(config);
|
||||
} catch (e) {
|
||||
errors.config = "配置数据必须是有效的JSON格式";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(errors).length > 0) {
|
||||
return Response.json({
|
||||
errors,
|
||||
values: Object.fromEntries(formData) as Record<string, string>
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const configData = {
|
||||
name,
|
||||
type,
|
||||
environment,
|
||||
config: JSON.parse(config),
|
||||
is_active,
|
||||
remark
|
||||
};
|
||||
|
||||
if (id) {
|
||||
// 更新配置
|
||||
const response = await updateConfig(id, configData);
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
} else {
|
||||
// 创建配置
|
||||
const response = await createConfig(configData);
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存成功,显示成功提示并重定向
|
||||
toastService.success("保存成功");
|
||||
return redirect("/config-lists");
|
||||
} catch (error) {
|
||||
console.error("保存配置失败:", error);
|
||||
return Response.json({
|
||||
success: false,
|
||||
errors: {
|
||||
general: error instanceof Error ? error.message : "保存配置失败,请稍后重试"
|
||||
},
|
||||
values: Object.fromEntries(formData) as Record<string, string>
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default function ConfigNew() {
|
||||
const { config, isEdit, types, environments } = useLoaderData<typeof loader>();
|
||||
const data = useLoaderData<typeof loader>();
|
||||
const actionData = useActionData<typeof action>();
|
||||
const navigation = useNavigation();
|
||||
const isSubmitting = navigation.state === "submitting";
|
||||
const formRef = useRef<HTMLFormElement>(null);
|
||||
|
||||
const [jsonError, setJsonError] = useState<string | null>(null);
|
||||
const [configDataValue, setConfigDataValue] = useState("");
|
||||
const { config, isEdit, types, environments, error } = data;
|
||||
|
||||
// 表单状态管理
|
||||
const [formValues, setFormValues] = useState<{
|
||||
name: string;
|
||||
type: string;
|
||||
environment: string;
|
||||
config: string;
|
||||
is_active: boolean;
|
||||
remark: string;
|
||||
}>({
|
||||
name: config?.name || "",
|
||||
type: config?.type || "",
|
||||
environment: config?.environment || "",
|
||||
config: config?.config ? JSON.stringify(config.config, null, 2) : "",
|
||||
is_active: config?.is_active ?? true,
|
||||
remark: config?.remark || "",
|
||||
});
|
||||
|
||||
// 表单验证错误状态
|
||||
const [formErrors, setFormErrors] = useState<{
|
||||
name?: string;
|
||||
type?: string;
|
||||
environment?: string;
|
||||
config?: string;
|
||||
general?: string;
|
||||
}>({});
|
||||
|
||||
// 字段是否被触摸过(用于确定何时显示错误)
|
||||
const [touchedFields, setTouchedFields] = useState<{
|
||||
name: boolean;
|
||||
type: boolean;
|
||||
environment: boolean;
|
||||
config: boolean;
|
||||
}>({
|
||||
name: false,
|
||||
type: false,
|
||||
environment: false,
|
||||
config: false
|
||||
});
|
||||
|
||||
// 示例JSON状态
|
||||
const [exampleJsonValue, setExampleJsonValue] = useState("");
|
||||
|
||||
// 标签选择状态
|
||||
const [selectedModule, setSelectedModule] = useState<string>("");
|
||||
const [selectedEnvironment, setSelectedEnvironment] = useState<string>("");
|
||||
|
||||
// 在 ConfigNew 组件中添加状态来跟踪当前选中的模板
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<keyof typeof CONFIG_TEMPLATES | null>(null);
|
||||
|
||||
// 从 actionData 初始化表单错误
|
||||
useEffect(() => {
|
||||
if (actionData?.errors) {
|
||||
setFormErrors(actionData.errors);
|
||||
}
|
||||
|
||||
// 如果提交后有错误,则将所有字段标记为已触摸
|
||||
if (actionData?.errors && Object.keys(actionData.errors).length > 0) {
|
||||
setTouchedFields({
|
||||
name: true,
|
||||
type: true,
|
||||
environment: true,
|
||||
config: true
|
||||
});
|
||||
}
|
||||
}, [actionData]);
|
||||
|
||||
// 根据加载的配置数据初始化表单
|
||||
useEffect(() => {
|
||||
// 初始化配置数据
|
||||
if (config) {
|
||||
setConfigDataValue(JSON.stringify(config.config, null, 2));
|
||||
setSelectedModule(config.type);
|
||||
setSelectedEnvironment(config.environment);
|
||||
setFormValues({
|
||||
name: config.name,
|
||||
type: config.type,
|
||||
environment: config.environment,
|
||||
config: JSON.stringify(config.config, null, 2),
|
||||
is_active: config.is_active,
|
||||
remark: config.remark || ""
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化示例JSON
|
||||
@@ -246,46 +332,213 @@ export default function ConfigNew() {
|
||||
}, null, 2));
|
||||
}, [config]);
|
||||
|
||||
// 处理JSON数据变更
|
||||
// 验证表单字段
|
||||
const validateField = (field: string, value: string): string => {
|
||||
switch (field) {
|
||||
case 'name':
|
||||
if(value.trim() === ""){
|
||||
return "配置名称不能为空";
|
||||
}else if(/^[a-zA-Z_]+$/.test(value)){
|
||||
return "配置名称只能包含英文字母和下划线";
|
||||
}else if(value.length > 100){
|
||||
return "配置名称不能超过100个字符";
|
||||
}
|
||||
return "";
|
||||
case 'type':
|
||||
return value.trim() === "" ? "请选择所属模块" : "";
|
||||
case 'environment':
|
||||
return value.trim() === "" ? "请选择环境" : "";
|
||||
case 'config':
|
||||
if (value.trim() === "") {
|
||||
return "配置数据不能为空";
|
||||
} else {
|
||||
try {
|
||||
JSON.parse(value);
|
||||
return "";
|
||||
} catch (e) {
|
||||
return "配置数据必须是有效的JSON格式";
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
// 处理字段改变
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
[name]: value
|
||||
}));
|
||||
|
||||
// 标记字段为已触摸
|
||||
if (['name', 'type', 'environment', 'config'].includes(name)) {
|
||||
setTouchedFields(prev => ({
|
||||
...prev,
|
||||
[name]: true
|
||||
}));
|
||||
}
|
||||
|
||||
// 实时验证
|
||||
const error = validateField(name, value);
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
[name]: error
|
||||
}));
|
||||
};
|
||||
|
||||
// 处理配置数据变更(JSON编辑器)
|
||||
const handleConfigDataChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const value = e.target.value;
|
||||
setConfigDataValue(value);
|
||||
const { value } = e.target;
|
||||
|
||||
if (value.trim() === "") {
|
||||
setJsonError(null);
|
||||
return;
|
||||
}
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
config: value
|
||||
}));
|
||||
|
||||
try {
|
||||
JSON.parse(value);
|
||||
setJsonError(null);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setJsonError(`配置数据必须是有效的JSON格式: ${error.message}`);
|
||||
} else {
|
||||
setJsonError("配置数据必须是有效的JSON格式");
|
||||
}
|
||||
}
|
||||
// 标记字段为已触摸
|
||||
setTouchedFields(prev => ({
|
||||
...prev,
|
||||
config: true
|
||||
}));
|
||||
|
||||
// 实时验证
|
||||
const error = validateField('config', value);
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
config: error
|
||||
}));
|
||||
};
|
||||
|
||||
// 格式化JSON
|
||||
const handleFormatJson = () => {
|
||||
|
||||
if (configDataValue.trim() === "") return;
|
||||
if (formValues.config.trim() === "") return;
|
||||
|
||||
try {
|
||||
const parsed = JSON.parse(configDataValue);
|
||||
setConfigDataValue(JSON.stringify(parsed, null, 2));
|
||||
setJsonError(null);
|
||||
const parsed = JSON.parse(formValues.config);
|
||||
const formatted = JSON.stringify(parsed, null, 2);
|
||||
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
config: formatted
|
||||
}));
|
||||
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
config: ""
|
||||
}));
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
setJsonError(`当前不是有效的JSON,无法格式化: ${error.message}`);
|
||||
} else {
|
||||
setJsonError("当前不是有效的JSON,无法格式化");
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
config: `当前不是有效的JSON,无法格式化: ${error instanceof Error ? error.message : '未知错误'}`
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// 处理模块类型选择
|
||||
const handleModuleSelect = (moduleType: string) => {
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
type: moduleType
|
||||
}));
|
||||
|
||||
// 标记字段为已触摸
|
||||
setTouchedFields(prev => ({
|
||||
...prev,
|
||||
type: true
|
||||
}));
|
||||
|
||||
// 清除错误
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
type: ""
|
||||
}));
|
||||
};
|
||||
|
||||
// 处理环境选择
|
||||
const handleEnvironmentSelect = (env: string) => {
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
environment: env
|
||||
}));
|
||||
|
||||
// 标记字段为已触摸
|
||||
setTouchedFields(prev => ({
|
||||
...prev,
|
||||
environment: true
|
||||
}));
|
||||
|
||||
// 清除错误
|
||||
setFormErrors(prev => ({
|
||||
...prev,
|
||||
environment: ""
|
||||
}));
|
||||
};
|
||||
|
||||
// 处理模板选择
|
||||
const handleTemplateSelect = (templateKey: keyof typeof CONFIG_TEMPLATES) => {
|
||||
setExampleJsonValue(JSON.stringify(CONFIG_TEMPLATES[templateKey], null, 2));
|
||||
setSelectedTemplate(templateKey);
|
||||
};
|
||||
|
||||
// 处理启用状态变更
|
||||
const handleActiveChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
is_active: e.target.checked
|
||||
}));
|
||||
};
|
||||
|
||||
// 提交前验证
|
||||
const handleBeforeSubmit = (e: React.FormEvent) => {
|
||||
// 标记所有字段为已触摸
|
||||
setTouchedFields({
|
||||
name: true,
|
||||
type: true,
|
||||
environment: true,
|
||||
config: true
|
||||
});
|
||||
|
||||
// 验证所有字段
|
||||
const errors = {
|
||||
name: validateField('name', formValues.name),
|
||||
type: validateField('type', formValues.type),
|
||||
environment: validateField('environment', formValues.environment),
|
||||
config: validateField('config', formValues.config)
|
||||
};
|
||||
|
||||
setFormErrors(errors);
|
||||
|
||||
// 如果有错误,阻止提交
|
||||
if (errors.name || errors.type || errors.environment || errors.config) {
|
||||
e.preventDefault();
|
||||
|
||||
// 滚动到第一个错误字段
|
||||
if (formRef.current) {
|
||||
const firstErrorField = Object.keys(errors).find(key => !!errors[key as keyof typeof errors]);
|
||||
if (firstErrorField) {
|
||||
const element = formRef.current.querySelector(`[name="${firstErrorField}"]`);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 如果加载数据时出错,显示错误信息
|
||||
if (error) {
|
||||
return (
|
||||
<div className="error-container p-6">
|
||||
<h1 className="text-xl font-bold text-red-500 mb-4">加载出错</h1>
|
||||
<p className="mb-4">{error}</p>
|
||||
<Button type="primary" to="/config-lists">返回列表</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="config-new-page">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
@@ -302,14 +555,20 @@ export default function ConfigNew() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{actionData?.errors?.general && (
|
||||
{formErrors.general && (
|
||||
<div className="mb-4 w-full">
|
||||
<div className="error-message general-error">{actionData.errors.general}</div>
|
||||
<div className="error-message general-error">{formErrors.general}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Card className="config-form-card">
|
||||
<Form method="post" id="configForm" className="config-form">
|
||||
<Form
|
||||
method="post"
|
||||
id="configForm"
|
||||
className="config-form"
|
||||
ref={formRef}
|
||||
onSubmit={handleBeforeSubmit}
|
||||
>
|
||||
{config?.id && <input type="hidden" name="id" value={config.id} />}
|
||||
|
||||
{/* 配置名称和状态 */}
|
||||
@@ -320,13 +579,14 @@ export default function ConfigNew() {
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
className={`form-input ${actionData?.errors?.name ? 'input-error' : ''}`}
|
||||
defaultValue={config?.name || ''}
|
||||
className={`form-input ${touchedFields.name && formErrors.name ? 'input-error' : ''}`}
|
||||
value={formValues.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="请输入配置名称,如database_connection"
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.name && (
|
||||
<div className="error-message">{actionData.errors.name}</div>
|
||||
{touchedFields.name && formErrors.name && (
|
||||
<div className="error-message">{formErrors.name}</div>
|
||||
)}
|
||||
<div className="form-help">
|
||||
唯一标识符,配置名称应使用英文,推荐使用下划线命名方式
|
||||
@@ -343,7 +603,8 @@ export default function ConfigNew() {
|
||||
name="is_active"
|
||||
value="true"
|
||||
className="form-checkbox"
|
||||
defaultChecked={config?.is_active !== false}
|
||||
checked={formValues.is_active}
|
||||
onChange={handleActiveChange}
|
||||
/>
|
||||
<label htmlFor="is_active" className="form-checkbox-label">
|
||||
启用此配置
|
||||
@@ -362,27 +623,28 @@ export default function ConfigNew() {
|
||||
<input
|
||||
type="hidden"
|
||||
name="type"
|
||||
value={selectedModule}
|
||||
value={formValues.type}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
id="typeDisplay"
|
||||
className={`form-input ${actionData?.errors?.type ? 'input-error' : ''}`}
|
||||
value={selectedModule}
|
||||
onChange={(e) => setSelectedModule(e.target.value)}
|
||||
className={`form-input ${touchedFields.type && formErrors.type ? 'input-error' : ''}`}
|
||||
value={formValues.type}
|
||||
onChange={handleInputChange}
|
||||
name="type"
|
||||
placeholder="请输入或选择所属模块"
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.type && (
|
||||
<div className="error-message">{actionData.errors.type}</div>
|
||||
{touchedFields.type && formErrors.type && (
|
||||
<div className="error-message">{formErrors.type}</div>
|
||||
)}
|
||||
<div className="tag-buttons mt-2">
|
||||
{types.map((type: string) => (
|
||||
<button
|
||||
key={type}
|
||||
type="button"
|
||||
className={`tag-button ${selectedModule === type ? 'active' : ''}`}
|
||||
onClick={() => setSelectedModule(type)}
|
||||
className={`tag-button ${formValues.type === type ? 'active' : ''}`}
|
||||
onClick={() => handleModuleSelect(type)}
|
||||
>
|
||||
{type}
|
||||
</button>
|
||||
@@ -399,27 +661,28 @@ export default function ConfigNew() {
|
||||
<input
|
||||
type="hidden"
|
||||
name="environment"
|
||||
value={selectedEnvironment}
|
||||
value={formValues.environment}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
id="environmentDisplay"
|
||||
className={`form-input ${actionData?.errors?.environment ? 'input-error' : ''}`}
|
||||
value={selectedEnvironment}
|
||||
onChange={(e) => setSelectedEnvironment(e.target.value)}
|
||||
className={`form-input ${touchedFields.environment && formErrors.environment ? 'input-error' : ''}`}
|
||||
value={formValues.environment}
|
||||
onChange={handleInputChange}
|
||||
name="environment"
|
||||
placeholder="请输入或选择环境"
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.environment && (
|
||||
<div className="error-message">{actionData.errors.environment}</div>
|
||||
{touchedFields.environment && formErrors.environment && (
|
||||
<div className="error-message">{formErrors.environment}</div>
|
||||
)}
|
||||
<div className="tag-buttons mt-2">
|
||||
{environments.map((env: string) => (
|
||||
<button
|
||||
key={env}
|
||||
type="button"
|
||||
className={`tag-button ${selectedEnvironment === env ? 'active' : ''}`}
|
||||
onClick={() => setSelectedEnvironment(env)}
|
||||
className={`tag-button ${formValues.environment === env ? 'active' : ''}`}
|
||||
onClick={() => handleEnvironmentSelect(env)}
|
||||
>
|
||||
{env}
|
||||
</button>
|
||||
@@ -439,8 +702,8 @@ export default function ConfigNew() {
|
||||
<textarea
|
||||
id="config"
|
||||
name="config"
|
||||
className={`json-editor ${(actionData?.errors?.config || jsonError) ? 'input-error' : ''}`}
|
||||
value={configDataValue}
|
||||
className={`json-editor ${touchedFields.config && formErrors.config ? 'input-error' : ''}`}
|
||||
value={formValues.config}
|
||||
onChange={handleConfigDataChange}
|
||||
required
|
||||
placeholder='请输入JSON格式的配置数据'
|
||||
@@ -457,8 +720,8 @@ export default function ConfigNew() {
|
||||
<i className="ri-braces-line mr-1"></i> 格式化JSON
|
||||
</Button>
|
||||
</div>
|
||||
{(actionData?.errors?.config || jsonError) && (
|
||||
<div className="error-message">{actionData?.errors?.config || jsonError}</div>
|
||||
{touchedFields.config && formErrors.config && (
|
||||
<div className="error-message">{formErrors.config}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -498,8 +761,7 @@ export default function ConfigNew() {
|
||||
className={`${selectedTemplate === 'database' ? 'border-[#00684a] text-[#00684a] focus:ring-0' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setExampleJsonValue(JSON.stringify(CONFIG_TEMPLATES.database, null, 2));
|
||||
setSelectedTemplate('database');
|
||||
handleTemplateSelect('database');
|
||||
}}
|
||||
>
|
||||
数据库配置
|
||||
@@ -510,8 +772,7 @@ export default function ConfigNew() {
|
||||
className={`${selectedTemplate === 'file' ? 'border-[#00684a] text-[#00684a] focus:ring-0' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setExampleJsonValue(JSON.stringify(CONFIG_TEMPLATES.file, null, 2));
|
||||
setSelectedTemplate('file');
|
||||
handleTemplateSelect('file');
|
||||
}}
|
||||
>
|
||||
文件存储配置
|
||||
@@ -522,8 +783,7 @@ export default function ConfigNew() {
|
||||
className={`${selectedTemplate === 'ai' ? 'border-[#00684a] text-[#00684a] focus:ring-0' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setExampleJsonValue(JSON.stringify(CONFIG_TEMPLATES.ai, null, 2));
|
||||
setSelectedTemplate('ai');
|
||||
handleTemplateSelect('ai');
|
||||
}}
|
||||
>
|
||||
AI服务配置
|
||||
@@ -545,7 +805,8 @@ export default function ConfigNew() {
|
||||
id="remark"
|
||||
name="remark"
|
||||
className="form-textarea"
|
||||
defaultValue={config?.remark || ''}
|
||||
value={formValues.remark}
|
||||
onChange={handleInputChange}
|
||||
rows={2}
|
||||
placeholder="请输入配置备注信息"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user