创建评查点分组的API文件

This commit is contained in:
2025-04-07 00:46:31 +08:00
parent 145aec6aa6
commit 17f330d07d
9 changed files with 1310 additions and 638 deletions
+18 -9
View File
@@ -58,17 +58,26 @@ export class ApiError extends Error {
* 构建请求URL * 构建请求URL
*/ */
export function buildUrl(path: string, params?: Record<string, any>): string { export function buildUrl(path: string, params?: Record<string, any>): string {
const url = new URL(`${API_BASE_URL}${path}`); // 确保API_BASE_URL末尾没有斜杠,而path开头有斜杠
const baseUrl = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
if (params) { try {
Object.entries(params).forEach(([key, value]) => { const url = new URL(`${baseUrl}${normalizedPath}`);
if (value !== undefined && value !== null) {
url.searchParams.append(key, String(value)); if (params) {
} Object.entries(params).forEach(([key, value]) => {
}); if (value !== undefined && value !== null) {
url.searchParams.append(key, String(value));
}
});
}
return url.toString();
} catch (error) {
console.error('URL构建错误:', error);
throw new Error(`无法构建URL: ${baseUrl}${normalizedPath}, 错误: ${error}`);
} }
return url.toString();
} }
/** /**
+37 -14
View File
@@ -14,8 +14,9 @@ export type ApiResponse<T> = {
export type QueryParams = Record<string, string | number | boolean | undefined>; export type QueryParams = Record<string, string | number | boolean | undefined>;
// 获取 API 基础 URL // 获取 API 基础 URL
const API_BASE_URL = '172.18.0.100:3000'; // const API_BASE_URL = '172.18.0.100:3000';
// const API_BASE_URL = '172.16.0.119:9000/admin'; // const API_BASE_URL = '172.16.0.119:9000/admin';
const API_BASE_URL = 'http://nas.7bm.co:3000';
// 是否使用模拟数据(开发环境使用) // 是否使用模拟数据(开发环境使用)
const USE_MOCK_DATA = false; // 设置为true使用模拟数据,避免API连接问题 const USE_MOCK_DATA = false; // 设置为true使用模拟数据,避免API连接问题
@@ -24,22 +25,36 @@ const USE_MOCK_DATA = false; // 设置为true使用模拟数据,避免API连
* 构建完整的 API URL * 构建完整的 API URL
*/ */
function buildUrl(endpoint: string, params?: QueryParams): string { function buildUrl(endpoint: string, params?: QueryParams): string {
// 创建 URL 字符串 let fullUrl;
const url = new URL(
endpoint.startsWith('http') ? endpoint : `http://${API_BASE_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`,
typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3000'
);
// 添加查询参数 // 检查endpoint是否已经是完整URL
if (params) { if (endpoint.startsWith('http')) {
Object.entries(params).forEach(([key, value]) => { fullUrl = endpoint;
if (value !== undefined) { } else {
url.searchParams.append(key, String(value)); // 确保API_BASE_URL格式正确
} const baseUrl = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
}); const path = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
fullUrl = `${baseUrl}${path}`;
} }
return url.toString(); try {
// 创建URL对象
const url = new URL(fullUrl);
// 添加查询参数
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined) {
url.searchParams.append(key, String(value));
}
});
}
return url.toString();
} catch (error) {
console.error('URL构建错误:', fullUrl, error);
throw new Error(`无法构建URL: ${fullUrl}, 错误: ${error}`);
}
} }
// 超时控制 // 超时控制
@@ -48,6 +63,7 @@ const fetchWithTimeout = async (url: string, options: RequestInit, timeout = 500
const id = setTimeout(() => controller.abort(), timeout); const id = setTimeout(() => controller.abort(), timeout);
try { try {
console.log(`📦 API 端点: ${url}`);
const response = await fetch(url, { const response = await fetch(url, {
...options, ...options,
signal: controller.signal signal: controller.signal
@@ -56,6 +72,13 @@ const fetchWithTimeout = async (url: string, options: RequestInit, timeout = 500
return response; return response;
} catch (error) { } catch (error) {
clearTimeout(id); clearTimeout(id);
console.error(`📦 API请求失败: ${error}`);
// 检查是否是网络连接问题
if (error instanceof TypeError && error.message.includes('fetch failed')) {
console.error('网络连接错误,请检查API_BASE_URL配置是否正确');
}
throw error; throw error;
} }
}; };
+249
View File
@@ -0,0 +1,249 @@
import { postgrestGet, type PostgrestParams } from '../postgrest-client';
/**
* 评查点分组接口
*/
export interface RuleGroup {
id: string;
pid: string;
name: string;
status: boolean;
ruleCount?: number; // 评查点数量
children?: RuleGroup[]; // 子分组
}
/**
* 获取评查点分组列表
* @returns 评查点分组列表
*/
export async function getRuleGroups(): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取所有一级分组(pid=0)
const parentGroupsParams: PostgrestParams = {
select: `
id,
pid,
name,
status
`,
filter: {
'pid': 'eq.0'
}
};
const parentGroupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{
id: number;
pid: number;
name: string;
status: boolean;
}>}>('evaluation_point_groups', parentGroupsParams);
if (parentGroupsResponse.error) {
return { error: parentGroupsResponse.error, status: parentGroupsResponse.status };
}
// 处理响应数据
let parentGroups: RuleGroup[] = [];
if (parentGroupsResponse.data && 'code' in parentGroupsResponse.data && parentGroupsResponse.data.data) {
parentGroups = parentGroupsResponse.data.data.map(group => ({
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
children: [] // 初始化子分组数组
}));
} else if (Array.isArray(parentGroupsResponse.data)) {
parentGroups = parentGroupsResponse.data.map(group => ({
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
children: [] // 初始化子分组数组
}));
}
return { data: parentGroups };
} catch (error) {
console.error('获取评查点分组列表出错:', error);
return {
error: error instanceof Error ? error.message : '获取评查点分组列表失败',
status: 500
};
}
}
/**
* 获取指定分组的子分组
* @param parentId 父分组ID
* @returns 子分组列表
*/
export async function getChildGroups(parentId: string): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取子分组
const childGroupsParams: PostgrestParams = {
select: `
id,
pid,
name,
status
`,
filter: {
'pid': `eq.${parentId}`
}
};
const childGroupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{
id: number;
pid: number;
name: string;
status: boolean;
}>}>('evaluation_point_groups', childGroupsParams);
if (childGroupsResponse.error) {
return { error: childGroupsResponse.error, status: childGroupsResponse.status };
}
// 2. 获取每个子分组的评查点数量
let childGroups: RuleGroup[] = [];
if (childGroupsResponse.data && 'code' in childGroupsResponse.data && childGroupsResponse.data.data) {
childGroups = await Promise.all(childGroupsResponse.data.data.map(async group => {
// 获取该分组的评查点数量
const ruleCountParams: PostgrestParams = {
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${group.id}`
}
};
const ruleCountResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_points', ruleCountParams);
return {
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
ruleCount: ruleCountResponse.data && 'code' in ruleCountResponse.data
? ruleCountResponse.data.data?.length || 0
: Array.isArray(ruleCountResponse.data)
? ruleCountResponse.data.length
: 0
};
}));
} else if (Array.isArray(childGroupsResponse.data)) {
childGroups = await Promise.all(childGroupsResponse.data.map(async group => {
// 获取该分组的评查点数量
const ruleCountParams: PostgrestParams = {
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${group.id}`
}
};
const ruleCountResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_points', ruleCountParams);
return {
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
ruleCount: ruleCountResponse.data && 'code' in ruleCountResponse.data
? ruleCountResponse.data.data?.length || 0
: Array.isArray(ruleCountResponse.data)
? ruleCountResponse.data.length
: 0
};
}));
}
return { data: childGroups };
} catch (error) {
console.error('获取子分组列表出错:', error);
return {
error: error instanceof Error ? error.message : '获取子分组列表失败',
status: 500
};
}
}
/**
* 获取所有评查点分组(包括一级和二级)
* @returns 完整的评查点分组列表
*/
export async function getAllRuleGroups(): Promise<{data: RuleGroup[]; error?: never} | {data?: never; error: string; status?: number}> {
try {
// 1. 获取所有分组
const allGroupsParams: PostgrestParams = {
select: `
id,
pid,
name,
status
`
};
const allGroupsResponse = await postgrestGet<{code: number; msg: string; data: Array<{
id: number;
pid: number;
name: string;
status: boolean;
}>}>('evaluation_point_groups', allGroupsParams);
if (allGroupsResponse.error) {
return { error: allGroupsResponse.error, status: allGroupsResponse.status };
}
// 2. 处理响应数据
let allGroups: RuleGroup[] = [];
if (allGroupsResponse.data && 'code' in allGroupsResponse.data && allGroupsResponse.data.data) {
allGroups = allGroupsResponse.data.data.map(group => ({
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
children: []
}));
} else if (Array.isArray(allGroupsResponse.data)) {
allGroups = allGroupsResponse.data.map(group => ({
id: group.id.toString(),
pid: group.pid.toString(),
name: group.name,
status: group.status,
children: []
}));
}
// 3. 构建树形结构
const parentGroups = allGroups.filter(group => group.pid === '0');
// 4. 为每个父分组添加子分组
for (const parent of parentGroups) {
parent.children = allGroups.filter(group => group.pid === parent.id);
// 5. 获取每个子分组的评查点数量
for (const child of parent.children) {
const ruleCountParams: PostgrestParams = {
select: 'id',
filter: {
'evaluation_point_groups_id': `eq.${child.id}`
}
};
const ruleCountResponse = await postgrestGet<{code: number; msg: string; data: Array<{id: number}>}>('evaluation_points', ruleCountParams);
child.ruleCount = ruleCountResponse.data && 'code' in ruleCountResponse.data
? ruleCountResponse.data.data?.length || 0
: Array.isArray(ruleCountResponse.data)
? ruleCountResponse.data.length
: 0;
}
}
return { data: parentGroups };
} catch (error) {
console.error('获取所有评查点分组出错:', error);
return {
error: error instanceof Error ? error.message : '获取所有评查点分组失败',
status: 500
};
}
}
+8 -4
View File
@@ -25,10 +25,14 @@ export interface PostgrestParams {
function logPostgrestQuery(endpoint: string, params?: QueryParams): void { function logPostgrestQuery(endpoint: string, params?: QueryParams): void {
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
// const baseUrl = 'http://172.16.0.119:9000/admin'; // const baseUrl = 'http://172.16.0.119:9000/admin';
const baseUrl = 'http://172.18.0.100:3000'; // const baseUrl = 'http://172.18.0.100:3000';
const baseUrl = 'http://nas.7bm.co:3000';
// 确保 endpoint 格式正确
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint;
console.log('\n📦 PostgREST 查询日志 ========================'); console.log('\n📦 PostgREST 查询日志 ========================');
console.log(`📦 API 端点: ${baseUrl}/${endpoint}`); console.log(`📦 API 端点: ${baseUrl}/${normalizedEndpoint}`);
if (params && Object.keys(params).length > 0) { if (params && Object.keys(params).length > 0) {
console.log('📦 查询参数:'); console.log('📦 查询参数:');
@@ -67,7 +71,7 @@ function logPostgrestQuery(endpoint: string, params?: QueryParams): void {
}) })
.join('&'); .join('&');
console.log(`\n📦 可读URL: ${baseUrl}/${endpoint}${readableQueryString ? '?' + readableQueryString : ''}`); console.log(`\n📦 可读URL: ${baseUrl}/${normalizedEndpoint}${readableQueryString ? '?' + readableQueryString : ''}`);
// 格式化查询为 PostgreSQL 风格的查询 // 格式化查询为 PostgreSQL 风格的查询
let postgrestQuery = `SELECT `; let postgrestQuery = `SELECT `;
@@ -78,7 +82,7 @@ function logPostgrestQuery(endpoint: string, params?: QueryParams): void {
postgrestQuery += '*'; postgrestQuery += '*';
} }
postgrestQuery += ` FROM ${endpoint}`; postgrestQuery += ` FROM ${normalizedEndpoint}`;
const conditions: string[] = []; const conditions: string[] = [];
+5 -2
View File
@@ -8,6 +8,7 @@ interface StatusDotProps {
className?: string; className?: string;
size?: 'default' | 'sm' | 'lg'; size?: 'default' | 'sm' | 'lg';
pulse?: boolean; pulse?: boolean;
align?: 'left' | 'center' | 'right';
} }
export function StatusDot({ export function StatusDot({
@@ -15,7 +16,8 @@ export function StatusDot({
text, text,
className = '', className = '',
size = 'default', size = 'default',
pulse = false pulse = false,
align = 'left'
}: StatusDotProps) { }: StatusDotProps) {
// 如果status是布尔值,则转换为对应的状态类型 // 如果status是布尔值,则转换为对应的状态类型
const statusType = typeof status === 'boolean' const statusType = typeof status === 'boolean'
@@ -32,9 +34,10 @@ export function StatusDot({
const sizeClass = size !== 'default' ? `status-dot-${size}` : ''; const sizeClass = size !== 'default' ? `status-dot-${size}` : '';
const pulseClass = pulse ? 'status-dot-pulse' : ''; const pulseClass = pulse ? 'status-dot-pulse' : '';
const alignClass = align === 'center' ? 'justify-center' : align === 'right' ? 'justify-end' : 'justify-start';
return ( return (
<span className={`status-dot-with-text ${className}`}> <span className={`status-dot-with-text ${alignClass} ${className}`}>
<span className={`status-dot status-dot-${statusType} ${sizeClass} ${pulseClass}`}></span> <span className={`status-dot status-dot-${statusType} ${sizeClass} ${pulseClass}`}></span>
<span className="status-dot-text">{statusText}</span> <span className="status-dot-text">{statusText}</span>
</span> </span>
+79 -102
View File
@@ -1,6 +1,6 @@
import { json, type MetaFunction } from "@remix-run/node"; import { json, type MetaFunction } from "@remix-run/node";
import { useLoaderData, Link, useNavigate, useSearchParams } from "@remix-run/react"; import { useLoaderData, Link, useNavigate, useSearchParams } from "@remix-run/react";
import { useState } from "react"; import { useState, useEffect } from "react";
import indexStyles from "~/styles/pages/rule-groups_index.css?url"; import indexStyles from "~/styles/pages/rule-groups_index.css?url";
import { Card } from "~/components/ui/Card"; import { Card } from "~/components/ui/Card";
import { Button } from "~/components/ui/Button"; import { Button } from "~/components/ui/Button";
@@ -8,23 +8,12 @@ import { StatusDot } from "~/components/ui/StatusDot";
import { Table } from "~/components/ui/Table"; import { Table } from "~/components/ui/Table";
import { FilterPanel, FilterSelect, SearchFilter } from "~/components/ui/FilterPanel"; import { FilterPanel, FilterSelect, SearchFilter } from "~/components/ui/FilterPanel";
import { Pagination } from "~/components/ui/Pagination"; import { Pagination } from "~/components/ui/Pagination";
import { getRuleGroups, getChildGroups, type RuleGroup } from "~/api/evaluation_points/rule-groups";
export function links() { export function links() {
return [{ rel: "stylesheet", href: indexStyles }]; return [{ rel: "stylesheet", href: indexStyles }];
} }
// 定义数据类型
interface RuleGroup {
id: string;
name: string;
code: string;
ruleCount: number;
subGroupCount: number;
status: 'active' | 'inactive';
createdAt: string;
children?: RuleGroup[];
}
export const meta: MetaFunction = () => { export const meta: MetaFunction = () => {
return [ return [
{ title: "评查点分组 - 中国烟草AI合同及卷宗审核系统" }, { title: "评查点分组 - 中国烟草AI合同及卷宗审核系统" },
@@ -32,98 +21,85 @@ export const meta: MetaFunction = () => {
]; ];
}; };
// 模拟数据
const MOCK_GROUPS: RuleGroup[] = [
{
id: "1",
name: "合同基本要素检查",
code: "contract-base",
ruleCount: 18,
subGroupCount: 12,
status: "active",
createdAt: "2023-10-01 14:30",
children: [
{
id: "2",
name: "必备要素检查",
code: "essential-elements",
ruleCount: 7,
subGroupCount: 0,
status: "active",
createdAt: "2023-10-02 10:15",
},
{
id: "3",
name: "合同主体检查",
code: "contract-parties",
ruleCount: 5,
subGroupCount: 0,
status: "active",
createdAt: "2023-10-03 16:20",
}
]
},
{
id: "4",
name: "销售合同专项检查",
code: "contract-sales",
ruleCount: 12,
subGroupCount: 5,
status: "active",
createdAt: "2023-10-05 09:30",
children: [
{
id: "6",
name: "付款条件检查",
code: "payment-terms",
ruleCount: 5,
subGroupCount: 0,
status: "active",
createdAt: "2023-10-05 14:45",
}
]
},
{
id: "5",
name: "行政处罚规范性检查",
code: "punishment",
ruleCount: 8,
subGroupCount: 0,
status: "inactive",
createdAt: "2023-10-08 11:45",
}
];
export async function loader() { export async function loader() {
return json({ groups: MOCK_GROUPS }); try {
const response = await getRuleGroups();
if (response.error) {
throw new Error(response.error);
}
return json({ groups: response.data });
} catch (error) {
console.error('加载评查点分组失败:', error);
return json({ groups: [] });
}
} }
export default function RuleGroupsIndex() { export default function RuleGroupsIndex() {
const { groups } = useLoaderData<typeof loader>(); const { groups: initialGroups } = useLoaderData<typeof loader>();
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const [expandedGroups, setExpandedGroups] = useState<string[]>([]); const [expandedGroups, setExpandedGroups] = useState<string[]>([]);
const [groups, setGroups] = useState<RuleGroup[]>(initialGroups);
const [loading, setLoading] = useState<Record<string, boolean>>({});
// 处理展开/收起 // 处理展开/收起
const toggleGroup = (groupId: string) => { const toggleGroup = async (groupId: string) => {
setExpandedGroups(prev => if (expandedGroups.includes(groupId)) {
prev.includes(groupId) // 收起分组
? prev.filter(id => id !== groupId) setExpandedGroups(prev => prev.filter(id => id !== groupId));
: [...prev, groupId] return;
); }
// 展开分组
setLoading(prev => ({ ...prev, [groupId]: true }));
try {
const response = await getChildGroups(groupId);
if (response.error) {
throw new Error(response.error);
}
// 更新分组数据
setGroups(prev => prev.map(group => {
if (group.id === groupId) {
return {
...group,
children: response.data
};
}
return group;
}));
setExpandedGroups(prev => [...prev, groupId]);
} catch (error) {
console.error('加载子分组失败:', error);
} finally {
setLoading(prev => ({ ...prev, [groupId]: false }));
}
}; };
// 展开/收起全部 // 展开/收起全部
const toggleAll = (expand: boolean) => { const toggleAll = async (expand: boolean) => {
setExpandedGroups(expand ? groups.map(g => g.id) : []); if (expand) {
// 展开所有分组
const expandedIds = groups.map(g => g.id);
setExpandedGroups(expandedIds);
// 加载所有子分组
for (const group of groups) {
if (!group.children || group.children.length === 0) {
await toggleGroup(group.id);
}
}
} else {
setExpandedGroups([]);
}
}; };
// 处理删除分组 // 处理删除分组
const handleDeleteGroup = (groupId: string) => { const handleDeleteGroup = (groupId: string) => {
if (confirm("确定要删除该分组吗?此操作将同时删除该分组下的所有评查点,且不可恢复。")) { if (confirm("确定要删除该分组吗?此操作将同时删除该分组下的所有评查点,且不可恢复。")) {
console.log('删除分组ID:', groupId); console.log('删除分组ID:', groupId);
// 实际应用中,这里会调用API删除数据 // TODO: 实现删除分组的API调用
} }
}; };
@@ -192,7 +168,7 @@ export default function RuleGroupsIndex() {
title: "分组名称", title: "分组名称",
key: "name", key: "name",
width: "400px", width: "400px",
render: (_: unknown, record: (RuleGroup & { isParent?: boolean, parentId?: string })) => ( render: (_: unknown, record: RuleGroup & { isParent?: boolean, parentId?: string }) => (
<div className={`flex items-center ${!record.isParent ? 'ml-8' : ''}`}> <div className={`flex items-center ${!record.isParent ? 'ml-8' : ''}`}>
{record.isParent && ( {record.isParent && (
<span <span
@@ -207,7 +183,11 @@ export default function RuleGroupsIndex() {
} }
}} }}
> >
<i className={`ri-arrow-${expandedGroups.includes(record.id) ? 'down' : 'right'}-s-line`}></i> {loading[record.id] ? (
<i className="ri-loader-4-line animate-spin"></i>
) : (
<i className={`ri-arrow-${expandedGroups.includes(record.id) ? 'down' : 'right'}-s-line`}></i>
)}
</span> </span>
)} )}
<Link <Link
@@ -231,23 +211,20 @@ export default function RuleGroupsIndex() {
title: "评查点数量", title: "评查点数量",
key: "ruleCount", key: "ruleCount",
render: (_: unknown, record: RuleGroup) => ( render: (_: unknown, record: RuleGroup) => (
<> <Link to={`/rule-groups/${record.id}/rules`} className="badge bg-primary text-white">
<Link to={`/rule-groups/${record.id}/rules`} className="badge bg-primary text-white"> {record.ruleCount || 0}
{record.ruleCount} </Link>
</Link>
{record.subGroupCount > 0 && (
<span className="text-secondary text-sm ml-1">
| : {record.subGroupCount}
</span>
)}
</>
) )
}, },
{ {
title: "状态", title: "状态",
key: "status", key: "status",
render: (_: unknown, record: RuleGroup) => ( render: (_: unknown, record: RuleGroup) => (
<StatusDot status={record.status === 'active' ? 'success' : 'error'} text={record.status === 'active' ? '启用' : '禁用'} /> <StatusDot
status={record.status ? 'success' : 'error'}
text={record.status ? '启用' : '禁用'}
align="left"
/>
) )
}, },
{ {
@@ -349,8 +326,8 @@ export default function RuleGroupsIndex() {
name="status" name="status"
value={searchParams.get('status') || ''} value={searchParams.get('status') || ''}
options={[ options={[
{ value: "active", label: "启用" }, { value: "true", label: "启用" },
{ value: "inactive", label: "禁用" } { value: "false", label: "禁用" }
]} ]}
onChange={handleStatusChange} onChange={handleStatusChange}
className="flex-1 min-w-[200px]" className="flex-1 min-w-[200px]"
-1
View File
@@ -430,7 +430,6 @@ export default function RulesIndex() {
key: "isActive", key: "isActive",
align: "left" as const, align: "left" as const,
width: "8%", width: "8%",
className: "status-column",
render: (_: unknown, record: Rule) => ( render: (_: unknown, record: Rule) => (
<StatusDot status={record.isActive} text={record.isActive ? "启用" : "禁用"} /> <StatusDot status={record.isActive} text={record.isActive ? "启用" : "禁用"} />
) )
+913 -506
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -28,6 +28,7 @@
"@typescript-eslint/eslint-plugin": "^6.7.4", "@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4", "@typescript-eslint/parser": "^6.7.4",
"autoprefixer": "^10.4.21", "autoprefixer": "^10.4.21",
"esbuild": "^0.25.1",
"eslint": "^8.38.0", "eslint": "^8.38.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1", "eslint-plugin-import": "^2.28.1",