完善文件上传的接口对接
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
import { postgrestGet, postgrestPut, postgrestPost, type PostgrestParams } from '../postgrest-client';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
* @param dateString 日期字符串
|
||||
* @returns 格式化后的日期字符串
|
||||
*/
|
||||
function formatDate(dateString: string): string {
|
||||
if (!dateString) return '';
|
||||
try {
|
||||
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss');
|
||||
} catch (error) {
|
||||
console.error('日期格式化失败:', error);
|
||||
return dateString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从不同格式的 API 响应中提取数据
|
||||
* @param responseData API 响应数据
|
||||
* @returns 提取后的数据或 null
|
||||
*/
|
||||
function extractApiData<T>(responseData: unknown): T | null {
|
||||
if (!responseData) return null;
|
||||
|
||||
// 格式1: { code: number, msg: string, data: T }
|
||||
if (typeof responseData === 'object' && responseData !== null &&
|
||||
'code' in responseData &&
|
||||
'data' in responseData &&
|
||||
(responseData as { data: unknown }).data) {
|
||||
return (responseData as { data: T }).data;
|
||||
}
|
||||
|
||||
// 格式2: 直接是数据对象
|
||||
return responseData as T;
|
||||
}
|
||||
|
||||
// 文档状态枚举
|
||||
export enum DocumentStatus {
|
||||
CUTTING = "Cutting",
|
||||
EXTRACTIONING = "extractioning",
|
||||
REVIEWING = "reviewing",
|
||||
COMPLETED = "completed"
|
||||
}
|
||||
|
||||
// 文档类型接口
|
||||
export interface DocumentType {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// 提取结果接口
|
||||
interface ExtractedResult {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
// 摘要接口
|
||||
interface Summary {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
// 文档接口
|
||||
export interface Document {
|
||||
id: number;
|
||||
name: string;
|
||||
type_id: number;
|
||||
file_size: number;
|
||||
status: DocumentStatus;
|
||||
created_at: string;
|
||||
document_number?: string;
|
||||
path?: string;
|
||||
storage_type?: string;
|
||||
is_test_document?: boolean;
|
||||
evaluation_level?: string;
|
||||
ocr_result?: Record<string, string>;
|
||||
extracted_results?: ExtractedResult;
|
||||
sumary?: Summary;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当天的文档列表
|
||||
* @returns 文档列表
|
||||
*/
|
||||
export async function getTodayDocuments(): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
const today = dayjs().startOf('day').format('YYYY-MM-DD');
|
||||
console.log('查询当天文档,日期范围:', today);
|
||||
|
||||
const params: PostgrestParams = {
|
||||
select: `
|
||||
id,
|
||||
name,
|
||||
type_id,
|
||||
file_size,
|
||||
status,
|
||||
created_at,
|
||||
document_number,
|
||||
path,
|
||||
storage_type,
|
||||
is_test_document,
|
||||
evaluation_level,
|
||||
ocr_result,
|
||||
extracted_results,
|
||||
sumary,
|
||||
remark
|
||||
`,
|
||||
order: 'created_at.desc',
|
||||
filter: {
|
||||
'created_at': `gte.${today}`
|
||||
}
|
||||
};
|
||||
|
||||
// console.log('发送请求参数:', params);
|
||||
const response = await postgrestGet<Document[]>('documents', params);
|
||||
// console.log('API 响应:', response);
|
||||
|
||||
if (response.error) {
|
||||
console.error('API 返回错误:', response.error);
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
const extractedData = extractApiData<Document[]>(response.data);
|
||||
// console.log('提取后的数据:', extractedData);
|
||||
|
||||
if (!extractedData) {
|
||||
console.error('数据提取失败');
|
||||
return { error: '获取数据失败', status: 500 };
|
||||
}
|
||||
|
||||
return { data: extractedData };
|
||||
} catch (error) {
|
||||
console.error('获取当天文档列表失败:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '获取当天文档列表失败',
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文档类型列表
|
||||
* @returns 文档类型列表
|
||||
*/
|
||||
export async function getDocumentTypes(): Promise<{data: DocumentType[]; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
const params: PostgrestParams = {
|
||||
select: 'id, name'
|
||||
};
|
||||
|
||||
const response = await postgrestGet<DocumentType[]>('document_types', params);
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
const extractedData = extractApiData<DocumentType[]>(response.data);
|
||||
if (!extractedData) {
|
||||
return { error: '获取数据失败', status: 500 };
|
||||
}
|
||||
|
||||
return { data: extractedData };
|
||||
} catch (error) {
|
||||
console.error('获取文档类型列表失败:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '获取文档类型列表失败',
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定文档的状态
|
||||
* @param documentIds 文档ID列表
|
||||
* @returns 文档状态列表
|
||||
*/
|
||||
export async function getDocumentsStatus(documentIds: number[]): Promise<{data: Document[]; error?: never} | {data?: never; error: string; status?: number}> {
|
||||
try {
|
||||
if (!documentIds || documentIds.length === 0) {
|
||||
return { data: [] };
|
||||
}
|
||||
|
||||
const params: PostgrestParams = {
|
||||
select: 'id, status',
|
||||
filter: {
|
||||
'id': `in.(${documentIds.join(',')})`
|
||||
}
|
||||
};
|
||||
|
||||
const response = await postgrestGet<Document[]>('documents', params);
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error, status: response.status };
|
||||
}
|
||||
|
||||
const extractedData = extractApiData<Document[]>(response.data);
|
||||
if (!extractedData) {
|
||||
return { error: '获取数据失败', status: 500 };
|
||||
}
|
||||
|
||||
return { data: extractedData };
|
||||
} catch (error) {
|
||||
console.error('获取文档状态失败:', error);
|
||||
return {
|
||||
error: error instanceof Error ? error.message : '获取文档状态失败',
|
||||
status: 500
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
import { postgrestGet, postgrestPut, postgrestPost, type PostgrestParams } from '../postgrest-client';
|
||||
import dayjs from 'dayjs';
|
||||
// 配置项接口
|
||||
export interface ConfigItem {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
description: string;
|
||||
environment: string;
|
||||
config: Record<string, unknown>;
|
||||
is_active: boolean;
|
||||
version: string;
|
||||
created_by: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
/**
|
||||
* 格式化日期
|
||||
* @param dateString 日期字符串
|
||||
* @returns 格式化后的日期字符串
|
||||
*/
|
||||
function formatDate(dateString: string): string {
|
||||
if (!dateString) return '';
|
||||
try {
|
||||
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss');
|
||||
} catch (error) {
|
||||
console.error('日期格式化失败:', error);
|
||||
return dateString;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 从不同格式的 API 响应中提取数据
|
||||
* @param responseData API 响应数据
|
||||
* @returns 提取后的数据或 null
|
||||
*/
|
||||
function extractApiData<T>(responseData: unknown): T | null {
|
||||
if (!responseData) return null;
|
||||
|
||||
// 格式1: { code: number, msg: string, data: T }
|
||||
if (typeof responseData === 'object' && responseData !== null &&
|
||||
'code' in responseData &&
|
||||
'data' in responseData &&
|
||||
(responseData as { data: unknown }).data) {
|
||||
return (responseData as { data: T }).data;
|
||||
}
|
||||
|
||||
// 格式2: 直接是数据对象
|
||||
return responseData as T;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 获取配置列表
|
||||
export async function getConfigLists(params: {
|
||||
name?: string;
|
||||
type?: string;
|
||||
environment?: string;
|
||||
is_active?: boolean;
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
}): Promise<{data: ConfigItem[]; total: number; error?: never} | {data?: never; error: string}> {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
type,
|
||||
environment,
|
||||
is_active,
|
||||
page = 1,
|
||||
pageSize = 10
|
||||
} = params;
|
||||
|
||||
// 构建查询参数
|
||||
const queryParams: PostgrestParams = {
|
||||
select: '*',
|
||||
order: 'created_at.desc',
|
||||
limit: pageSize,
|
||||
offset: (page-1)*pageSize,
|
||||
filter: {} as Record<string, string>,
|
||||
headers: {
|
||||
'Prefer': 'count=exact'
|
||||
}
|
||||
};
|
||||
|
||||
// 添加筛选条件
|
||||
const filter: Record<string, string> = {};
|
||||
if (name) {
|
||||
filter['name'] = `ilike.%${name}%`;
|
||||
}
|
||||
if (type) {
|
||||
filter['type'] = `eq.${type}`;
|
||||
}
|
||||
if (environment) {
|
||||
filter['environment'] = `eq.${environment}`;
|
||||
}
|
||||
if (is_active !== undefined) {
|
||||
filter['is_active'] = `eq.${is_active}`;
|
||||
}
|
||||
queryParams.filter = filter;
|
||||
|
||||
// 获取数据
|
||||
const response = await postgrestGet<ConfigItem[]>('configurations', queryParams);
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error };
|
||||
}
|
||||
|
||||
const data = extractApiData<ConfigItem[]>(response.data);
|
||||
if (!data) {
|
||||
return { error: '获取数据失败' };
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
const formattedData = data.map(item => ({
|
||||
...item,
|
||||
created_at: formatDate(item.created_at),
|
||||
updated_at: formatDate(item.updated_at)
|
||||
}));
|
||||
|
||||
// 从响应头中获取总数
|
||||
let totalCount = 0;
|
||||
const responseWithHeaders = response as { data: ConfigItem[]; headers: Record<string, string> };
|
||||
if (responseWithHeaders.headers) {
|
||||
const rangeHeader = responseWithHeaders.headers['content-range'];
|
||||
if (rangeHeader) {
|
||||
const total = rangeHeader.split('/')[1];
|
||||
if (total !== '*') {
|
||||
totalCount = parseInt(total, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
data: formattedData,
|
||||
total: totalCount
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取配置列表失败:', error);
|
||||
return { error: error instanceof Error ? error.message : '获取配置列表失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置类型和环境选项
|
||||
export async function getConfigOptions(): Promise<{data: {types: string[]; environments: string[]}; error?: never} | {data?: never; error: string}> {
|
||||
try {
|
||||
// 获取类型选项
|
||||
const typeResponse = await postgrestGet<{type: string}[]>('configurations', {
|
||||
select: 'type'
|
||||
});
|
||||
|
||||
if (typeResponse.error) {
|
||||
return { error: typeResponse.error };
|
||||
}
|
||||
|
||||
const typesData = extractApiData<{type: string}[]>(typeResponse.data);
|
||||
if (!typesData) {
|
||||
return { error: '获取类型选项失败' };
|
||||
}
|
||||
|
||||
// 获取环境选项
|
||||
const envResponse = await postgrestGet<{environment: string}[]>('configurations', {
|
||||
select: 'environment'
|
||||
});
|
||||
|
||||
if (envResponse.error) {
|
||||
return { error: envResponse.error };
|
||||
}
|
||||
|
||||
const envData = extractApiData<{environment: string}[]>(envResponse.data);
|
||||
if (!envData) {
|
||||
return { error: '获取环境选项失败' };
|
||||
}
|
||||
|
||||
// 手动去重
|
||||
const types = [...new Set(typesData.map(item => item.type))];
|
||||
const environments = [...new Set(envData.map(item => item.environment))];
|
||||
|
||||
return {
|
||||
data: {
|
||||
types,
|
||||
environments
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取配置选项失败:', error);
|
||||
return { error: error instanceof Error ? error.message : '获取配置选项失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 获取配置详情
|
||||
export async function getConfigDetail(id: string): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
|
||||
try {
|
||||
const response = await postgrestGet<ConfigItem[]>('configurations', {
|
||||
filter: {
|
||||
'id': `eq.${id}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error };
|
||||
}
|
||||
|
||||
const data = extractApiData<ConfigItem[]>(response.data);
|
||||
if (!data || data.length === 0) {
|
||||
return { error: '未找到配置' };
|
||||
}
|
||||
|
||||
const config = data[0];
|
||||
return {
|
||||
data: {
|
||||
...config,
|
||||
created_at: formatDate(config.created_at),
|
||||
updated_at: formatDate(config.updated_at)
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('获取配置详情失败:', error);
|
||||
return { error: error instanceof Error ? error.message : '获取配置详情失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 创建配置
|
||||
export async function createConfig(data: {
|
||||
name: string;
|
||||
type: string;
|
||||
environment: string;
|
||||
config: Record<string, unknown>;
|
||||
is_active: boolean;
|
||||
remarks?: string;
|
||||
}): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
|
||||
try {
|
||||
const response = await postgrestPost<ConfigItem, typeof data>('configurations', data);
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error };
|
||||
}
|
||||
|
||||
const createdData = extractApiData<ConfigItem>(response.data);
|
||||
if (!createdData) {
|
||||
return { error: '创建配置失败' };
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
...createdData,
|
||||
created_at: formatDate(createdData.created_at),
|
||||
updated_at: formatDate(createdData.updated_at)
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('创建配置失败:', error);
|
||||
return { error: error instanceof Error ? error.message : '创建配置失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
export async function updateConfig(id: string, data: {
|
||||
name: string;
|
||||
type: string;
|
||||
environment: string;
|
||||
config: Record<string, unknown>;
|
||||
is_active: boolean;
|
||||
remarks?: string;
|
||||
}): Promise<{data: ConfigItem; error?: never} | {data?: never; error: string}> {
|
||||
try {
|
||||
const response = await postgrestPut<ConfigItem, typeof data>('configurations', data, {
|
||||
id: id.toString()
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
return { error: response.error };
|
||||
}
|
||||
|
||||
const updatedData = extractApiData<ConfigItem>(response.data);
|
||||
if (!updatedData) {
|
||||
return { error: '更新配置失败' };
|
||||
}
|
||||
|
||||
return {
|
||||
data: {
|
||||
...updatedData,
|
||||
created_at: formatDate(updatedData.created_at),
|
||||
updated_at: formatDate(updatedData.updated_at)
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('更新配置失败:', error);
|
||||
return { error: error instanceof Error ? error.message : '更新配置失败' };
|
||||
}
|
||||
}
|
||||
|
||||
// 更新配置状态
|
||||
export async function updateConfigStatus(id: number, is_active: boolean): Promise<{success: boolean; error?: string}> {
|
||||
try {
|
||||
const response = await postgrestPut<ConfigItem, {is_active: boolean}>(
|
||||
'configurations',
|
||||
{ is_active },
|
||||
{ id: id.toString() }
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
return { success: false, error: response.error };
|
||||
}
|
||||
|
||||
const updatedData = extractApiData<ConfigItem>(response.data);
|
||||
if (!updatedData) {
|
||||
return { success: false, error: '更新配置状态失败' };
|
||||
}
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('更新配置状态失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : '更新配置状态失败'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
path: '/files/upload',
|
||||
icon: 'ri-upload-cloud-line'
|
||||
},
|
||||
{
|
||||
id: 'file-list',
|
||||
title: '文件列表',
|
||||
path: '/files',
|
||||
icon: 'ri-file-list-3-line'
|
||||
},
|
||||
// {
|
||||
// id: 'file-list',
|
||||
// title: '文件列表',
|
||||
// path: '/files',
|
||||
// icon: 'ri-file-list-3-line'
|
||||
// },
|
||||
{
|
||||
id:'documents',
|
||||
title:'文档列表',
|
||||
@@ -80,15 +80,7 @@ export function Sidebar({ onToggle, collapsed }: SidebarProps) {
|
||||
title: '新增评查点',
|
||||
path: '/rules/new',
|
||||
icon: 'ri-add-circle-line'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'review-management',
|
||||
title: '评查结果',
|
||||
path: '/reviews',
|
||||
icon: 'ri-bar-chart-box-line',
|
||||
children: [
|
||||
},
|
||||
{
|
||||
id: 'review-detail',
|
||||
title: '评查详情',
|
||||
|
||||
@@ -50,7 +50,15 @@ export const UploadArea = forwardRef<UploadAreaRef, UploadAreaProps>(({
|
||||
}));
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!disabled && !shouldPreventFileSelect && fileInputRef.current) {
|
||||
if (disabled) return;
|
||||
|
||||
if (shouldPreventFileSelect) {
|
||||
// 如果应该阻止文件选择,则触发表单提交
|
||||
const form = fileInputRef.current?.closest('form');
|
||||
if (form) {
|
||||
form.requestSubmit();
|
||||
}
|
||||
} else if (fileInputRef.current) {
|
||||
fileInputRef.current.click();
|
||||
}
|
||||
}, [disabled, shouldPreventFileSelect]);
|
||||
@@ -76,7 +84,15 @@ export const UploadArea = forwardRef<UploadAreaRef, UploadAreaProps>(({
|
||||
e.preventDefault();
|
||||
setIsDragOver(false);
|
||||
|
||||
if (!disabled && !shouldPreventFileSelect && e.dataTransfer.files.length > 0) {
|
||||
if (disabled) return;
|
||||
|
||||
if (shouldPreventFileSelect) {
|
||||
// 如果应该阻止文件选择,则触发表单提交
|
||||
const form = e.currentTarget.closest('form');
|
||||
if (form) {
|
||||
form.requestSubmit();
|
||||
}
|
||||
} else if (e.dataTransfer.files.length > 0) {
|
||||
onFilesSelected(e.dataTransfer.files);
|
||||
}
|
||||
}, [disabled, shouldPreventFileSelect, onFilesSelected]);
|
||||
|
||||
@@ -7,13 +7,13 @@ import { FilterPanel, FilterSelect, SearchFilter } from "~/components/ui/FilterP
|
||||
import { Pagination } from "~/components/ui/Pagination";
|
||||
import { Table } from "~/components/ui/Table";
|
||||
import { Tag } from "~/components/ui/Tag";
|
||||
import { getConfigLists, getConfigOptions, updateConfigStatus, type ConfigItem } from "~/api/system_setting/config-lists";
|
||||
import configListsStyles from "~/styles/pages/config-lists_index.css?url";
|
||||
|
||||
export const links = () => [
|
||||
{ rel: "stylesheet", href: configListsStyles }
|
||||
];
|
||||
|
||||
|
||||
export const meta: MetaFunction = () => {
|
||||
return [
|
||||
{ title: "系统配置管理 - 中国烟草AI合同及卷宗审核系统" },
|
||||
@@ -54,165 +54,55 @@ export const MODULE_LABELS: Record<ConfigModule, string> = {
|
||||
[ConfigModule.NOTIFICATION]: '通知'
|
||||
};
|
||||
|
||||
// 配置数据类型
|
||||
interface ConfigDataType {
|
||||
[key: string]: string | number | boolean | string[] | ConfigDataType | ConfigDataType[];
|
||||
}
|
||||
|
||||
// 配置项模型
|
||||
interface ConfigItem {
|
||||
id: string;
|
||||
configName: string;
|
||||
module: ConfigModule;
|
||||
environment: ConfigEnvironment;
|
||||
isActive: boolean;
|
||||
configData: ConfigDataType;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface LoaderData {
|
||||
configs: ConfigItem[];
|
||||
totalCount: number;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
totalPages: number;
|
||||
types: string[];
|
||||
environments: string[];
|
||||
}
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const url = new URL(request.url);
|
||||
const configName = url.searchParams.get("configName") || "";
|
||||
const module = url.searchParams.get("module") || "";
|
||||
const name = url.searchParams.get("name") || "";
|
||||
const type = url.searchParams.get("type") || "";
|
||||
const environment = url.searchParams.get("environment") || "";
|
||||
const isActive = url.searchParams.get("isActive") || "";
|
||||
const is_active = url.searchParams.get("is_active") ? url.searchParams.get("is_active") === "true" : undefined;
|
||||
const currentPage = parseInt(url.searchParams.get("page") || "1", 10);
|
||||
const pageSize = parseInt(url.searchParams.get("pageSize") || "10", 10);
|
||||
|
||||
try {
|
||||
// 模拟数据,实际项目中应从API获取
|
||||
const mockConfigs: ConfigItem[] = [
|
||||
{
|
||||
id: "1",
|
||||
configName: "database_connection",
|
||||
module: ConfigModule.SYSTEM,
|
||||
environment: ConfigEnvironment.PROD,
|
||||
isActive: true,
|
||||
configData: {
|
||||
database: {
|
||||
host: "db.cluster.com",
|
||||
port: 5432,
|
||||
pool_size: 20,
|
||||
ssl: true
|
||||
},
|
||||
cache: {
|
||||
ttl: 3600,
|
||||
max_entries: 1000
|
||||
},
|
||||
feature_flags: ["new_ui", "analytics_v2"]
|
||||
},
|
||||
createdAt: "2023-07-10 10:15:23",
|
||||
updatedAt: "2023-07-15 14:30:26"
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
configName: "text_extraction_ai",
|
||||
module: ConfigModule.AI,
|
||||
environment: ConfigEnvironment.TEST,
|
||||
isActive: true,
|
||||
configData: {
|
||||
model: "gpt-4",
|
||||
parameters: {
|
||||
temperature: 0.7,
|
||||
max_tokens: 2000
|
||||
},
|
||||
api_key: "sk-**********",
|
||||
timeout: 30
|
||||
},
|
||||
createdAt: "2023-07-12 08:45:12",
|
||||
updatedAt: "2023-07-14 09:15:33"
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
configName: "notification_service",
|
||||
module: ConfigModule.NOTIFICATION,
|
||||
environment: ConfigEnvironment.DEV,
|
||||
isActive: false,
|
||||
configData: {
|
||||
email: {
|
||||
smtp_server: "smtp.example.com",
|
||||
port: 587,
|
||||
use_tls: true,
|
||||
sender: "noreply@example.com"
|
||||
},
|
||||
sms: {
|
||||
provider: "aliyun",
|
||||
region: "cn-hangzhou",
|
||||
sign_name: "AI审核系统"
|
||||
}
|
||||
},
|
||||
createdAt: "2023-07-05 13:20:45",
|
||||
updatedAt: "2023-07-10 16:45:19"
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
configName: "file_storage",
|
||||
module: ConfigModule.FILE,
|
||||
environment: ConfigEnvironment.PROD,
|
||||
isActive: true,
|
||||
configData: {
|
||||
type: "oss",
|
||||
region: "cn-shanghai",
|
||||
bucket: "contracts-ai-review",
|
||||
access_control: "private",
|
||||
lifecycle_rules: [
|
||||
{
|
||||
prefix: "temp/",
|
||||
ttl_days: 7
|
||||
}
|
||||
]
|
||||
},
|
||||
createdAt: "2023-06-28 09:30:18",
|
||||
updatedAt: "2023-07-08 11:22:07"
|
||||
}
|
||||
];
|
||||
|
||||
// 过滤数据
|
||||
let filteredConfigs = [...mockConfigs];
|
||||
|
||||
if (configName) {
|
||||
filteredConfigs = filteredConfigs.filter(config =>
|
||||
config.configName.toLowerCase().includes(configName.toLowerCase())
|
||||
);
|
||||
// 获取配置列表
|
||||
const configsResponse = await getConfigLists({
|
||||
name,
|
||||
type,
|
||||
environment,
|
||||
is_active,
|
||||
page: currentPage,
|
||||
pageSize
|
||||
});
|
||||
|
||||
if (configsResponse.error || !configsResponse.data) {
|
||||
throw new Error(configsResponse.error || "获取配置列表失败");
|
||||
}
|
||||
|
||||
if (module) {
|
||||
filteredConfigs = filteredConfigs.filter(config => config.module === module);
|
||||
|
||||
// 获取配置选项
|
||||
const optionsResponse = await getConfigOptions();
|
||||
|
||||
if (optionsResponse.error || !optionsResponse.data) {
|
||||
throw new Error(optionsResponse.error || "获取配置选项失败");
|
||||
}
|
||||
|
||||
if (environment) {
|
||||
filteredConfigs = filteredConfigs.filter(config => config.environment === environment);
|
||||
}
|
||||
|
||||
if (isActive) {
|
||||
const activeValue = isActive === 'true';
|
||||
filteredConfigs = filteredConfigs.filter(config => config.isActive === activeValue);
|
||||
}
|
||||
|
||||
// 计算分页信息
|
||||
const totalCount = filteredConfigs.length;
|
||||
const totalPages = Math.ceil(totalCount / pageSize);
|
||||
|
||||
// 分页截取
|
||||
const startIndex = (currentPage - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const paginatedConfigs = filteredConfigs.slice(startIndex, endIndex);
|
||||
|
||||
|
||||
return json<LoaderData>({
|
||||
configs: paginatedConfigs,
|
||||
totalCount,
|
||||
configs: configsResponse.data,
|
||||
totalCount: configsResponse.total,
|
||||
currentPage,
|
||||
pageSize,
|
||||
totalPages
|
||||
totalPages: Math.ceil(configsResponse.total / pageSize),
|
||||
types: optionsResponse.data.types,
|
||||
environments: optionsResponse.data.environments
|
||||
}, {
|
||||
headers: {
|
||||
"Cache-Control": "max-age=60, s-maxage=180"
|
||||
@@ -233,28 +123,18 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
return json({ success: false, error: "缺少配置ID" }, { status: 400 });
|
||||
}
|
||||
|
||||
// 进行更新启用和禁用的状态
|
||||
try {
|
||||
if (_action === 'toggleStatus') {
|
||||
const isActive = formData.get('isActive') === 'true';
|
||||
const newStatus = !isActive;
|
||||
const is_active = formData.get('is_active') === 'true';
|
||||
|
||||
// 实际项目中应调用API更新状态
|
||||
console.log(`切换配置 ${configId} 状态为: ${newStatus}`);
|
||||
const response = await updateConfigStatus(parseInt(configId as string), is_active);
|
||||
|
||||
// 模拟API调用
|
||||
// const response = await fetch(`/api/configs/${configId}/status`, {
|
||||
// method: 'PATCH',
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
// },
|
||||
// body: JSON.stringify({ isActive: newStatus }),
|
||||
// });
|
||||
if (!response.success) {
|
||||
return json({ success: false, error: response.error }, { status: 500 });
|
||||
}
|
||||
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`状态切换失败: ${response.status}`);
|
||||
// }
|
||||
|
||||
return json({ success: true, newStatus });
|
||||
return json({ success: true });
|
||||
}
|
||||
|
||||
return json({ success: false, error: "未知操作" }, { status: 400 });
|
||||
@@ -275,7 +155,7 @@ export function ErrorBoundary() {
|
||||
}
|
||||
|
||||
export default function ConfigListsIndex() {
|
||||
const { configs, totalCount, currentPage, pageSize } = useLoaderData<typeof loader>();
|
||||
const { configs, totalCount, currentPage, pageSize, types, environments } = useLoaderData<typeof loader>();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const submit = useSubmit();
|
||||
const [showDetailModal, setShowDetailModal] = useState(false);
|
||||
@@ -300,9 +180,9 @@ export default function ConfigListsIndex() {
|
||||
const handleConfigNameSearch = (value: string) => {
|
||||
const newParams = new URLSearchParams(searchParams);
|
||||
if (value) {
|
||||
newParams.set('configName', value);
|
||||
newParams.set('name', value);
|
||||
} else {
|
||||
newParams.delete('configName');
|
||||
newParams.delete('name');
|
||||
}
|
||||
|
||||
// 搜索时,重置到第一页
|
||||
@@ -312,11 +192,11 @@ export default function ConfigListsIndex() {
|
||||
};
|
||||
|
||||
const handleToggleStatus = (config: ConfigItem) => {
|
||||
if (window.confirm(`确定要${config.isActive ? '禁用' : '启用'}该配置吗?`)) {
|
||||
if (window.confirm(`确定要${config.is_active ? '禁用' : '启用'}该配置吗?`)) {
|
||||
const formData = new FormData();
|
||||
formData.append('_action', 'toggleStatus');
|
||||
formData.append('configId', config.id);
|
||||
formData.append('isActive', String(config.isActive));
|
||||
formData.append('configId', config.id.toString());
|
||||
formData.append('is_active', String(!config.is_active));
|
||||
|
||||
submit(formData, { method: 'post' });
|
||||
}
|
||||
@@ -342,10 +222,20 @@ export default function ConfigListsIndex() {
|
||||
|
||||
// 处理重置筛选
|
||||
const handleReset = () => {
|
||||
const nameInput = document.querySelector('input[placeholder="请输入配置名称"]') as HTMLInputElement;
|
||||
const typeSelect = document.querySelector('select[name="type"]') as HTMLInputElement;
|
||||
const environmentSelect = document.querySelector('select[name="environment"]') as HTMLInputElement;
|
||||
const statusSelect = document.querySelector('select[name="is_active"]') as HTMLInputElement;
|
||||
|
||||
setSearchParams(new URLSearchParams());
|
||||
|
||||
if(nameInput) nameInput.value = ''
|
||||
if(typeSelect) typeSelect.value = ''
|
||||
if(environmentSelect) environmentSelect.value = ''
|
||||
if(statusSelect) statusSelect.value = ''
|
||||
|
||||
};
|
||||
|
||||
|
||||
// 关闭详情模态框
|
||||
const closeDetailModal = () => {
|
||||
setShowDetailModal(false);
|
||||
@@ -356,43 +246,42 @@ export default function ConfigListsIndex() {
|
||||
const columns = [
|
||||
{
|
||||
title: "配置名称",
|
||||
dataIndex: "configName" as keyof ConfigItem,
|
||||
key: "configName",
|
||||
dataIndex: "name" as keyof ConfigItem,
|
||||
key: "name",
|
||||
width: "20%"
|
||||
},
|
||||
{
|
||||
title: "所属模块",
|
||||
key: "module",
|
||||
key: "type",
|
||||
width: "10%",
|
||||
render: (_: unknown, record: ConfigItem) => MODULE_LABELS[record.module]
|
||||
render: (_: unknown, record: ConfigItem) => record.type
|
||||
},
|
||||
{
|
||||
title: "环境",
|
||||
key: "environment",
|
||||
width: "15%",
|
||||
render: (_: unknown, record: ConfigItem) => {
|
||||
const envClass = `env-tag env-tag-${record.environment}`;
|
||||
return (
|
||||
<span className={envClass}>
|
||||
{ENVIRONMENT_LABELS[record.environment]}
|
||||
<span className="env-tag">
|
||||
{record.environment}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "状态",
|
||||
key: "isActive",
|
||||
key: "is_active",
|
||||
width: "15%",
|
||||
render: (_: unknown, record: ConfigItem) => (
|
||||
<Tag color={record.isActive ? 'green' : 'red'}>
|
||||
{record.isActive ? '已启用' : '已禁用'}
|
||||
<Tag color={record.is_active ? 'green' : 'red'}>
|
||||
{record.is_active ? '已启用' : '已禁用'}
|
||||
</Tag>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "最后更新时间",
|
||||
dataIndex: "updatedAt" as keyof ConfigItem,
|
||||
key: "updatedAt",
|
||||
dataIndex: "updated_at" as keyof ConfigItem,
|
||||
key: "updated_at",
|
||||
width: "15%"
|
||||
},
|
||||
{
|
||||
@@ -417,29 +306,17 @@ export default function ConfigListsIndex() {
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
className={`operation-btn ${record.isActive ? '!text-[--color-warning]' : '!text-[--color-success]'}`}
|
||||
className={`operation-btn ${record.is_active ? '!text-[--color-warning]' : '!text-[--color-success]'}`}
|
||||
onClick={() => handleToggleStatus(record)}
|
||||
>
|
||||
<i className={record.isActive ? `ri-stop-circle-line` : `ri-play-circle-line`}></i>
|
||||
{record.isActive ? '禁用' : '启用'}
|
||||
<i className={record.is_active ? `ri-stop-circle-line` : `ri-play-circle-line`}></i>
|
||||
{record.is_active ? '禁用' : '启用'}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
// 生成环境选项
|
||||
const environmentOptions = Object.entries(ENVIRONMENT_LABELS).map(([value, label]) => ({
|
||||
value,
|
||||
label
|
||||
}));
|
||||
|
||||
// 生成模块选项
|
||||
const moduleOptions = Object.entries(MODULE_LABELS).map(([value, label]) => ({
|
||||
value,
|
||||
label
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="config-lists">
|
||||
{/* 页面头部 */}
|
||||
@@ -458,9 +335,9 @@ export default function ConfigListsIndex() {
|
||||
<Button type="default" icon="ri-refresh-line" onClick={handleReset} className="mr-2">
|
||||
重置
|
||||
</Button>
|
||||
<Button type="primary" icon="ri-search-line">
|
||||
{/* <Button type="primary" icon="ri-search-line">
|
||||
查询
|
||||
</Button>
|
||||
</Button> */}
|
||||
</>
|
||||
}
|
||||
noActionDivider={true}
|
||||
@@ -468,7 +345,7 @@ export default function ConfigListsIndex() {
|
||||
<SearchFilter
|
||||
label="配置名称"
|
||||
placeholder="请输入配置名称"
|
||||
value={searchParams.get('configName') || ''}
|
||||
value={searchParams.get('name') || ''}
|
||||
onSearch={handleConfigNameSearch}
|
||||
className="flex-1 min-w-[200px]"
|
||||
instantSearch={true}
|
||||
@@ -476,9 +353,9 @@ export default function ConfigListsIndex() {
|
||||
|
||||
<FilterSelect
|
||||
label="所属模块"
|
||||
name="module"
|
||||
value={searchParams.get('module') || ''}
|
||||
options={[{ value: '', label: '全部' }, ...moduleOptions]}
|
||||
name="type"
|
||||
value={searchParams.get('type') || ''}
|
||||
options={[ ...types.map(type => ({ value: type, label: type }))]}
|
||||
onChange={handleFilterChange}
|
||||
className="flex-1 min-w-[200px]"
|
||||
/>
|
||||
@@ -487,17 +364,16 @@ export default function ConfigListsIndex() {
|
||||
label="环境"
|
||||
name="environment"
|
||||
value={searchParams.get('environment') || ''}
|
||||
options={[{ value: '', label: '全部' }, ...environmentOptions]}
|
||||
options={[ ...environments.map(env => ({ value: env, label: env }))]}
|
||||
onChange={handleFilterChange}
|
||||
className="flex-1 min-w-[200px]"
|
||||
/>
|
||||
|
||||
<FilterSelect
|
||||
label="状态"
|
||||
name="isActive"
|
||||
value={searchParams.get('isActive') || ''}
|
||||
name="is_active"
|
||||
value={searchParams.get('is_active') || ''}
|
||||
options={[
|
||||
{ value: '', label: '全部' },
|
||||
{ value: 'true', label: '已启用' },
|
||||
{ value: 'false', label: '已禁用' }
|
||||
]}
|
||||
@@ -545,19 +421,19 @@ export default function ConfigListsIndex() {
|
||||
<div className="config-detail-content">
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">配置名称</div>
|
||||
<div className="config-detail-value">{selectedConfig.configName}</div>
|
||||
<div className="config-detail-value">{selectedConfig.name}</div>
|
||||
</div>
|
||||
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">所属模块</div>
|
||||
<div className="config-detail-value">{MODULE_LABELS[selectedConfig.module]}</div>
|
||||
<div className="config-detail-value">{selectedConfig.type}</div>
|
||||
</div>
|
||||
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">环境</div>
|
||||
<div className="config-detail-value">
|
||||
<span className={`env-tag env-tag-${selectedConfig.environment}`}>
|
||||
{ENVIRONMENT_LABELS[selectedConfig.environment]}
|
||||
<span className="env-tag">
|
||||
{selectedConfig.environment}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -565,8 +441,8 @@ export default function ConfigListsIndex() {
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">状态</div>
|
||||
<div className="config-detail-value">
|
||||
<Tag color={selectedConfig.isActive ? 'green' : 'red'}>
|
||||
{selectedConfig.isActive ? '已启用' : '已禁用'}
|
||||
<Tag color={selectedConfig.is_active ? 'green' : 'red'}>
|
||||
{selectedConfig.is_active ? '已启用' : '已禁用'}
|
||||
</Tag>
|
||||
</div>
|
||||
</div>
|
||||
@@ -574,19 +450,19 @@ export default function ConfigListsIndex() {
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">配置数据</div>
|
||||
<pre className="config-detail-code">
|
||||
{JSON.stringify(selectedConfig.configData, null, 2)}
|
||||
{JSON.stringify(selectedConfig.config, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">创建时间</div>
|
||||
<div className="config-detail-value">{selectedConfig.createdAt}</div>
|
||||
<div className="config-detail-value">{selectedConfig.created_at}</div>
|
||||
</div>
|
||||
|
||||
<div className="config-detail-item">
|
||||
<div className="config-detail-label">更新时间</div>
|
||||
<div className="config-detail-value">{selectedConfig.updatedAt}</div>
|
||||
<div className="config-detail-value">{selectedConfig.updated_at}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+105
-209
@@ -4,6 +4,7 @@ import { useEffect, useState } 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 { getConfigOptions, getConfigDetail, createConfig, updateConfig } from "~/api/system_setting/config-lists";
|
||||
import configNewStyles from "~/styles/pages/config-lists_new.css?url";
|
||||
|
||||
export const links = () => [
|
||||
@@ -40,17 +41,19 @@ export const EXTENDED_ENVIRONMENT_LABELS: Record<string, string> = {
|
||||
|
||||
interface ConfigData {
|
||||
id: string;
|
||||
configName: string;
|
||||
module: ConfigModule;
|
||||
environment: string; // 使用扩展的环境类型
|
||||
isActive: boolean;
|
||||
configData: string; // JSON字符串
|
||||
remarks?: string; // 添加备注字段
|
||||
name: string;
|
||||
type: string;
|
||||
environment: string;
|
||||
is_active: boolean;
|
||||
config: Record<string, unknown>;
|
||||
remarks?: string;
|
||||
}
|
||||
|
||||
interface LoaderData {
|
||||
config?: ConfigData;
|
||||
isEdit: boolean;
|
||||
types: string[];
|
||||
environments: string[];
|
||||
}
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
@@ -58,156 +61,72 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const id = url.searchParams.get("id");
|
||||
let config: ConfigData | undefined = undefined;
|
||||
|
||||
if (id) {
|
||||
try {
|
||||
// 实际应用中,应从API获取配置详情
|
||||
// const response = await fetch(`${process.env.API_BASE_URL}/api/configs/${id}`);
|
||||
// if (!response.ok) throw new Error(`获取配置详情失败: ${response.status}`);
|
||||
// config = await response.json();
|
||||
// config.configData = JSON.stringify(config.configData, null, 2);
|
||||
|
||||
// 使用模拟数据
|
||||
if (id === "1") {
|
||||
config = {
|
||||
id: "1",
|
||||
configName: "database_connection",
|
||||
module: ConfigModule.SYSTEM,
|
||||
environment: ExtendedConfigEnvironment.PROD,
|
||||
isActive: true,
|
||||
remarks: "数据库连接配置,包含主库和从库配置",
|
||||
configData: JSON.stringify({
|
||||
database: {
|
||||
host: "db.cluster.com",
|
||||
port: 5432,
|
||||
pool_size: 20,
|
||||
ssl: true
|
||||
},
|
||||
cache: {
|
||||
ttl: 3600,
|
||||
max_entries: 1000
|
||||
},
|
||||
feature_flags: ["new_ui", "analytics_v2"]
|
||||
}, null, 2)
|
||||
};
|
||||
} else if (id === "2") {
|
||||
config = {
|
||||
id: "2",
|
||||
configName: "text_extraction_ai",
|
||||
module: ConfigModule.AI,
|
||||
environment: ExtendedConfigEnvironment.TEST,
|
||||
isActive: true,
|
||||
remarks: "AI文本抽取服务配置",
|
||||
configData: JSON.stringify({
|
||||
model: "gpt-4",
|
||||
parameters: {
|
||||
temperature: 0.7,
|
||||
max_tokens: 2000
|
||||
},
|
||||
api_key: "sk-**********",
|
||||
timeout: 30
|
||||
}, null, 2)
|
||||
};
|
||||
} else if (id === "3") {
|
||||
config = {
|
||||
id: "3",
|
||||
configName: "notification_service",
|
||||
module: ConfigModule.NOTIFICATION,
|
||||
environment: ExtendedConfigEnvironment.DEV,
|
||||
isActive: false,
|
||||
remarks: "通知服务配置,目前处于开发测试阶段",
|
||||
configData: JSON.stringify({
|
||||
email: {
|
||||
smtp_server: "smtp.example.com",
|
||||
port: 587,
|
||||
use_tls: true,
|
||||
sender: "noreply@example.com"
|
||||
},
|
||||
sms: {
|
||||
provider: "aliyun",
|
||||
region: "cn-hangzhou",
|
||||
sign_name: "AI审核系统"
|
||||
}
|
||||
}, null, 2)
|
||||
};
|
||||
} else if (id === "4") {
|
||||
config = {
|
||||
id: "4",
|
||||
configName: "file_storage",
|
||||
module: ConfigModule.FILE,
|
||||
environment: ExtendedConfigEnvironment.COMMON,
|
||||
isActive: true,
|
||||
remarks: "文件存储通用配置,适用于所有环境",
|
||||
configData: JSON.stringify({
|
||||
type: "oss",
|
||||
region: "cn-shanghai",
|
||||
bucket: "contracts-ai-review",
|
||||
access_control: "private",
|
||||
lifecycle_rules: [
|
||||
{
|
||||
prefix: "temp/",
|
||||
ttl_days: 7
|
||||
}
|
||||
]
|
||||
}, null, 2)
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取配置详情失败:", error);
|
||||
// 在实际应用中,应该将错误信息返回给客户端
|
||||
// 这里简单处理,返回空config
|
||||
}
|
||||
// 获取配置选项
|
||||
const optionsResponse = await getConfigOptions();
|
||||
if (optionsResponse.error) {
|
||||
throw new Error(optionsResponse.error);
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
if (id) {
|
||||
// 获取配置详情
|
||||
const detailResponse = await getConfigDetail(id);
|
||||
if (detailResponse.error) {
|
||||
throw new Error(detailResponse.error);
|
||||
}
|
||||
config = detailResponse.data;
|
||||
}
|
||||
|
||||
return json<LoaderData>({
|
||||
config,
|
||||
isEdit: !!config
|
||||
isEdit: !!config,
|
||||
types: optionsResponse.data.types,
|
||||
environments: optionsResponse.data.environments
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
interface ActionData {
|
||||
success?: boolean;
|
||||
errors?: {
|
||||
configName?: string;
|
||||
module?: string;
|
||||
name?: string;
|
||||
type?: string;
|
||||
environment?: string;
|
||||
configData?: string;
|
||||
config?: string;
|
||||
general?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const formData = await request.formData();
|
||||
const configId = formData.get("id") as string;
|
||||
const configName = formData.get("configName") as string;
|
||||
const module = formData.get("module") as string;
|
||||
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 configData = formData.get("configData") as string;
|
||||
const isActive = formData.get("isActive") === "true";
|
||||
const config = formData.get("config") as string;
|
||||
const is_active = formData.get("is_active") === "true";
|
||||
const remarks = formData.get("remarks") as string;
|
||||
|
||||
const errors: ActionData["errors"] = {};
|
||||
|
||||
// 表单验证
|
||||
if (!configName || configName.trim() === "") {
|
||||
errors.configName = "配置名称不能为空";
|
||||
if (!name || name.trim() === "") {
|
||||
errors.name = "配置名称不能为空";
|
||||
}
|
||||
|
||||
if (!module) {
|
||||
errors.module = "请选择所属模块";
|
||||
if (!type) {
|
||||
errors.type = "请选择所属模块";
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
errors.environment = "请选择环境";
|
||||
}
|
||||
|
||||
if (!configData || configData.trim() === "") {
|
||||
errors.configData = "配置数据不能为空";
|
||||
if (!config || config.trim() === "") {
|
||||
errors.config = "配置数据不能为空";
|
||||
} else {
|
||||
try {
|
||||
JSON.parse(configData);
|
||||
JSON.parse(config);
|
||||
} catch (e) {
|
||||
errors.configData = "配置数据必须是有效的JSON格式";
|
||||
errors.config = "配置数据必须是有效的JSON格式";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,31 +135,29 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
}
|
||||
|
||||
try {
|
||||
// 实际应用中,应调用API保存数据
|
||||
console.log("保存配置:", { configId, configName, module, environment, configData, isActive, remarks });
|
||||
const configData = {
|
||||
name,
|
||||
type,
|
||||
environment,
|
||||
config: JSON.parse(config),
|
||||
is_active,
|
||||
remarks
|
||||
};
|
||||
|
||||
// 模拟API调用
|
||||
// const response = await fetch(`${process.env.API_BASE_URL}/api/configs${configId ? `/${configId}` : ''}`, {
|
||||
// method: configId ? "PUT" : "POST",
|
||||
// headers: {
|
||||
// "Content-Type": "application/json",
|
||||
// },
|
||||
// body: JSON.stringify({
|
||||
// id: configId,
|
||||
// configName,
|
||||
// module,
|
||||
// environment,
|
||||
// configData: JSON.parse(configData),
|
||||
// isActive,
|
||||
// remarks,
|
||||
// }),
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`保存失败: ${response.status}`);
|
||||
// }
|
||||
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);
|
||||
@@ -290,8 +207,7 @@ const JSON_TEMPLATES = {
|
||||
};
|
||||
|
||||
export default function ConfigNew() {
|
||||
const { config, isEdit } = useLoaderData<typeof loader>();
|
||||
|
||||
const { config, isEdit, types, environments } = useLoaderData<typeof loader>();
|
||||
const actionData = useActionData<typeof action>();
|
||||
const navigation = useNavigation();
|
||||
const isSubmitting = navigation.state === "submitting";
|
||||
@@ -306,16 +222,9 @@ export default function ConfigNew() {
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化配置数据
|
||||
if (config?.configData) {
|
||||
setConfigDataValue(config.configData);
|
||||
}
|
||||
|
||||
// 初始化模块和环境的选中状态
|
||||
if (config?.module) {
|
||||
setSelectedModule(config.module);
|
||||
}
|
||||
|
||||
if (config?.environment) {
|
||||
if (config) {
|
||||
setConfigDataValue(JSON.stringify(config.config, null, 2));
|
||||
setSelectedModule(config.type);
|
||||
setSelectedEnvironment(config.environment);
|
||||
}
|
||||
|
||||
@@ -333,7 +242,6 @@ export default function ConfigNew() {
|
||||
},
|
||||
feature_flags: ["new_ui", "analytics_v2"]
|
||||
}, null, 2));
|
||||
|
||||
}, [config]);
|
||||
|
||||
// 处理JSON数据变更
|
||||
@@ -382,16 +290,6 @@ export default function ConfigNew() {
|
||||
setJsonError(null);
|
||||
};
|
||||
|
||||
// 模块标签点击
|
||||
const handleModuleTagClick = (module: string) => {
|
||||
setSelectedModule(module);
|
||||
};
|
||||
|
||||
// 环境标签点击
|
||||
const handleEnvironmentTagClick = (env: string) => {
|
||||
setSelectedEnvironment(env);
|
||||
};
|
||||
|
||||
// 显示JSON语法高亮
|
||||
const renderJsonWithSyntaxHighlight = (json: string) => {
|
||||
try {
|
||||
@@ -452,18 +350,18 @@ export default function ConfigNew() {
|
||||
{/* 配置名称和状态 */}
|
||||
<div className="form-row">
|
||||
<div className="form-group">
|
||||
<label htmlFor="configName" className="form-label required">配置名称</label>
|
||||
<label htmlFor="name" className="form-label required">配置名称</label>
|
||||
<input
|
||||
type="text"
|
||||
id="configName"
|
||||
name="configName"
|
||||
className={`form-input ${actionData?.errors?.configName ? 'input-error' : ''}`}
|
||||
defaultValue={config?.configName || ''}
|
||||
id="name"
|
||||
name="name"
|
||||
className={`form-input ${actionData?.errors?.name ? 'input-error' : ''}`}
|
||||
defaultValue={config?.name || ''}
|
||||
placeholder="请输入配置名称,如database_connection"
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.configName && (
|
||||
<div className="error-message">{actionData.errors.configName}</div>
|
||||
{actionData?.errors?.name && (
|
||||
<div className="error-message">{actionData.errors.name}</div>
|
||||
)}
|
||||
<div className="form-help">
|
||||
唯一标识符,配置名称应使用英文,推荐使用下划线命名方式
|
||||
@@ -471,18 +369,18 @@ export default function ConfigNew() {
|
||||
</div>
|
||||
|
||||
<div className="form-group">
|
||||
<label htmlFor="isActive" className="form-label">状态</label>
|
||||
<label htmlFor="is_active" className="form-label">状态</label>
|
||||
<div className="mt-2">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="isActive"
|
||||
name="isActive"
|
||||
id="is_active"
|
||||
name="is_active"
|
||||
value="true"
|
||||
className="form-checkbox"
|
||||
defaultChecked={config?.isActive !== false}
|
||||
defaultChecked={config?.is_active !== false}
|
||||
/>
|
||||
<label htmlFor="isActive" className="form-checkbox-label">
|
||||
<label htmlFor="is_active" className="form-checkbox-label">
|
||||
启用此配置
|
||||
</label>
|
||||
</div>
|
||||
@@ -495,33 +393,33 @@ export default function ConfigNew() {
|
||||
|
||||
{/* 所属模块 */}
|
||||
<div className="form-group">
|
||||
<label htmlFor="module" className="form-label required">所属模块</label>
|
||||
<label htmlFor="type" className="form-label required">所属模块</label>
|
||||
<input
|
||||
type="hidden"
|
||||
name="module"
|
||||
name="type"
|
||||
value={selectedModule}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
id="moduleDisplay"
|
||||
className={`form-input ${actionData?.errors?.module ? 'input-error' : ''}`}
|
||||
value={selectedModule ? MODULE_LABELS[selectedModule as ConfigModule] || selectedModule : ''}
|
||||
id="typeDisplay"
|
||||
className={`form-input ${actionData?.errors?.type ? 'input-error' : ''}`}
|
||||
value={selectedModule}
|
||||
onChange={(e) => setSelectedModule(e.target.value)}
|
||||
placeholder="请输入或选择所属模块"
|
||||
readOnly
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.module && (
|
||||
<div className="error-message">{actionData.errors.module}</div>
|
||||
{actionData?.errors?.type && (
|
||||
<div className="error-message">{actionData.errors.type}</div>
|
||||
)}
|
||||
<div className="tag-buttons mt-2">
|
||||
{Object.entries(MODULE_LABELS).map(([value, label]) => (
|
||||
{types.map(type => (
|
||||
<button
|
||||
key={value}
|
||||
key={type}
|
||||
type="button"
|
||||
className={`tag-button ${selectedModule === value ? 'active' : ''}`}
|
||||
onClick={() => handleModuleTagClick(value)}
|
||||
className={`tag-button ${selectedModule === type ? 'active' : ''}`}
|
||||
onClick={() => setSelectedModule(type)}
|
||||
>
|
||||
{label}
|
||||
{type}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -542,23 +440,23 @@ export default function ConfigNew() {
|
||||
type="text"
|
||||
id="environmentDisplay"
|
||||
className={`form-input ${actionData?.errors?.environment ? 'input-error' : ''}`}
|
||||
value={selectedEnvironment ? EXTENDED_ENVIRONMENT_LABELS[selectedEnvironment] || selectedEnvironment : ''}
|
||||
value={selectedEnvironment}
|
||||
onChange={(e) => setSelectedEnvironment(e.target.value)}
|
||||
placeholder="请输入或选择环境"
|
||||
readOnly
|
||||
required
|
||||
/>
|
||||
{actionData?.errors?.environment && (
|
||||
<div className="error-message">{actionData.errors.environment}</div>
|
||||
)}
|
||||
<div className="tag-buttons mt-2">
|
||||
{Object.entries(EXTENDED_ENVIRONMENT_LABELS).map(([value, label]) => (
|
||||
{environments.map(env => (
|
||||
<button
|
||||
key={value}
|
||||
key={env}
|
||||
type="button"
|
||||
className={`tag-button ${selectedEnvironment === value ? 'active' : ''}`}
|
||||
onClick={() => handleEnvironmentTagClick(value)}
|
||||
className={`tag-button ${selectedEnvironment === env ? 'active' : ''}`}
|
||||
onClick={() => setSelectedEnvironment(env)}
|
||||
>
|
||||
{label}
|
||||
{env}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -569,14 +467,14 @@ export default function ConfigNew() {
|
||||
|
||||
{/* 配置数据 */}
|
||||
<div className="form-group">
|
||||
<label htmlFor="configData" className="form-label required">配置数据 (JSON)</label>
|
||||
<label htmlFor="config" className="form-label required">配置数据 (JSON)</label>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4" style={{ minHeight: '390px' }}>
|
||||
{/* 左侧JSON编辑区 */}
|
||||
<div className="h-full">
|
||||
<textarea
|
||||
id="configData"
|
||||
name="configData"
|
||||
className={`json-editor ${(actionData?.errors?.configData || jsonError) ? 'input-error' : ''}`}
|
||||
id="config"
|
||||
name="config"
|
||||
className={`json-editor ${(actionData?.errors?.config || jsonError) ? 'input-error' : ''}`}
|
||||
value={configDataValue}
|
||||
onChange={handleConfigDataChange}
|
||||
required
|
||||
@@ -591,8 +489,8 @@ export default function ConfigNew() {
|
||||
<i className="ri-braces-line mr-1"></i> 格式化JSON
|
||||
</Button>
|
||||
</div>
|
||||
{(actionData?.errors?.configData || jsonError) && (
|
||||
<div className="error-message">{actionData?.errors?.configData || jsonError}</div>
|
||||
{(actionData?.errors?.config || jsonError) && (
|
||||
<div className="error-message">{actionData?.errors?.config || jsonError}</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -663,8 +561,6 @@ export default function ConfigNew() {
|
||||
<div className="error-message general-error">{actionData.errors.general}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
+538
-352
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
.file-upload-page .form-select {
|
||||
@apply block w-full px-3 py-2 text-base border-gray-300 rounded-md shadow-sm focus:outline-none;
|
||||
@apply block w-full px-3 py-2 text-base rounded-md shadow-sm focus:outline-none;
|
||||
}
|
||||
|
||||
.file-upload-page .form-select:focus {
|
||||
|
||||
@@ -1,108 +1,27 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"template_name": "行政处罚-抽取通用模板",
|
||||
"template_type": "Extraction",
|
||||
"description": "本模板用于抽取行政处罚决定书编号等信息",
|
||||
"template_content": "你是一个专业的文档信息抽取助手。请从以下{docType}文档中抽取关键信息:\n\n1. 处罚决定书编号\n2. 处罚对象名称\n3. 处罚事由\n4. 处罚依据\n5. 处罚内容\n6. 处罚金额\n7. 发文日期\n\n请将结果以JSON格式输出,包含以上字段。如果某个字段在文档中未找到,则该字段的值设为null。",
|
||||
"variables": {
|
||||
"docType": "文档类型"
|
||||
"id": 8,
|
||||
"user_id": null,
|
||||
"type_id": 1,
|
||||
"name": "4414260202410033-2024年度平烟第33号_20250227115714.pdf",
|
||||
"document_number": "HT-202504080TNWA",
|
||||
"path": "http://172.18.0.100:9000/docauditai/documents/%E5%90%88%E5%90%8C%E6%96%87%E6%A1%A3/2025/04%E6%9C%8808%E6%97%A5/4414260202410033-2024%E5%B9%B4%E5%BA%A6%E5%B9%B3%E7%83%9F%E7%AC%AC33%E5%8F%B7_20250227115714_11%E6%97%B637%E5%88%8650%E7%A7%92/4414260202410033-",
|
||||
"storage_type": "minio",
|
||||
"file_size": 47660228,
|
||||
"upload_time": "2025-04-08T03:37:44.332187",
|
||||
"is_test_document": true,
|
||||
"evaluation_level": "普通",
|
||||
"status": "completed",
|
||||
"ocr_result": {
|
||||
"现场笔录": "行政执法现场笔录\n\n案件编号:甬市监案字〔2023〕1234号\n检查时间:2023年5月15日10时30分\n检查地点:海曙区中山路45号\"优品商城\"3楼15号商铺\n\n当事人:张明华\n身份证号码:330225199001234567\n联系电话:13912345678\n\n执法人员:李晓东、陈明\n证件编号:浙执证字330225001号、浙执证字330225002号\n\n现场情况:\n执法人员对当事人经营场所进行检查,发现柜台内摆放有标注\"耐克\"商标的运动鞋若干。经初步判断,这些鞋子可能是假冒商品。\n\n查获物品:\n\"耐克\"品牌运动鞋35双,商品编号NK-20230515\n商品英文序列号:ABCDEF123456\n商品数量:35双\n货值金额:约人民币10500元\n\n有关合同信息:\n合同编号:YP-2023-0501\n合同金额:¥8750元\n\n当事人陈述:\n以上运动鞋是从广州一名叫王某的商贩处批发的,每双单价250元,不清楚是否为假冒商品。\n\n执法人员:李晓东(签名) 陈明(签名)\n当事人:张明华(手写签名)\n时间:2023年5月15日",
|
||||
"立案报告表": "行政执法机关立案报告表\n案件编号:甬市监案字〔2023〕1234号\n\n案件来源:群众举报\n\n当事人信息:\n姓名:张明华\n身份证号码:330225199001234567\n住址:浙江省宁波市海曙区文化路123号\n\n案由:销售假冒注册商标的商品\n\n案情摘要:\n2023年5月15日上午10时,根据群众举报,我局执法人员在位于海曙区中山路45号的\"优品商城\"内对当事人张明华经营的商铺进行检查,查获涉嫌假冒\"耐克\"注册商标的运动鞋35双,货值金额约人民币10500元。根据《中华人民共和国商标法》第六十七条规定,当事人的行为已构成销售假冒注册商标的商品的违法行为。\n\n案发时间:2023年5月15日\n案发地点:海曙区中山路45号\"优品商城\"\n\n承办部门意见:\n根据查明的事实和证据,建议对当事人依法立案调查。\n承办人:李晓东 2023年5月16日\n\n负责人意见:\n同意立案。\n负责人:王建国 2023年5月17日\n\n(盖章处)\n(骑缝章)",
|
||||
"案件处理审批表": "行政执法机关案件处理审批表\n案件编号:甬市监案字〔2023〕1234号\n\n案件来源:群众举报\n\n当事人信息:\n姓名:张明华\n身份证号码:330225199001234567\n住址:浙江省宁波市海曙区文化路123号\n\n案由:销售假冒注册商标的商品\n\n违法事实和证据:\n2023年5月15日,我局执法人员在当事人张明华经营的商铺内查获涉嫌假冒\"耐克\"注册商标的运动鞋35双,货值金额约人民币10500元。证据包括现场检查笔录、照片、扣押物品清单、商标权利人鉴定意见等。\n\n处罚依据:\n根据《中华人民共和国商标法》第六十七条规定,对当事人张明华处以没收违法商品和罚款人民币31500元的行政处罚。\n\n承办人意见:\n建议对当事人依法给予行政处罚。\n承办人:李晓东 2023年6月10日\n\n审核意见:\n同意承办人意见。\n审核人:陈志远 2023年6月12日\n\n审批意见:\n同意给予处罚。\n审批人:王建国 2023年6月15日\n\n(盖章处)",
|
||||
"案件调查终结报告": "行政执法机关案件调查终结报告\n案件编号:甬市监案字〔2023〕1234号\n\n案件来源:群众举报\n\n当事人信息:\n姓名:张明华\n身份证号码:330225199001234567\n住址:浙江省宁波市海曙区文化路123号\n\n案由:销售假冒注册商标的商品\n\n调查情况:\n2023年5月15日至6月5日,我局对当事人张明华涉嫌销售假冒注册商标的商品一案进行了调查。经查,当事人明知是假冒\"耐克\"注册商标的商品而销售,违反了《中华人民共和国商标法》的相关规定。\n\n主要证据:\n1. 现场检查笔录1份;\n2. 涉案物品照片8张;\n3. 扣押物品清单1份;\n4. 商标权利人鉴定意见1份;\n5. 当事人询问笔录2份。\n\n定性依据:\n根据《中华人民共和国商标法》第六十七条规定,当事人的行为构成销售假冒注册商标的商品的违法行为。\n\n处理建议:\n建议对当事人张明华处以没收违法商品和罚款人民币31500元的行政处罚。\n\n承办人:李晓东 陈明 \n2023年6月8日\n\n(盖章处)"
|
||||
},
|
||||
"status": 2,
|
||||
"version": "v1.0",
|
||||
"created_by": 1,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"template_name": "销售合同-甲方信息评估",
|
||||
"template_type": "Evaluation",
|
||||
"description": "评估销售合同中甲方信息是否完整",
|
||||
"template_content": "你是一个专业的合同审核助手。请评估以下{docType}中甲方信息的完整性:\n\n请检查以下要素是否存在且完整:\n1. 甲方全称\n2. 注册地址\n3. 统一社会信用代码\n4. 法定代表人\n5. 联系方式\n\n请给出评估结果,并标明缺失或不完整的信息。",
|
||||
"variables": {
|
||||
"docType": "文档类型"
|
||||
},
|
||||
"status": 1,
|
||||
"version": "v1.2",
|
||||
"created_by": 2,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"template_name": "专卖许可证-摘要模板",
|
||||
"template_type": "Summary",
|
||||
"description": "生成专卖许可证申请文件的内容摘要",
|
||||
"template_content": "你是一个专业的文档摘要助手。请为以下{docType}生成一份简洁的摘要:\n\n摘要应包含以下要点:\n1. 申请人基本信息\n2. 许可证类型\n3. 申请事项\n4. 经营范围\n5. 申请日期\n\n请控制摘要在200字以内,保留关键信息。",
|
||||
"variables": {
|
||||
"docType": "文档类型"
|
||||
},
|
||||
"status": 1,
|
||||
"version": "v1.0",
|
||||
"created_by": 2,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"template_name": "采购合同-乙方资质抽取",
|
||||
"template_type": "Extraction",
|
||||
"description": "抽取采购合同中乙方的资质信息",
|
||||
"template_content": "你是一个专业的合同信息抽取助手。请从以下{docType}中抽取乙方的资质信息:\n\n需要抽取的信息包括:\n1. 乙方全称\n2. 资质证书类型\n3. 资质证书编号\n4. 资质等级\n5. 证书有效期\n\n请将结果以JSON格式输出,包含以上字段。",
|
||||
"variables": {
|
||||
"docType": "文档类型"
|
||||
},
|
||||
"status": 0,
|
||||
"version": "v1.1",
|
||||
"created_by": 3,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"template_name": "合同通用-关键条款评估",
|
||||
"template_type": "Evaluation",
|
||||
"description": "评估合同中关键条款是否明确、合规",
|
||||
"template_content": "你是一个专业的{industry}行业合同审核助手。请评估以下合同中的关键条款是否明确、合规:\n\n请重点关注以下条款:\n1. 合同标的\n2. 价格条款\n3. 付款条件\n4. 交付方式\n5. 违约责任\n6. 争议解决\n\n请对每一项给出评估结果,并指出不明确或存在风险的条款。",
|
||||
"variables": {
|
||||
"docType": "文档类型",
|
||||
"industry": "行业类型"
|
||||
},
|
||||
"status": 1,
|
||||
"version": "v2.0",
|
||||
"created_by": 4,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"template_name": "LLM通用抽取Prompt",
|
||||
"template_type": "Extraction",
|
||||
"description": "",
|
||||
"template_content": "上面的文本为{{文档名称}}文档,请帮我结构化抽取下列信息:\n{{提取字段}}\n\n以 下面的json 结构输出抽取结果\n**输出格式**:\n - 以JSON格式输出结果:\n{\n \"{{文档名称}}\": {\n \"案件来源\": \"字段值\", \n \"案由\": \"字段值\"\n }\n}",
|
||||
"variables": {
|
||||
|
||||
},
|
||||
"status": 1,
|
||||
"version": "v2.0",
|
||||
"created_by": 4,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"template_name": "VLM通用抽取Prompt",
|
||||
"template_type": "Extraction",
|
||||
"description": null,
|
||||
"template_content": "上面的文本为{{文档名称}}文档,请帮我结构化抽取下列信息:\n{{提取字段}}\n\n以 下面的json 结构输出抽取结果\n**输出格式**:\n - 以JSON格式输出结果:\n{\n \"{{文档名称}}\": {\n \"案件来源\": \"字段值\", \n \"案由\": \"字段值\"\n }\n}",
|
||||
"variables": {
|
||||
|
||||
},
|
||||
"status": 1,
|
||||
"version": "v2.0",
|
||||
"created_by": 4,
|
||||
"created_at": "2025-03-26T01:23:58.549908",
|
||||
"updated_at": "2025-03-26T01:23:58.549908"
|
||||
"extracted_results": null,
|
||||
"sumary": null,
|
||||
"remark": "",
|
||||
"created_at": "2025-04-08T11:37:50.758998+00:00",
|
||||
"updated_at": "2025-04-08T11:37:50.758998+00:00"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user