增加审批组件

This commit is contained in:
dengqichen 2025-10-24 22:45:10 +08:00
parent ab4ea6e367
commit 164a39bd42
6 changed files with 111 additions and 17 deletions

View File

@ -9,6 +9,7 @@ import { gitRepositoriesConfig } from './presets/git';
import { dockerRegistriesConfig } from './presets/docker';
import { notificationChannelTypesConfig, notificationChannelsConfig } from './presets/notification';
import { usersConfig, rolesConfig, departmentsConfig } from './presets/user';
import { environmentsConfig, projectGroupsConfig, applicationsConfig } from './presets/deploy';
/**
*
@ -22,7 +23,10 @@ export const DATA_SOURCE_REGISTRY: DataSourceRegistry = {
[DataSourceType.NOTIFICATION_CHANNELS]: notificationChannelsConfig,
[DataSourceType.USERS]: usersConfig,
[DataSourceType.ROLES]: rolesConfig,
[DataSourceType.DEPARTMENTS]: departmentsConfig
[DataSourceType.DEPARTMENTS]: departmentsConfig,
[DataSourceType.ENVIRONMENTS]: environmentsConfig,
[DataSourceType.PROJECT_GROUPS]: projectGroupsConfig,
[DataSourceType.APPLICATIONS]: applicationsConfig
};
/**

View File

@ -0,0 +1,55 @@
/**
*
*/
import type { DataSourceConfig } from '../types';
/**
*
*/
export const environmentsConfig: DataSourceConfig = {
url: '/api/v1/environments/list',
params: { enabled: true },
transform: (data: any[]) => {
return data.map((item: any) => ({
label: item.name,
value: item.id,
code: item.code,
type: item.type,
description: item.description
}));
}
};
/**
*
*/
export const projectGroupsConfig: DataSourceConfig = {
url: '/api/v1/project-groups/list',
params: { enabled: true },
transform: (data: any[]) => {
return data.map((item: any) => ({
label: item.name,
value: item.id,
code: item.code,
description: item.description
}));
}
};
/**
*
*/
export const applicationsConfig: DataSourceConfig = {
url: '/api/v1/applications/list',
params: { enabled: true },
transform: (data: any[]) => {
return data.map((item: any) => ({
label: item.name,
value: item.id,
code: item.code,
projectGroupId: item.projectGroupId,
description: item.description
}));
}
};

View File

@ -14,7 +14,10 @@ export enum DataSourceType {
NOTIFICATION_CHANNELS = 'NOTIFICATION_CHANNELS',
USERS = 'USERS',
ROLES = 'ROLES',
DEPARTMENTS = 'DEPARTMENTS'
DEPARTMENTS = 'DEPARTMENTS',
ENVIRONMENTS = 'ENVIRONMENTS',
PROJECT_GROUPS = 'PROJECT_GROUPS',
APPLICATIONS = 'APPLICATIONS'
}
/**

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { useToast } from '@/components/ui/use-toast';
import { FormDesigner } from '@/components/FormDesigner';
import type { FormSchema } from '@/components/FormDesigner';
import { ArrowLeft, Workflow } from 'lucide-react';
@ -14,6 +15,7 @@ import type { FormDefinitionRequest } from './types';
const FormDesignerPage: React.FC = () => {
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const { toast } = useToast();
const [formSchema, setFormSchema] = useState<FormSchema | null>(null);
const [formDefinition, setFormDefinition] = useState<any>(null);
@ -37,7 +39,11 @@ const FormDesignerPage: React.FC = () => {
// 保存表单(只更新 schema不修改基本信息
const handleSave = async (schema: FormSchema) => {
if (!id || !formDefinition) {
alert('表单信息加载失败');
toast({
variant: "destructive",
title: "保存失败",
description: "表单信息加载失败,请刷新页面后重试",
});
return;
}
@ -49,14 +55,22 @@ const FormDesignerPage: React.FC = () => {
isTemplate: formDefinition.isTemplate,
schema,
status: formDefinition.status || 'DRAFT',
version: formDefinition.version, // 乐观锁版本号
};
try {
await updateDefinition(Number(id), request);
alert('保存成功');
toast({
title: "保存成功",
description: `表单 "${formDefinition.name}" 已保存`,
});
} catch (error) {
console.error('保存表单失败:', error);
alert('保存失败');
toast({
variant: "destructive",
title: "保存失败",
description: error instanceof Error ? error.message : '未知错误,请稍后重试',
});
}
};

View File

@ -13,6 +13,7 @@ import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { useToast } from '@/components/ui/use-toast';
import { Loader2, FileText, Tag, Folder, AlignLeft, Copy } from 'lucide-react';
import { getEnabledCategories } from '../../Category/service';
import { updateDefinition } from '../service';
@ -27,6 +28,7 @@ interface EditBasicInfoModalProps {
}
const EditBasicInfoModal: React.FC<EditBasicInfoModalProps> = ({ visible, record, onClose, onSuccess }) => {
const { toast } = useToast();
const [submitting, setSubmitting] = useState(false);
const [categories, setCategories] = useState<FormCategoryResponse[]>([]);
const [formData, setFormData] = useState({
@ -70,15 +72,27 @@ const EditBasicInfoModal: React.FC<EditBasicInfoModalProps> = ({ visible, record
if (!record) return;
if (!formData.name.trim()) {
alert('请输入表单名称');
toast({
variant: "destructive",
title: "验证失败",
description: "请输入表单名称",
});
return;
}
if (!formData.key.trim()) {
alert('请输入表单标识');
toast({
variant: "destructive",
title: "验证失败",
description: "请输入表单标识",
});
return;
}
if (!/^[a-zA-Z0-9-]+$/.test(formData.key)) {
alert('表单标识只能包含英文字母、数字和中划线');
toast({
variant: "destructive",
title: "验证失败",
description: "表单标识只能包含英文字母、数字和中划线",
});
return;
}
@ -92,15 +106,23 @@ const EditBasicInfoModal: React.FC<EditBasicInfoModalProps> = ({ visible, record
schema: record.schema,
status: record.status,
isTemplate: formData.isTemplate,
version: record.version, // 乐观锁版本号
};
await updateDefinition(record.id, request);
alert('更新成功');
toast({
title: "更新成功",
description: `表单 "${formData.name}" 的基本信息已更新`,
});
onSuccess();
onClose();
} catch (error) {
console.error('更新表单失败:', error);
alert('更新表单失败: ' + (error as Error).message);
toast({
variant: "destructive",
title: "更新失败",
description: error instanceof Error ? error.message : '未知错误,请稍后重试',
});
} finally {
setSubmitting(false);
}

View File

@ -1,4 +1,4 @@
import { BaseQuery } from '@/types/base';
import { BaseQuery, BaseResponse } from '@/types/base';
import type { FormSchema } from '@/components/FormDesigner';
/**
@ -19,8 +19,7 @@ export interface FormDefinitionQuery extends BaseQuery {
/**
*
*/
export interface FormDefinitionResponse {
id: number;
export interface FormDefinitionResponse extends BaseResponse {
name: string;
key: string;
formVersion: number;
@ -30,10 +29,6 @@ export interface FormDefinitionResponse {
tags?: string[];
status: FormDefinitionStatus;
isTemplate: boolean;
createBy?: string;
createTime?: string;
updateBy?: string;
updateTime?: string;
}
/**
@ -48,5 +43,6 @@ export interface FormDefinitionRequest {
tags?: string[];
status?: FormDefinitionStatus;
isTemplate?: boolean;
version?: number; // 乐观锁版本号(更新时必传)
}