diff --git a/apps/admin/src/App.tsx b/apps/admin/src/App.tsx index ff62f91..eed9a23 100644 --- a/apps/admin/src/App.tsx +++ b/apps/admin/src/App.tsx @@ -29,6 +29,7 @@ import AttendancePage from './pages/Attendance'; import TeacherWorkspacePage from './pages/TeacherWorkspace'; import NotificationsPage from './pages/Notifications'; import DepartmentsPage from './pages/Departments'; +import IntegrationConfigPage from './pages/IntegrationConfig'; import PermissionRoute from './components/PermissionRoute'; const PrivateRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => { @@ -262,6 +263,15 @@ const App: React.FC = () => { } /> + + + + + } + /> diff --git a/apps/admin/src/layouts/MainLayout.tsx b/apps/admin/src/layouts/MainLayout.tsx index 6057c52..a6ad416 100644 --- a/apps/admin/src/layouts/MainLayout.tsx +++ b/apps/admin/src/layouts/MainLayout.tsx @@ -25,6 +25,7 @@ import { CheckCircleOutlined, LaptopOutlined, BellOutlined, + ApiOutlined, } from '@ant-design/icons'; import { usePermission } from '../hooks/usePermission'; import NotificationBell from '../components/NotificationBell'; @@ -113,6 +114,7 @@ const allMenuItems: MenuItemType[] = [ { key: '/operation-logs', icon: , label: '操作日志', permission: 'log:view' }, { key: '/roles', icon: , label: '角色管理', permission: 'role:view' }, { key: '/permissions', icon: , label: '权限一览', permission: 'role:view' }, + { key: '/integration-config', icon: , label: '钉钉集成配置', permission: 'integration:read' }, { key: '/users', icon: , label: '账号管理', permission: 'user:view' }, ], }, diff --git a/apps/admin/src/pages/IntegrationConfig/index.tsx b/apps/admin/src/pages/IntegrationConfig/index.tsx new file mode 100644 index 0000000..e601eea --- /dev/null +++ b/apps/admin/src/pages/IntegrationConfig/index.tsx @@ -0,0 +1,139 @@ +import React, { useEffect, useState } from 'react'; +import { + Card, Form, Input, Button, Space, message, Spin, Switch, Alert, Descriptions, Tag, +} from 'antd'; +import { + SaveOutlined, ApiOutlined, CheckCircleOutlined, CloseCircleOutlined, +} from '@ant-design/icons'; +import api from '../../api'; + +interface DingTalkConfig { + agentId: string; + appSecret: string; + corpId: string; + startEnable: boolean; +} + +const IntegrationConfigPage: React.FC = () => { + const [loading, setLoading] = useState(false); + const [saving, setSaving] = useState(false); + const [testing, setTesting] = useState(false); + const [config, setConfig] = useState(null); + const [verified, setVerified] = useState(null); + const [form] = Form.useForm(); + + const fetchConfig = async () => { + setLoading(true); + try { + const res = await api.get<{ success: boolean; data: Array<{ type: string; verify: boolean; config: DingTalkConfig }> }>('/integration/config'); + const dt = res.data?.find((c) => c.type === 'DINGTALK'); + if (dt) { + setConfig(dt.config); + setVerified(dt.verify); + form.setFieldsValue(dt.config); + } + } catch { + // not configured + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchConfig(); + }, []); + + const handleSave = async () => { + const values = await form.validateFields(); + setSaving(true); + try { + await api.post('/integration/config', { type: 'DINGTALK', config: values }); + message.success('配置已保存'); + await fetchConfig(); + } catch (e: unknown) { + const err = e as { message?: string }; + message.error(err?.message || '保存失败'); + } finally { + setSaving(false); + } + }; + + const handleTest = async () => { + const values = await form.validateFields(); + setTesting(true); + try { + const res = await api.post<{ success: boolean; message: string }>('/integration/config/test', { + type: 'DINGTALK', + config: values, + }); + setVerified(res.success); + message.success(res.message); + } catch (e: unknown) { + const err = e as { message?: string }; + setVerified(false); + message.error(err?.message || '连接失败'); + } finally { + setTesting(false); + } + }; + + return ( + + {verified === true && } color="success">已连接} + {verified === false && } color="error">未连接} + + }> + + {config && ( + + {config.corpId || '-'} + {config.agentId || '-'} + + + {config.startEnable ? '已启用' : '未启用'} + + + + )} + + + +
+ + + + + + + + + + + + + + + + +
+
+
+ ); +}; + +export default IntegrationConfigPage;