Jelajahi Sumber

新增知识库相关接口定义,优化知识库API逻辑,提供获取、创建、更新和删除知识的功能。同时,更新页面组件以支持知识库管理,提升代码可维护性和用户体验。

zyh 8 bulan lalu
induk
melakukan
602317ea44

+ 90 - 1
client/admin/api.ts

@@ -6,7 +6,7 @@ import type {
   User, FileLibrary, FileCategory, ThemeSettings,
  SystemSetting, SystemSettingGroupData, 
  LoginLocation, LoginLocationDetail,
- Message, UserMessage
+ Message, UserMessage, KnowInfo
 } from '../share/types.ts';
 
 
@@ -605,6 +605,37 @@ export interface LoginLocationUpdateResponse {
   data: LoginLocationDetail;
 }
 
+// 知识库相关接口类型定义
+interface KnowInfoListResponse {
+  data: KnowInfo[];
+  pagination: {
+    total: number;
+    current: number;
+    pageSize: number;
+    totalPages: number;
+  };
+}
+
+interface KnowInfoResponse {
+  data: KnowInfo;
+  message?: string;
+}
+
+interface KnowInfoCreateResponse {
+  message: string;
+  data: KnowInfo;
+}
+
+interface KnowInfoUpdateResponse {
+  message: string;
+  data: KnowInfo;
+}
+
+interface KnowInfoDeleteResponse {
+  message: string;
+  id: number;
+}
+
 
 // 地图相关API
 export const MapAPI = {
@@ -648,6 +679,64 @@ export const MapAPI = {
 };
 
 // 系统设置API
+// 知识库API
+export const KnowInfoAPI = {
+  // 获取知识库列表
+  getKnowInfos: async (params?: {
+    page?: number;
+    pageSize?: number;
+    search?: string;
+    categoryId?: number;
+  }): Promise<KnowInfoListResponse> => {
+    try {
+      const response = await axios.get(`${API_BASE_URL}/know-infos`, { params });
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 获取单个知识详情
+  getKnowInfo: async (id: number): Promise<KnowInfoResponse> => {
+    try {
+      const response = await axios.get(`${API_BASE_URL}/know-infos/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 创建知识
+  createKnowInfo: async (data: Partial<KnowInfo>): Promise<KnowInfoCreateResponse> => {
+    try {
+      const response = await axios.post(`${API_BASE_URL}/know-infos`, data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 更新知识
+  updateKnowInfo: async (id: number, data: Partial<KnowInfo>): Promise<KnowInfoUpdateResponse> => {
+    try {
+      const response = await axios.put(`${API_BASE_URL}/know-infos/${id}`, data);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  },
+
+  // 删除知识
+  deleteKnowInfo: async (id: number): Promise<KnowInfoDeleteResponse> => {
+    try {
+      const response = await axios.delete(`${API_BASE_URL}/know-infos/${id}`);
+      return response.data;
+    } catch (error) {
+      throw error;
+    }
+  }
+};
+
 export const SystemAPI = {
   // 获取所有系统设置
   getSettings: async (): Promise<SystemSettingGroupData[]> => {

+ 440 - 0
client/admin/pages_know.tsx

@@ -0,0 +1,440 @@
+import React, { useState, useEffect } from 'react';
+import { 
+  Layout, Menu, Button, Table, Space,
+  Form, Input, Select, message, Modal,
+  Card, Spin, Row, Col, Breadcrumb, Avatar,
+  Dropdown, ConfigProvider, theme, Typography,
+  Switch, Badge, Image, Upload, Divider, Descriptions,
+  Popconfirm, Tag, Statistic, DatePicker, Radio, Progress, Tabs, List, Alert, Collapse, Empty, Drawer
+} from 'antd';
+import {
+  UploadOutlined,
+  FileImageOutlined,
+  FileExcelOutlined,
+  FileWordOutlined,
+  FilePdfOutlined,
+  FileOutlined,
+} from '@ant-design/icons';   
+import { 
+  useQuery,
+} from '@tanstack/react-query';
+import dayjs from 'dayjs';
+import weekday from 'dayjs/plugin/weekday';
+import localeData from 'dayjs/plugin/localeData';
+import 'dayjs/locale/zh-cn';
+import type { 
+  FileLibrary, FileCategory, KnowInfo
+} from '../share/types.ts';
+
+import {
+   AuditStatus,AuditStatusNameMap,
+   OssType,
+} from '../share/types.ts';
+
+import { getEnumOptions } from './utils.ts';
+
+import {
+  FileAPI,
+  UserAPI,
+} from './api.ts';
+
+
+// 配置 dayjs 插件
+dayjs.extend(weekday);
+dayjs.extend(localeData);
+
+// 设置 dayjs 语言
+dayjs.locale('zh-cn');
+
+const { Title } = Typography;
+
+
+// 知识库管理页面组件
+export const KnowInfoPage = () => {
+  const [modalVisible, setModalVisible] = useState(false);
+  const [formMode, setFormMode] = useState<'create' | 'edit'>('create');
+  const [editingId, setEditingId] = useState<number | null>(null);
+  const [form] = Form.useForm();
+  const [isLoading, setIsLoading] = useState(false);
+  const [searchParams, setSearchParams] = useState({
+    title: '',
+    category: '',
+    page: 1,
+    limit: 10,
+  });
+  
+  // 使用React Query获取知识库文章列表
+  const { data: articlesData, isLoading: isListLoading, refetch } = useQuery({
+    queryKey: ['articles', searchParams],
+    queryFn: async () => {
+      const { title, category, page, limit } = searchParams;
+      const params = new URLSearchParams();
+      
+      if (title) params.append('title', title);
+      if (category) params.append('category', category);
+      params.append('page', String(page));
+      params.append('limit', String(limit));
+      
+      const response = await fetch(`/api/know-info?${params.toString()}`, {
+        headers: {
+          'Authorization': `Bearer ${localStorage.getItem('token')}`,
+        },
+      });
+      
+      if (!response.ok) {
+        throw new Error('获取知识库文章列表失败');
+      }
+      
+      return await response.json();
+    }
+  });
+  
+  const articles = articlesData?.data || [];
+  const pagination = articlesData?.pagination || { current: 1, pageSize: 10, total: 0 };
+  
+  // 获取单个知识库文章
+  const fetchArticle = async (id: number) => {
+    try {
+      const response = await fetch(`/api/know-info/${id}`, {
+        headers: {
+          'Authorization': `Bearer ${localStorage.getItem('token')}`,
+        },
+      });
+      
+      if (!response.ok) {
+        throw new Error('获取知识库文章详情失败');
+      }
+      
+      return await response.json();
+    } catch (error) {
+      message.error('获取知识库文章详情失败');
+      return null;
+    }
+  };
+  
+  // 处理表单提交
+  const handleSubmit = async (values: Partial<KnowInfo>) => {
+    setIsLoading(true);
+    
+    try {
+      const url = formMode === 'create'
+        ? '/api/know-info'
+        : `/api/know-info/${editingId}`;
+      
+      const method = formMode === 'create' ? 'POST' : 'PUT';
+      
+      const response = await fetch(url, {
+        method,
+        headers: {
+          'Content-Type': 'application/json',
+          'Authorization': `Bearer ${localStorage.getItem('token')}`,
+        },
+        body: JSON.stringify(values),
+      });
+      
+      if (!response.ok) {
+        throw new Error(formMode === 'create' ? '创建知识库文章失败' : '更新知识库文章失败');
+      }
+      
+      message.success(formMode === 'create' ? '创建知识库文章成功' : '更新知识库文章成功');
+      setModalVisible(false);
+      form.resetFields();
+      refetch();
+    } catch (error) {
+      message.error((error as Error).message);
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  
+  // 处理编辑
+  const handleEdit = async (id: number) => {
+    const article = await fetchArticle(id);
+    
+    if (article) {
+      setFormMode('edit');
+      setEditingId(id);
+      form.setFieldsValue(article);
+      setModalVisible(true);
+    }
+  };
+  
+  // 处理删除
+  const handleDelete = async (id: number) => {
+    try {
+      const response = await fetch(`/api/know-info/${id}`, {
+        method: 'DELETE',
+        headers: {
+          'Authorization': `Bearer ${localStorage.getItem('token')}`,
+        },
+      });
+      
+      if (!response.ok) {
+        throw new Error('删除知识库文章失败');
+      }
+      
+      message.success('删除知识库文章成功');
+      refetch();
+    } catch (error) {
+      message.error((error as Error).message);
+    }
+  };
+  
+  // 处理搜索
+  const handleSearch = (values: any) => {
+    setSearchParams(prev => ({
+      ...prev,
+      title: values.title || '',
+      category: values.category || '',
+      page: 1,
+    }));
+  };
+  
+  // 处理分页
+  const handlePageChange = (page: number, pageSize?: number) => {
+    setSearchParams(prev => ({
+      ...prev,
+      page,
+      limit: pageSize || prev.limit,
+    }));
+  };
+  
+  // 处理添加
+  const handleAdd = () => {
+    setFormMode('create');
+    setEditingId(null);
+    form.resetFields();
+    setModalVisible(true);
+  };
+  
+  // 审核状态映射
+  const auditStatusOptions = getEnumOptions(AuditStatus, AuditStatusNameMap);
+  
+  // 表格列定义
+  const columns = [
+    {
+      title: 'ID',
+      dataIndex: 'id',
+      key: 'id',
+      width: 80,
+    },
+    {
+      title: '标题',
+      dataIndex: 'title',
+      key: 'title',
+    },
+    {
+      title: '分类',
+      dataIndex: 'category',
+      key: 'category',
+    },
+    {
+      title: '标签',
+      dataIndex: 'tags',
+      key: 'tags',
+      render: (tags: string) => tags ? tags.split(',').map(tag => (
+        <Tag key={tag}>{tag}</Tag>
+      )) : null,
+    },
+    {
+      title: '作者',
+      dataIndex: 'author',
+      key: 'author',
+    },
+    {
+      title: '审核状态',
+      dataIndex: 'audit_status',
+      key: 'audit_status',
+      render: (status: AuditStatus) => {
+        let color = '';
+        let text = '';
+        
+        switch(status) {
+          case AuditStatus.PENDING:
+            color = 'orange';
+            text = '待审核';
+            break;
+          case AuditStatus.APPROVED:
+            color = 'green';
+            text = '已通过';
+            break;
+          case AuditStatus.REJECTED:
+            color = 'red';
+            text = '已拒绝';
+            break;
+          default:
+            color = 'default';
+            text = '未知';
+        }
+        
+        return <Tag color={color}>{text}</Tag>;
+      },
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'created_at',
+      key: 'created_at',
+      render: (date: string) => new Date(date).toLocaleString(),
+    },
+    {
+      title: '操作',
+      key: 'action',
+      render: (_: any, record: KnowInfo) => (
+        <Space size="middle">
+          <Button type="link" onClick={() => handleEdit(record.id)}>编辑</Button>
+          <Popconfirm
+            title="确定要删除这篇文章吗?"
+            onConfirm={() => handleDelete(record.id)}
+            okText="确定"
+            cancelText="取消"
+          >
+            <Button type="link" danger>删除</Button>
+          </Popconfirm>
+        </Space>
+      ),
+    },
+  ];
+  
+  return (
+    <div>
+      <Card title="知识库管理" className="mb-4">
+        <Form
+          layout="inline"
+          onFinish={handleSearch}
+          style={{ marginBottom: '16px' }}
+        >
+          <Form.Item name="title" label="标题">
+            <Input placeholder="请输入文章标题" />
+          </Form.Item>
+          
+          <Form.Item name="category" label="分类">
+            <Input placeholder="请输入文章分类" />
+          </Form.Item>
+          
+          <Form.Item>
+            <Space>
+              <Button type="primary" htmlType="submit">
+                搜索
+              </Button>
+              <Button onClick={() => {
+                setSearchParams({
+                  title: '',
+                  category: '',
+                  page: 1,
+                  limit: 10,
+                });
+              }}>
+                重置
+              </Button>
+              <Button type="primary" onClick={handleAdd}>
+                添加文章
+              </Button>
+            </Space>
+          </Form.Item>
+        </Form>
+        
+        <Table
+          columns={columns}
+          dataSource={articles}
+          rowKey="id"
+          loading={isListLoading}
+          pagination={{
+            current: pagination.current,
+            pageSize: pagination.pageSize,
+            total: pagination.total,
+            onChange: handlePageChange,
+            showSizeChanger: true,
+          }}
+        />
+      </Card>
+      
+      <Modal
+        title={formMode === 'create' ? '添加知识库文章' : '编辑知识库文章'}
+        open={modalVisible}
+        onOk={() => form.submit()}
+        onCancel={() => setModalVisible(false)}
+        width={800}
+      >
+        <Form
+          form={form}
+          layout="vertical"
+          onFinish={handleSubmit}
+          initialValues={{
+            audit_status: AuditStatus.PENDING,
+          }}
+        >
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item
+                name="title"
+                label="文章标题"
+                rules={[{ required: true, message: '请输入文章标题' }]}
+              >
+                <Input placeholder="请输入文章标题" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item
+                name="category"
+                label="文章分类"
+              >
+                <Input placeholder="请输入文章分类" />
+              </Form.Item>
+            </Col>
+          </Row>
+          
+          <Form.Item
+            name="tags"
+            label="文章标签"
+            help="多个标签请用英文逗号分隔,如: 服务器,网络,故障"
+          >
+            <Input placeholder="请输入文章标签,多个标签请用英文逗号分隔" />
+          </Form.Item>
+          
+          <Form.Item
+            name="content"
+            label="文章内容"
+            rules={[{ required: true, message: '请输入文章内容' }]}
+          >
+            <Input.TextArea rows={15} placeholder="请输入文章内容,支持Markdown格式" />
+          </Form.Item>
+          
+          <Row gutter={16}>
+            <Col span={12}>
+              <Form.Item
+                name="author"
+                label="文章作者"
+              >
+                <Input placeholder="请输入文章作者" />
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item
+                name="cover_url"
+                label="封面图片URL"
+              >
+                <Input placeholder="请输入封面图片URL" />
+              </Form.Item>
+            </Col>
+          </Row>
+          
+          <Form.Item
+            name="audit_status"
+            label="审核状态"
+          >
+            <Select options={auditStatusOptions} />
+          </Form.Item>
+          
+          <Form.Item>
+            <Space>
+              <Button type="primary" htmlType="submit" loading={isLoading}>
+                {formMode === 'create' ? '创建' : '保存'}
+              </Button>
+              <Button onClick={() => setModalVisible(false)}>取消</Button>
+            </Space>
+          </Form.Item>
+        </Form>
+      </Modal>
+    </div>
+  );
+};

+ 0 - 390
client/admin/pages_sys.tsx

@@ -349,396 +349,6 @@ export const UsersPage = () => {
   );
 };
 
-// 知识库管理页面组件
-export const KnowInfoPage = () => {
-  const [modalVisible, setModalVisible] = useState(false);
-  const [formMode, setFormMode] = useState<'create' | 'edit'>('create');
-  const [editingId, setEditingId] = useState<number | null>(null);
-  const [form] = Form.useForm();
-  const [isLoading, setIsLoading] = useState(false);
-  const [searchParams, setSearchParams] = useState({
-    title: '',
-    category: '',
-    page: 1,
-    limit: 10,
-  });
-  
-  // 使用React Query获取知识库文章列表
-  const { data: articlesData, isLoading: isListLoading, refetch } = useQuery({
-    queryKey: ['articles', searchParams],
-    queryFn: async () => {
-      const { title, category, page, limit } = searchParams;
-      const params = new URLSearchParams();
-      
-      if (title) params.append('title', title);
-      if (category) params.append('category', category);
-      params.append('page', String(page));
-      params.append('limit', String(limit));
-      
-      const response = await fetch(`/api/know-info?${params.toString()}`, {
-        headers: {
-          'Authorization': `Bearer ${localStorage.getItem('token')}`,
-        },
-      });
-      
-      if (!response.ok) {
-        throw new Error('获取知识库文章列表失败');
-      }
-      
-      return await response.json();
-    }
-  });
-  
-  const articles = articlesData?.data || [];
-  const pagination = articlesData?.pagination || { current: 1, pageSize: 10, total: 0 };
-  
-  // 获取单个知识库文章
-  const fetchArticle = async (id: number) => {
-    try {
-      const response = await fetch(`/api/know-info/${id}`, {
-        headers: {
-          'Authorization': `Bearer ${localStorage.getItem('token')}`,
-        },
-      });
-      
-      if (!response.ok) {
-        throw new Error('获取知识库文章详情失败');
-      }
-      
-      return await response.json();
-    } catch (error) {
-      message.error('获取知识库文章详情失败');
-      return null;
-    }
-  };
-  
-  // 处理表单提交
-  const handleSubmit = async (values: Partial<KnowInfo>) => {
-    setIsLoading(true);
-    
-    try {
-      const url = formMode === 'create'
-        ? '/api/know-info'
-        : `/api/know-info/${editingId}`;
-      
-      const method = formMode === 'create' ? 'POST' : 'PUT';
-      
-      const response = await fetch(url, {
-        method,
-        headers: {
-          'Content-Type': 'application/json',
-          'Authorization': `Bearer ${localStorage.getItem('token')}`,
-        },
-        body: JSON.stringify(values),
-      });
-      
-      if (!response.ok) {
-        throw new Error(formMode === 'create' ? '创建知识库文章失败' : '更新知识库文章失败');
-      }
-      
-      message.success(formMode === 'create' ? '创建知识库文章成功' : '更新知识库文章成功');
-      setModalVisible(false);
-      form.resetFields();
-      refetch();
-    } catch (error) {
-      message.error((error as Error).message);
-    } finally {
-      setIsLoading(false);
-    }
-  };
-  
-  // 处理编辑
-  const handleEdit = async (id: number) => {
-    const article = await fetchArticle(id);
-    
-    if (article) {
-      setFormMode('edit');
-      setEditingId(id);
-      form.setFieldsValue(article);
-      setModalVisible(true);
-    }
-  };
-  
-  // 处理删除
-  const handleDelete = async (id: number) => {
-    try {
-      const response = await fetch(`/api/know-info/${id}`, {
-        method: 'DELETE',
-        headers: {
-          'Authorization': `Bearer ${localStorage.getItem('token')}`,
-        },
-      });
-      
-      if (!response.ok) {
-        throw new Error('删除知识库文章失败');
-      }
-      
-      message.success('删除知识库文章成功');
-      refetch();
-    } catch (error) {
-      message.error((error as Error).message);
-    }
-  };
-  
-  // 处理搜索
-  const handleSearch = (values: any) => {
-    setSearchParams(prev => ({
-      ...prev,
-      title: values.title || '',
-      category: values.category || '',
-      page: 1,
-    }));
-  };
-  
-  // 处理分页
-  const handlePageChange = (page: number, pageSize?: number) => {
-    setSearchParams(prev => ({
-      ...prev,
-      page,
-      limit: pageSize || prev.limit,
-    }));
-  };
-  
-  // 处理添加
-  const handleAdd = () => {
-    setFormMode('create');
-    setEditingId(null);
-    form.resetFields();
-    setModalVisible(true);
-  };
-  
-  // 审核状态映射
-  const auditStatusOptions = getEnumOptions(AuditStatus, AuditStatusNameMap);
-  
-  // 表格列定义
-  const columns = [
-    {
-      title: 'ID',
-      dataIndex: 'id',
-      key: 'id',
-      width: 80,
-    },
-    {
-      title: '标题',
-      dataIndex: 'title',
-      key: 'title',
-    },
-    {
-      title: '分类',
-      dataIndex: 'category',
-      key: 'category',
-    },
-    {
-      title: '标签',
-      dataIndex: 'tags',
-      key: 'tags',
-      render: (tags: string) => tags ? tags.split(',').map(tag => (
-        <Tag key={tag}>{tag}</Tag>
-      )) : null,
-    },
-    {
-      title: '作者',
-      dataIndex: 'author',
-      key: 'author',
-    },
-    {
-      title: '审核状态',
-      dataIndex: 'audit_status',
-      key: 'audit_status',
-      render: (status: AuditStatus) => {
-        let color = '';
-        let text = '';
-        
-        switch(status) {
-          case AuditStatus.PENDING:
-            color = 'orange';
-            text = '待审核';
-            break;
-          case AuditStatus.APPROVED:
-            color = 'green';
-            text = '已通过';
-            break;
-          case AuditStatus.REJECTED:
-            color = 'red';
-            text = '已拒绝';
-            break;
-          default:
-            color = 'default';
-            text = '未知';
-        }
-        
-        return <Tag color={color}>{text}</Tag>;
-      },
-    },
-    {
-      title: '创建时间',
-      dataIndex: 'created_at',
-      key: 'created_at',
-      render: (date: string) => new Date(date).toLocaleString(),
-    },
-    {
-      title: '操作',
-      key: 'action',
-      render: (_: any, record: KnowInfo) => (
-        <Space size="middle">
-          <Button type="link" onClick={() => handleEdit(record.id)}>编辑</Button>
-          <Popconfirm
-            title="确定要删除这篇文章吗?"
-            onConfirm={() => handleDelete(record.id)}
-            okText="确定"
-            cancelText="取消"
-          >
-            <Button type="link" danger>删除</Button>
-          </Popconfirm>
-        </Space>
-      ),
-    },
-  ];
-  
-  return (
-    <div>
-      <Card title="知识库管理" className="mb-4">
-        <Form
-          layout="inline"
-          onFinish={handleSearch}
-          style={{ marginBottom: '16px' }}
-        >
-          <Form.Item name="title" label="标题">
-            <Input placeholder="请输入文章标题" />
-          </Form.Item>
-          
-          <Form.Item name="category" label="分类">
-            <Input placeholder="请输入文章分类" />
-          </Form.Item>
-          
-          <Form.Item>
-            <Space>
-              <Button type="primary" htmlType="submit">
-                搜索
-              </Button>
-              <Button onClick={() => {
-                setSearchParams({
-                  title: '',
-                  category: '',
-                  page: 1,
-                  limit: 10,
-                });
-              }}>
-                重置
-              </Button>
-              <Button type="primary" onClick={handleAdd}>
-                添加文章
-              </Button>
-            </Space>
-          </Form.Item>
-        </Form>
-        
-        <Table
-          columns={columns}
-          dataSource={articles}
-          rowKey="id"
-          loading={isListLoading}
-          pagination={{
-            current: pagination.current,
-            pageSize: pagination.pageSize,
-            total: pagination.total,
-            onChange: handlePageChange,
-            showSizeChanger: true,
-          }}
-        />
-      </Card>
-      
-      <Modal
-        title={formMode === 'create' ? '添加知识库文章' : '编辑知识库文章'}
-        open={modalVisible}
-        onOk={() => form.submit()}
-        onCancel={() => setModalVisible(false)}
-        width={800}
-      >
-        <Form
-          form={form}
-          layout="vertical"
-          onFinish={handleSubmit}
-          initialValues={{
-            audit_status: AuditStatus.PENDING,
-          }}
-        >
-          <Row gutter={16}>
-            <Col span={12}>
-              <Form.Item
-                name="title"
-                label="文章标题"
-                rules={[{ required: true, message: '请输入文章标题' }]}
-              >
-                <Input placeholder="请输入文章标题" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                name="category"
-                label="文章分类"
-              >
-                <Input placeholder="请输入文章分类" />
-              </Form.Item>
-            </Col>
-          </Row>
-          
-          <Form.Item
-            name="tags"
-            label="文章标签"
-            help="多个标签请用英文逗号分隔,如: 服务器,网络,故障"
-          >
-            <Input placeholder="请输入文章标签,多个标签请用英文逗号分隔" />
-          </Form.Item>
-          
-          <Form.Item
-            name="content"
-            label="文章内容"
-            rules={[{ required: true, message: '请输入文章内容' }]}
-          >
-            <Input.TextArea rows={15} placeholder="请输入文章内容,支持Markdown格式" />
-          </Form.Item>
-          
-          <Row gutter={16}>
-            <Col span={12}>
-              <Form.Item
-                name="author"
-                label="文章作者"
-              >
-                <Input placeholder="请输入文章作者" />
-              </Form.Item>
-            </Col>
-            <Col span={12}>
-              <Form.Item
-                name="cover_url"
-                label="封面图片URL"
-              >
-                <Input placeholder="请输入封面图片URL" />
-              </Form.Item>
-            </Col>
-          </Row>
-          
-          <Form.Item
-            name="audit_status"
-            label="审核状态"
-          >
-            <Select options={auditStatusOptions} />
-          </Form.Item>
-          
-          <Form.Item>
-            <Space>
-              <Button type="primary" htmlType="submit" loading={isLoading}>
-                {formMode === 'create' ? '创建' : '保存'}
-              </Button>
-              <Button onClick={() => setModalVisible(false)}>取消</Button>
-            </Space>
-          </Form.Item>
-        </Form>
-      </Modal>
-    </div>
-  );
-};
-
 // 文件库管理页面
 export const FileLibraryPage = () => {
   const [loading, setLoading] = useState(false);

+ 2 - 3
client/admin/test/theme_setting_page.test.tsx

@@ -1,6 +1,5 @@
-import { JSDOM } from 'npm:jsdom'
+import { JSDOM } from 'jsdom'
 import React from 'react'
-import 'npm:jsdom-global'
 import {render, fireEvent, within, screen} from '@testing-library/react'
 import { ThemeSettingsPage } from "../pages_settings.tsx"
 import { ThemeProvider } from "../hooks_sys.tsx"
@@ -79,7 +78,7 @@ Deno.test('主题设置页面测试', async (t) => {
     </QueryClientProvider>
   )
 
-  debug(await findByRole('radio', { name: /浅色模式/i }))
+  // debug(await findByRole('radio', { name: /浅色模式/i }))
 
   // 测试1: 渲染基本元素
   await t.step('应渲染主题设置标题', async () => {

+ 1 - 1
client/admin/web_app.tsx

@@ -72,9 +72,9 @@ import {
 import {
   DashboardPage,
   UsersPage,
-  KnowInfoPage,
   FileLibraryPage
 } from './pages_sys.tsx';
+import { KnowInfoPage } from './pages_know.tsx';
 import { MessagesPage } from './pages_messages.tsx';
 import {
   SettingsPage,

+ 2 - 1
deno.json

@@ -29,7 +29,8 @@
     "react-hook-form": "https://esm.d8d.fun/react-hook-form@7.55.0?dev&deps=react@19.0.0,react-dom@19.0.0",
     "@heroicons/react/24/outline": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/outline?dev&deps=react@19.0.0,react-dom@19.0.0",
     "@heroicons/react/24/solid": "https://esm.d8d.fun/@heroicons/react@2.1.1/24/solid?dev&deps=react@19.0.0,react-dom@19.0.0",
-    "@testing-library/react": "https://esm.d8d.fun/@testing-library/react@16.3.0?dev&deps=react@19.0.0,react-dom@19.0.0"
+    "@testing-library/react": "https://esm.d8d.fun/@testing-library/react@16.3.0?dev&deps=react@19.0.0,react-dom@19.0.0",
+    "jsdom":"npm:jsdom@26.0.0"
   },
   "compilerOptions": {
     "lib": ["dom", "dom.iterable", "esnext", "deno.ns"]

File diff ditekan karena terlalu besar
+ 621 - 0
deno.lock


Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini