From 248358cada5913fcd670331356b26cbed427caf1 Mon Sep 17 00:00:00 2001 From: mmmww <562306868@qq.com> Date: Sat, 11 May 2024 03:59:53 +0000 Subject: [PATCH 1/2] Initial commit From fe8a2e2c5975bebb65b6ee01c4cc674fa86193b3 Mon Sep 17 00:00:00 2001 From: mmmww <562306868@qq.com> Date: Sat, 11 May 2024 03:59:53 +0000 Subject: [PATCH 2/2] Pending changes exported from your codespace --- config/config.ts | 20 +- config/defaultSettings.ts | 4 +- config/routes.ts | 63 +-- go.mod | 10 + go.sum | 6 + public/logo.svg | 2 +- public/logo2.svg | 1 + src/app.tsx | 29 +- src/components/Footer/index.tsx | 30 +- src/components/RightContent/index.tsx | 12 +- src/components/index.ts | 5 +- src/global.tsx | 21 +- src/locales/bn-BD/pages.ts | 2 +- src/locales/en-US/pages.ts | 2 +- src/locales/id-ID/pages.ts | 2 +- src/locales/pt-BR/pages.ts | 2 +- src/locales/zh-CN/menu.ts | 4 +- src/locales/zh-CN/pages.ts | 14 +- src/locales/zh-TW/pages.ts | 2 +- src/pages/404.tsx | 8 +- src/pages/Admin.tsx | 31 +- src/pages/TableList/components/UpdateForm.tsx | 267 ++++------ src/pages/TableList/group.tsx | 145 ++++++ src/pages/TableList/index.tsx | 465 ++++++++++++------ src/pages/TableList/list.tsx | 353 +++++++++++++ src/pages/User/Login/index.tsx | 150 ++---- src/pages/Welcome.tsx | 70 +-- src/pages/dashboard.tsx | 84 ++++ src/services/ant-design-pro/api.ts | 40 +- src/services/ant-design-pro/typings.d.ts | 4 + 30 files changed, 1195 insertions(+), 653 deletions(-) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 public/logo2.svg create mode 100644 src/pages/TableList/group.tsx create mode 100644 src/pages/TableList/list.tsx create mode 100644 src/pages/dashboard.tsx diff --git a/config/config.ts b/config/config.ts index f0004a8512..96ec717052 100644 --- a/config/config.ts +++ b/config/config.ts @@ -4,9 +4,7 @@ import { join } from 'path'; import defaultSettings from './defaultSettings'; import proxy from './proxy'; import routes from './routes'; - const { REACT_APP_ENV = 'dev' } = process.env; - export default defineConfig({ /** * @name 开启 hash 模式 @@ -14,7 +12,6 @@ export default defineConfig({ * @doc https://umijs.org/docs/api/config#hash */ hash: true, - /** * @name 兼容性设置 * @description 设置 ie11 不一定完美兼容,需要检查自己使用的所有依赖 @@ -76,7 +73,7 @@ export default defineConfig({ * @name layout 插件 * @doc https://umijs.org/docs/max/layout-menu */ - title: 'Ant Design Pro', + title: '在线管理系统', layout: { locale: true, ...defaultSettings, @@ -93,15 +90,7 @@ export default defineConfig({ /** * @name 国际化插件 * @doc https://umijs.org/docs/max/i18n - */ - locale: { - // default zh-CN - default: 'zh-CN', - antd: true, - // default true, when it is true, will use `navigator.language` overwrite default - baseNavigator: true, - }, - /** + */ /** * @name antd 插件 * @description 内置了 babel import 插件 * @doc https://umijs.org/docs/max/antd#antd @@ -125,7 +114,10 @@ export default defineConfig({ */ headScripts: [ // 解决首次加载时白屏的问题 - { src: '/scripts/loading.js', async: true }, + { + src: '/scripts/loading.js', + async: true, + }, ], //================ pro 插件配置 ================= presets: ['umi-presets-pro'], diff --git a/config/defaultSettings.ts b/config/defaultSettings.ts index 2796a7ecb1..f7439705c2 100644 --- a/config/defaultSettings.ts +++ b/config/defaultSettings.ts @@ -15,9 +15,9 @@ const Settings: ProLayoutProps & { fixedHeader: false, fixSiderbar: true, colorWeak: false, - title: 'Ant Design Pro', + title: '在线管理系统', pwa: true, - logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg', + logo: '/logo.svg', iconfontUrl: '', token: { // 参见ts声明,demo 见文档,通过token 修改样式 diff --git a/config/routes.ts b/config/routes.ts index 9a68bcb2e2..1c2e056c4e 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -1,63 +1,26 @@ -/** - * @name umi 的路由配置 - * @description 只支持 path,component,routes,redirect,wrappers,name,icon 的配置 - * @param path path 只支持两种占位符配置,第一种是动态参数 :id 的形式,第二种是 * 通配符,通配符只能出现路由字符串的最后。 - * @param component 配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。 - * @param routes 配置子路由,通常在需要为多个路径增加 layout 组件时使用。 - * @param redirect 配置路由跳转 - * @param wrappers 配置路由组件的包装组件,通过包装组件可以为当前的路由组件组合进更多的功能。 比如,可以用于路由级别的权限校验 - * @param name 配置路由的标题,默认读取国际化文件 menu.ts 中 menu.xxxx 的值,如配置 name 为 login,则读取 menu.ts 中 menu.login 的取值作为标题 - * @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 则取值应为 user 或者 User - * @doc https://umijs.org/docs/guides/routes - */ +import component from "@/locales/bn-BD/component"; + export default [ { path: '/user', layout: false, - routes: [ - { - name: 'login', - path: '/user/login', - component: './User/Login', - }, - ], - }, - { - path: '/welcome', - name: 'welcome', - icon: 'smile', - component: './Welcome', + routes: [{ name: '登录', path: '/user/login', component: './User/Login' }], }, + { path: '/welcome', name: '欢迎', icon: 'smile', component: './Welcome' }, + { path: '/dashboard/workplace', name: '工作台', icon: 'dashboard', component: './dashboard'}, { path: '/admin', - name: 'admin', + name: '管理页', icon: 'crown', access: 'canAdmin', routes: [ - { - path: '/admin', - redirect: '/admin/sub-page', - }, - { - path: '/admin/sub-page', - name: 'sub-page', - component: './Admin', - }, + { path: '/admin', redirect: '/admin/sub-page' }, + { path: '/admin/sub-page', name: '二级管理页', component: './Admin' }, ], }, - { - name: 'list.table-list', - icon: 'table', - path: '/list', - component: './TableList', - }, - { - path: '/', - redirect: '/welcome', - }, - { - path: '*', - layout: false, - component: './404', - }, + { name: '设备列表', icon: 'table', path: '/list/device-list', component: './TableList' }, + { name: '设备分组', icon: 'table', path: '/list/group-list', component: './TableList/group' }, + { name: '记录列表', icon: 'table', path: '/list/basic-list', component: './TableList/list' }, + { path: '/', redirect: '/welcome' }, + { path: '*', layout: false, component: './404' }, ]; diff --git a/go.mod b/go.mod new file mode 100644 index 0000000000..ee67e07b4d --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module app + +go 1.22.2 + +require ( + github.com/gorilla/websocket v1.5.1 + golang.org/x/sys v0.19.0 +) + +require golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000000..0cf6c193a3 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/public/logo.svg b/public/logo.svg index 239bf69f18..c4e279a8e0 100644 --- a/public/logo.svg +++ b/public/logo.svg @@ -1 +1 @@ -Group 28 Copy 5Created with Sketch. \ No newline at end of file + \ No newline at end of file diff --git a/public/logo2.svg b/public/logo2.svg new file mode 100644 index 0000000000..239bf69f18 --- /dev/null +++ b/public/logo2.svg @@ -0,0 +1 @@ +Group 28 Copy 5Created with Sketch. \ No newline at end of file diff --git a/src/app.tsx b/src/app.tsx index 22fd9a9e30..e5d4a5cbda 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,13 +1,12 @@ -import { Footer, Question, SelectLang, AvatarDropdown, AvatarName } from '@/components'; +import { AvatarDropdown, AvatarName, Footer, Question } from '@/components'; +import { currentUser as queryCurrentUser } from '@/services/ant-design-pro/api'; import { LinkOutlined } from '@ant-design/icons'; import type { Settings as LayoutSettings } from '@ant-design/pro-components'; import { SettingDrawer } from '@ant-design/pro-components'; import type { RunTimeLayoutConfig } from '@umijs/max'; -import { history, Link } from '@umijs/max'; +import { Link, history } from '@umijs/max'; import defaultSettings from '../config/defaultSettings'; import { errorConfig } from './requestErrorConfig'; -import { currentUser as queryCurrentUser } from '@/services/ant-design-pro/api'; -import React from 'react'; const isDev = process.env.NODE_ENV === 'development'; const loginPath = '/user/login'; @@ -50,7 +49,7 @@ export async function getInitialState(): Promise<{ // ProLayout 支持的api https://procomponents.ant.design/components/layout export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => { return { - actionsRender: () => [, ], + actionsRender: () => [], avatarProps: { src: initialState?.currentUser?.avatar, title: , @@ -131,6 +130,26 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) = * 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。 * @doc https://umijs.org/docs/max/request#配置 */ +/** + * + * 对request进行运行时配置,并且该配置会直接透传到umi-request的全局配置。 + * 后续直接从umi中引入request或者useRequest直接使用,可以说是非常方便。 + */ + +/** 请求拦截 */ +const requestInterceptor = (url: any, options: any): any => { + const headers = { + ...options.headers, + //此处需要修改一下逻辑判断 + Authorization: localStorage.getItem('authToken') || '1213', + }; + return { + url: url, + options: { ...options, headers: headers }, + }; +}; + export const request = { ...errorConfig, + requestInterceptors: [requestInterceptor], //请求拦截 }; diff --git a/src/components/Footer/index.tsx b/src/components/Footer/index.tsx index f204ac2930..0d6c24e052 100644 --- a/src/components/Footer/index.tsx +++ b/src/components/Footer/index.tsx @@ -9,22 +9,22 @@ const Footer: React.FC = () => { background: 'none', }} links={[ + // { + // key: 'Pro', + // title: 'Pro', + // href: '', + // blankTarget: true, + // }, + // { + // key: '@@@', + // title: , + // href: '', + // blankTarget: true, + // }, { - key: 'Ant Design Pro', - title: 'Ant Design Pro', - href: 'https://pro.ant.design', - blankTarget: true, - }, - { - key: 'github', - title: , - href: 'https://github.com/ant-design/ant-design-pro', - blankTarget: true, - }, - { - key: 'Ant Design', - title: 'Ant Design', - href: 'https://ant.design', + key: 'copyright', + title: "2024", + href: '', blankTarget: true, }, ]} diff --git a/src/components/RightContent/index.tsx b/src/components/RightContent/index.tsx index 20a7831109..5fa818fc6b 100644 --- a/src/components/RightContent/index.tsx +++ b/src/components/RightContent/index.tsx @@ -1,9 +1,6 @@ import { QuestionCircleOutlined } from '@ant-design/icons'; -import { SelectLang as UmiSelectLang } from '@umijs/max'; -import React from 'react'; - +import '@umijs/max'; export type SiderTheme = 'light' | 'dark'; - export const SelectLang = () => { return ( { /> ); }; - export const Question = () => { return (
{ display: 'flex', height: 26, }} - onClick={() => { - window.open('https://pro.ant.design/docs/getting-started'); - }} + // onClick={() => { + // window.open('https://pro.ant.design/docs/getting-started'); + // }} >
diff --git a/src/components/index.ts b/src/components/index.ts index ca88a6d07d..33aa76e6a1 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -6,7 +6,6 @@ * 布局组件 */ import Footer from './Footer'; -import { Question, SelectLang } from './RightContent'; +import { Question } from './RightContent'; import { AvatarDropdown, AvatarName } from './RightContent/AvatarDropdown'; - -export { Footer, Question, SelectLang, AvatarDropdown, AvatarName }; +export { AvatarDropdown, AvatarName, Footer, Question }; diff --git a/src/global.tsx b/src/global.tsx index afa1fab566..db2c2969f3 100644 --- a/src/global.tsx +++ b/src/global.tsx @@ -1,10 +1,8 @@ -import { useIntl } from '@umijs/max'; +import '@umijs/max'; import { Button, message, notification } from 'antd'; import defaultSettings from '../config/defaultSettings'; - const { pwa } = defaultSettings; const isHttps = document.location.protocol === 'https:'; - const clearCache = () => { // remove all caches if (window.caches) { @@ -23,7 +21,7 @@ const clearCache = () => { if (pwa) { // Notify user if offline now window.addEventListener('sw.offline', () => { - message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' })); + message.warning('当前处于离线状态'); }); // Pop up a prompt on the page asking the user if they want to use the latest version @@ -46,9 +44,13 @@ if (pwa) { resolve(msgEvent.data); } }; - worker.postMessage({ type: 'skip-waiting' }, [channel.port2]); + worker.postMessage( + { + type: 'skip-waiting', + }, + [channel.port2], + ); }); - clearCache(); window.location.reload(); return true; @@ -62,12 +64,12 @@ if (pwa) { reloadSW(); }} > - {useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })} + {'刷新'} ); notification.open({ - message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }), - description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }), + message: '有新内容', + description: '请点击“刷新”按钮或者手动刷新页面', btn, key, onClose: async () => null, @@ -86,6 +88,5 @@ if (pwa) { serviceWorker.getRegistration().then((sw) => { if (sw) sw.unregister(); }); - clearCache(); } diff --git a/src/locales/bn-BD/pages.ts b/src/locales/bn-BD/pages.ts index 07e0cf1692..b621d34dcd 100644 --- a/src/locales/bn-BD/pages.ts +++ b/src/locales/bn-BD/pages.ts @@ -5,7 +5,7 @@ export default { 'pages.login.accountLogin.errorMessage': 'ভুল ব্যবহারকারীর নাম/পাসওয়ার্ড(admin/ant.design)', 'pages.login.failure': 'লগইন ব্যর্থ হয়েছে। আবার চেষ্টা করুন!', 'pages.login.success': 'সফল লগইন!', - 'pages.login.username.placeholder': 'ব্যবহারকারীর নাম: admin or user', + 'pages.login.username.placeholder': 'ব্যবহারকারীর নাম', 'pages.login.username.required': 'আপনার ব্যবহারকারীর নাম ইনপুট করুন!', 'pages.login.password.placeholder': 'পাসওয়ার্ড: ant.design', 'pages.login.password.required': 'আপনার পাসওয়ার্ড ইনপুট করুন!', diff --git a/src/locales/en-US/pages.ts b/src/locales/en-US/pages.ts index 3334c03057..43b7f67784 100644 --- a/src/locales/en-US/pages.ts +++ b/src/locales/en-US/pages.ts @@ -5,7 +5,7 @@ export default { 'pages.login.accountLogin.errorMessage': 'Incorrect username/password(admin/ant.design)', 'pages.login.failure': 'Login failed, please try again!', 'pages.login.success': 'Login successful!', - 'pages.login.username.placeholder': 'Username: admin or user', + 'pages.login.username.placeholder': 'Username', 'pages.login.username.required': 'Please input your username!', 'pages.login.password.placeholder': 'Password: ant.design', 'pages.login.password.required': 'Please input your password!', diff --git a/src/locales/id-ID/pages.ts b/src/locales/id-ID/pages.ts index de28ef3668..49ae4aeb25 100644 --- a/src/locales/id-ID/pages.ts +++ b/src/locales/id-ID/pages.ts @@ -5,7 +5,7 @@ export default { 'pages.login.accountLogin.errorMessage': 'Nama pengguna dan kata sandi salah(admin/ant.design)', 'pages.login.failure': 'Log masuk gagal, silakan coba lagi!', 'pages.login.success': 'Login berhasil!', - 'pages.login.username.placeholder': 'nama pengguna: admin atau user', + 'pages.login.username.placeholder': 'nama pengguna', 'pages.login.username.required': 'Nama pengguna harus diisi!', 'pages.login.password.placeholder': 'kata sandi: ant.design', 'pages.login.password.required': 'Kata sandi harus diisi!', diff --git a/src/locales/pt-BR/pages.ts b/src/locales/pt-BR/pages.ts index 6a96e9b889..807fc75a3d 100644 --- a/src/locales/pt-BR/pages.ts +++ b/src/locales/pt-BR/pages.ts @@ -5,7 +5,7 @@ export default { 'pages.login.accountLogin.errorMessage': 'usuário/senha incorreto(admin/ant.design)', 'pages.login.failure': 'Login falhou, por favor tente novamente!', 'pages.login.success': 'Login efetuado com sucesso!', - 'pages.login.username.placeholder': 'Usuário: admin or user', + 'pages.login.username.placeholder': 'Usuário', 'pages.login.username.required': 'Por favor insira seu usuário!', 'pages.login.password.placeholder': 'Senha: ant.design', 'pages.login.password.required': 'Por favor insira sua senha!', diff --git a/src/locales/zh-CN/menu.ts b/src/locales/zh-CN/menu.ts index fecb70a40f..29b619f7eb 100644 --- a/src/locales/zh-CN/menu.ts +++ b/src/locales/zh-CN/menu.ts @@ -22,8 +22,8 @@ export default { 'menu.form.step-form.result': '分步表单(完成)', 'menu.form.advanced-form': '高级表单', 'menu.list': '列表页', - 'menu.list.table-list': '查询表格', - 'menu.list.basic-list': '标准列表', + 'menu.list.table-list': '设备列表', + 'menu.list.basic-list': '记录列表', 'menu.list.card-list': '卡片列表', 'menu.list.search-list': '搜索列表', 'menu.list.search-list.articles': '搜索列表(文章)', diff --git a/src/locales/zh-CN/pages.ts b/src/locales/zh-CN/pages.ts index a266bc6ca5..4d6fa5bfc0 100644 --- a/src/locales/zh-CN/pages.ts +++ b/src/locales/zh-CN/pages.ts @@ -1,12 +1,12 @@ export default { 'pages.layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范', 'pages.login.accountLogin.tab': '账户密码登录', - 'pages.login.accountLogin.errorMessage': '错误的用户名和密码(admin/ant.design)', + 'pages.login.accountLogin.errorMessage': '错误的用户名和密码', 'pages.login.failure': '登录失败,请重试!', 'pages.login.success': '登录成功!', - 'pages.login.username.placeholder': '用户名: admin or user', + 'pages.login.username.placeholder': '用户名', 'pages.login.username.required': '用户名是必填项!', - 'pages.login.password.placeholder': '密码: ant.design', + 'pages.login.password.placeholder': '密码', 'pages.login.password.required': '密码是必填项!', 'pages.login.phoneLogin.tab': '手机号登录', 'pages.login.phoneLogin.errorMessage': '验证码错误', @@ -31,7 +31,7 @@ export default { 'pages.searchTable.createForm.newRule': '新建规则', 'pages.searchTable.updateForm.ruleConfig': '规则配置', 'pages.searchTable.updateForm.basicConfig': '基本信息', - 'pages.searchTable.updateForm.ruleName.nameLabel': '规则名称', + 'pages.searchTable.updateForm.ruleName.nameLabel': '名称', 'pages.searchTable.updateForm.ruleName.nameRules': '请输入规则名称!', 'pages.searchTable.updateForm.ruleDesc.descLabel': '规则描述', 'pages.searchTable.updateForm.ruleDesc.descPlaceholder': '请输入至少五个字符', @@ -45,10 +45,10 @@ export default { 'pages.searchTable.updateForm.schedulingPeriod.timeRules': '请选择开始时间!', 'pages.searchTable.titleDesc': '描述', 'pages.searchTable.ruleName': '规则名称为必填项', - 'pages.searchTable.titleCallNo': '服务调用次数', + 'pages.searchTable.titleCallNo': '本机IP', 'pages.searchTable.titleStatus': '状态', - 'pages.searchTable.nameStatus.default': '关闭', - 'pages.searchTable.nameStatus.running': '运行中', + 'pages.searchTable.nameStatus.default': '离线', + 'pages.searchTable.nameStatus.running': '在线', 'pages.searchTable.nameStatus.online': '已上线', 'pages.searchTable.nameStatus.abnormal': '异常', 'pages.searchTable.titleUpdatedAt': '上次调度时间', diff --git a/src/locales/zh-TW/pages.ts b/src/locales/zh-TW/pages.ts index 37000c0145..e66e414c45 100644 --- a/src/locales/zh-TW/pages.ts +++ b/src/locales/zh-TW/pages.ts @@ -4,7 +4,7 @@ export default { 'pages.login.accountLogin.errorMessage': '錯誤的用戶名和密碼(admin/ant.design)', 'pages.login.failure': '登錄失敗,請重試!', 'pages.login.success': '登錄成功!', - 'pages.login.username.placeholder': '用戶名: admin or user', + 'pages.login.username.placeholder': '用戶名', 'pages.login.username.required': '用戶名是必填項!', 'pages.login.password.placeholder': '密碼: ant.design', 'pages.login.password.required': '密碼是必填項!', diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 469356750c..42b3a15026 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,18 +1,16 @@ -import { history, useIntl } from '@umijs/max'; +import { history } from '@umijs/max'; import { Button, Result } from 'antd'; import React from 'react'; - const NoFoundPage: React.FC = () => ( history.push('/')}> - {useIntl().formatMessage({ id: 'pages.404.buttonText' })} + {'返回首页'} } /> ); - export default NoFoundPage; diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx index 2f93986b49..e0a1aae352 100644 --- a/src/pages/Admin.tsx +++ b/src/pages/Admin.tsx @@ -1,24 +1,14 @@ import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons'; import { PageContainer } from '@ant-design/pro-components'; -import { useIntl } from '@umijs/max'; +import '@umijs/max'; import { Alert, Card, Typography } from 'antd'; import React from 'react'; - const Admin: React.FC = () => { - const intl = useIntl(); return ( - + { marginBottom: 48, }} /> - + Ant Design Pro You -

+

Want to add more pages? Please refer to{' '} use block @@ -41,5 +41,4 @@ const Admin: React.FC = () => { ); }; - export default Admin; diff --git a/src/pages/TableList/components/UpdateForm.tsx b/src/pages/TableList/components/UpdateForm.tsx index 5cd603ee22..158f5cca8d 100644 --- a/src/pages/TableList/components/UpdateForm.tsx +++ b/src/pages/TableList/components/UpdateForm.tsx @@ -1,13 +1,7 @@ -import { - ProFormDateTimePicker, - ProFormRadio, - ProFormSelect, - ProFormText, - ProFormTextArea, - StepsForm, -} from '@ant-design/pro-components'; -import { FormattedMessage, useIntl } from '@umijs/max'; -import { Modal } from 'antd'; +import { ProFormText, ProFormTextArea, ProFormSelect, ModalForm } from '@ant-design/pro-components'; +import '@umijs/max'; +import { Button } from 'antd'; +import { request } from '@umijs/max'; import React from 'react'; export type FormValueType = { @@ -16,6 +10,7 @@ export type FormValueType = { type?: string; time?: string; frequency?: string; + group?: number; // 分组选项的 ID } & Partial; export type UpdateFormProps = { @@ -26,183 +21,91 @@ export type UpdateFormProps = { }; const UpdateForm: React.FC = (props) => { - const intl = useIntl(); + const { updateModalOpen, onCancel, onSubmit, values } = props; + + const handleFinish = async (formValues: FormValueType) => { + await onSubmit(formValues); + }; + return ( - + title="修改名称" + width={640} + open={updateModalOpen} + modalProps={{ + destroyOnClose: true, + onCancel: () => onCancel(), + }} + onFinish={handleFinish} + initialValues={{ + name: values.name, + desc: values.desc, + group: values.group_id, // 初始化时设定分组选项 }} - stepsFormRender={(dom, submitter) => { - return ( - { - props.onCancel(); - }} - > - {dom} - - ); + submitter={{ + render: (_, dom) => ( + <> + + {dom.pop()} + + ), }} - onFinish={props.onSubmit} > - - - ), - }, - ]} - /> - - ), - min: 5, - }, - ]} - /> - - - - - - - + + { + try { + const response = await request('https://867t766n6.zicp.fun/groups', { + method: 'GET' + } + ); + const { data } = response; + + // 返回一个包含 { label, value } 键值对的数组 + return data.map((group: { id: number; group_name: string }) => ({ + label: group.group_name, + value: group.id, + })); + } catch (error) { + console.error('获取分组数据失败', error); + return []; + } }} - title={intl.formatMessage({ - id: 'pages.searchTable.updateForm.schedulingPeriod.title', - defaultMessage: '设定调度周期', - })} - > - - ), - }, - ]} - /> - - - + // rules={[ + // { + // required: true, + // message: '请选择一个分组!', + // }, + // ]} + // width="md" + /> + ); }; diff --git a/src/pages/TableList/group.tsx b/src/pages/TableList/group.tsx new file mode 100644 index 0000000000..adf5eeb451 --- /dev/null +++ b/src/pages/TableList/group.tsx @@ -0,0 +1,145 @@ +import React, { useRef } from 'react'; +import { ActionType, ModalForm, ProColumns, ProFormText, ProTable } from '@ant-design/pro-components'; +import { Button, Popconfirm, message } from 'antd'; +import { request } from '@umijs/max'; + +// 定义一个接口来描述分组的形状 +interface Tag { + id: number; + TagKey: string; + TagValue: string; +} + +const TagsTable: React.FC = () => { + // 创建一个actionRef来控制ProTable + const actionRef = useRef(); + +const onFinish = async (values: { group_name: string, description: string }) => { + try { + // 使用@umijs/max的request方法发送POST请求 + const { success, message: apiMessage, group_id } = await request('https://867t766n6.zicp.fun/groups', { + method: 'POST', + data: { + group_name: values.group_name, + description: values.description, // 假设对于新分组TagValue是空的 + }, + // 注意:@umijs/max的request默认使用'application/json',并自动转换body为JSON字符串 + }); + + // 根据接口返回的success字段判断操作是否成功 + if (success) { + message.success(apiMessage || '分组创建成功!'); + actionRef.current?.reload(); // 刷新表格以显示新创建的分组 + return true; + } else { + message.error(apiMessage || '分组创建失败。'); + return false; + } + } catch (error) { + // 处理请求过程中出现的错误 + console.error('创建操作失败', error); + message.error('操作异常,请稍后重试。'); + return false; + } +}; + + // 使用ProColumns来确保columns与Tag接口一致 + const columns: ProColumns[] = [ + { title: 'ID', dataIndex: 'id', key: 'id' }, + { title: '分组名称', dataIndex: 'group_name', key: 'group_name' }, + { title: '分组描述', dataIndex: 'description', key: 'description' }, + { + title: '操作', + key: 'action', + render: (_, record: Tag) => ( + deleteTag(record)} + okText="确定" + cancelText="取消" + > + + + ), + }, + ]; + +const deleteTag = async (record: Tag) => { + try { + // 使用@umijs/max的request方法发送DELETE请求 + const { success, message: apiMessage } = await request(`https://867t766n6.zicp.fun/groups/${record.id}`, { + method: 'DELETE', + }); + + // 根据返回的success字段判断操作是否成功 + if (success) { + message.success(apiMessage || '分组删除成功。'); + } else { + message.error(apiMessage || '分组删除失败。'); + } + + // 如果你有引用ProTable的actionRef来刷新数据,也可以在这里调用 + actionRef.current?.reload(); + } catch (error) { + // 处理请求过程中出现的错误 + console.error('删除操作失败', error); + message.error('操作异常,请稍后重试。'); + } +}; + + return + columns={columns} + actionRef={actionRef} + request={async (params, sorter, filter) => { + // 使用 @umijs/max 的 request 方法请求数据 + const response = await request('https://867t766n6.zicp.fun/groups', { + method: 'GET', // 根据实际请求调整 + // 可以在这里传递查询参数(如分页信息),或者设置请求头部等 + // params: { ...params }, + }); + + // 直接从response中解构出data + const { data } = response; + + return { + data: data, // 实际的数据数组 + success: true, // 请求是否成功 + total: data.length, // 数据总数,用于分页 + }; + }} + + rowKey="id" + pagination={false} + search={false} + toolBarRender={() => [ + + 新建分组 + + } + onFinish={onFinish} + modalProps={{ + onCancel: () => console.log('取消新建分组'), + }} + > + + + , + ]} + />; +}; + +export default TagsTable; diff --git a/src/pages/TableList/index.tsx b/src/pages/TableList/index.tsx index c201007242..4599c48e49 100644 --- a/src/pages/TableList/index.tsx +++ b/src/pages/TableList/index.tsx @@ -1,20 +1,92 @@ import { addRule, removeRule, rule, updateRule } from '@/services/ant-design-pro/api'; -import { PlusOutlined } from '@ant-design/icons'; import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components'; import { FooterToolbar, ModalForm, PageContainer, ProDescriptions, + ProFormSelect, ProFormText, ProFormTextArea, ProTable, } from '@ant-design/pro-components'; -import { FormattedMessage, useIntl } from '@umijs/max'; -import { Button, Drawer, Input, message } from 'antd'; +import '@umijs/max'; +import { Button, Drawer, Image, Input, Modal, Popconfirm, Space, Tag, Tooltip, Typography, message } from 'antd'; import React, { useRef, useState } from 'react'; import type { FormValueType } from './components/UpdateForm'; import UpdateForm from './components/UpdateForm'; +import { request } from '@umijs/max'; +import { DeleteOutlined } from '@ant-design/icons'; +const { Text, Link } = Typography; +const HistoryModalTable = ({ visible, guid, onCancel }) => { + return ( + + { + // 根据 format 判断内容类型 + if (record.format === 'CF_TEXT') { + // 直接显示文本 + return record.content; + } else if (record.format === 'CF_BITMAP') { + // 显示为图片 + const imageUrl = `https://867t766n6.zicp.fun/${record.content}`; + return 剪辑图片; + } else { + // 其他类型显示默认信息 + return '未知内容'; + } + }, + }, + { + title: '地址', + dataIndex: 'detected_address', + key: 'detected_address', + }, + ]} + request={async (params) => { + const response = await request( + `https://867t766n6.zicp.fun/history?guid1=${guid}&pageSize=${params.pageSize}¤t=${params.current}`,{ + method: 'GET' + } + ); + return { + data: response.data || [], + success: true, + total: response.total || 0, + }; + }} + rowKey="id" + pagination={{ + pageSize: 10, + }} + search={false} + /> + + ); +}; /** * @en-US Add node @@ -24,7 +96,9 @@ import UpdateForm from './components/UpdateForm'; const handleAdd = async (fields: API.RuleListItem) => { const hide = message.loading('正在添加'); try { - await addRule({ ...fields }); + await addRule({ + ...fields, + }); hide(); message.success('Added successfully'); return true; @@ -42,20 +116,20 @@ const handleAdd = async (fields: API.RuleListItem) => { * @param fields */ const handleUpdate = async (fields: FormValueType) => { - const hide = message.loading('Configuring'); + const hide = message.loading('正在修改'); try { await updateRule({ + key: [fields.id], name: fields.name, desc: fields.desc, - key: fields.key, + group: fields.group, }); hide(); - - message.success('Configuration is successful'); + message.success('修改成功'); return true; } catch (error) { hide(); - message.error('Configuration failed, please try again!'); + message.error('修改失败,请重试!'); return false; } }; @@ -71,18 +145,20 @@ const handleRemove = async (selectedRows: API.RuleListItem[]) => { if (!selectedRows) return true; try { await removeRule({ - key: selectedRows.map((row) => row.key), + key: selectedRows.map((row) => row.id), }); hide(); - message.success('Deleted successfully and will refresh soon'); + message.success('删除成功,即将刷新'); return true; } catch (error) { hide(); - message.error('Delete failed, please try again'); + message.error('删除失败,请重试'); return false; } }; + + const TableList: React.FC = () => { /** * @en-US Pop-up window of new window @@ -94,131 +170,165 @@ const TableList: React.FC = () => { * @zh-CN 分布更新窗口的弹窗 * */ const [updateModalOpen, handleUpdateModalOpen] = useState(false); - const [showDetail, setShowDetail] = useState(false); - const actionRef = useRef(); const [currentRow, setCurrentRow] = useState(); const [selectedRowsState, setSelectedRows] = useState([]); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [historyModalVisible, setHistoryModalVisible] = useState(false); + + + const handleViewClick = (record) => { + setCurrentRow(record); + setHistoryModalVisible(true); + }; + + const onFinish = async (values) => { + try { + // 发送批量分组请求 + await request('https://867t766n6.zicp.fun/batchGroupDevices', { + method: 'POST', + data: { + group_id: values.group, + device_ids: selectedRowKeys, + }, + }); + console.log('分组设置成功!'); + message.success('分组设置成功!'); + // 调用成功回调 + actionRef.current?.reload(); + return true; // 关闭ModalForm + } catch (error) { + console.error('分组设置失败:', error); + message.error('分组设置失败:', error); + // 在这里处理错误情况 + return false; // 保持ModalForm开启,以便用户可以修正并重试 + } + }; /** * @en-US International configuration * @zh-CN 国际化配置 * */ - const intl = useIntl(); const columns: ProColumns[] = [ { - title: ( - - ), - dataIndex: 'name', - tip: 'The rule name is the unique key', + title: '名称', + dataIndex: 'username', + tip: '名称/用户名', + hideInSearch: true, render: (dom, entity) => { return ( - + {/* { setCurrentRow(entity); setShowDetail(true); }} - > + > {dom} - + */} + {dom} +

{entity.name}
+ ); }, }, { - title: , + title: '描述', dataIndex: 'desc', valueType: 'textarea', + hideInSearch: true, }, { - title: ( - - ), - dataIndex: 'callNo', - sorter: true, + title: '主机名', + dataIndex: 'hostname', + width: '10%', + hideInSearch: true, + }, + // { + // title: '本机IP', + // dataIndex: 'ip_mac', + // sorter: true, + // hideInForm: true, + // width: '10%', + // render: (_, record) => { + // return ( + // <> + // {record.ip_mac.map((item, index) => ( + // + // {`${item.ip_address.slice(0, 20)} (${item.mac})`} + // + // ))} + // + // ); + // }, + // }, + { + title: '分组', + dataIndex: 'group_name', hideInForm: true, - renderText: (val: string) => - `${val}${intl.formatMessage({ - id: 'pages.searchTable.tenThousand', - defaultMessage: ' 万 ', - })}`, + valueType: 'select', + request: async () => { + const response = await request('https://867t766n6.zicp.fun/groups', { + method: 'GET', + }); + // 映射返回的分组数据,并在数组开头添加 "未分组" + const groups = response.data.map(item => ({ label: item.group_name, value: item.id })); + + // 添加未分组选项 + groups.unshift({ label: '未分组', value: 0 }); + + return groups; + // return response.data.map(item => ({ label: item.group_name , value: item.id })); + }, + // render: (_, record) => ( + // + // {record.search_word_obj.map((word, index) => ( + // + // {word} + // + // ))} + // + // ), + search: { + transform: (value) => ({ group_id: value }), + }, }, { - title: , + title: '状态', dataIndex: 'status', hideInForm: true, valueEnum: { 0: { - text: ( - - ), + text: '离线', status: 'Default', }, 1: { - text: ( - - ), - status: 'Processing', - }, - 2: { - text: ( - - ), + text: '在线', status: 'Success', }, - 3: { - text: ( - - ), - status: 'Error', - }, }, }, { - title: ( - - ), + title: '上线时间', sorter: true, - dataIndex: 'updatedAt', + dataIndex: 'lastOnline', valueType: 'dateTime', + hideInSearch: true, renderFormItem: (item, { defaultRender, ...rest }, form) => { const status = form.getFieldValue('status'); if (`${status}` === '0') { return false; } if (`${status}` === '3') { - return ( - - ); + return ; } return defaultRender(item); }, }, { - title: , + title: '操作', dataIndex: 'option', valueType: 'option', render: (_, record) => [ @@ -229,14 +339,36 @@ const TableList: React.FC = () => { setCurrentRow(record); }} > - + 修改 , - - + // + // + // 查看 + // , + handleViewClick(record)}> + 查看 , + , + removeRule({ key: [record.id] })} + onConfirm={async () => { + // 调用 removeRule 函数并传递参数 + await removeRule({ key: [record.id] }); + // 调用 actionRef 的 reloadAndRest 方法刷新表格 + actionRef.current?.reloadAndRest?.(); + }} + okText="确定" + cancelText="取消" + > + + 删除 + + ], }, ]; @@ -244,78 +376,132 @@ const TableList: React.FC = () => { return ( - headerTitle={intl.formatMessage({ - id: 'pages.searchTable.title', - defaultMessage: 'Enquiry form', - })} + headerTitle="设备列表" actionRef={actionRef} - rowKey="key" + rowKey="id" search={{ - labelWidth: 120, + labelWidth: 0, }} - toolBarRender={() => [ - , - ]} + // toolBarRender={() => [ + // , + // ]} request={rule} columns={columns} + // rowSelection={{ + // onChange: (_, selectedRows) => { + // setSelectedRows(selectedRows); + // }, + // }} rowSelection={{ - onChange: (_, selectedRows) => { + selectedRowKeys, + onChange: (selectedRowKeys, selectedRows) => { + setSelectedRowKeys(selectedRowKeys); setSelectedRows(selectedRows); }, + // getCheckboxProps: (record) => ({ + // disabled: record.id === 3, // 根据条件禁用某些行的选择框 + // name: record.name, + // }), }} + toolBarRender={() => [ + + 批量设置分组 + + } + modalProps={{ + onCancel: () => console.log('取消批量设置分组'), + }} + onFinish={onFinish} + > + { + try { + const { data } = await request('https://867t766n6.zicp.fun/groups', { + method: 'GET', + }); + console.log(data); + return data.map((item) => ({ + label: item.group_name, // 分组名称作为选项文本 + value: item.id, // 分组ID作为选项值 + })); + } catch (error) { + console.error('获取分组失败:', error); + return []; + } + }} + placeholder="请选择一个分组" + /> + , + // , + // , + // , + ]} /> {selectedRowsState?.length > 0 && ( - {' '} - {selectedRowsState.length}{' '} - -    - + 已选择{' '} + + {selectedRowsState.length} + {' '} + 项    + {/* {' '} {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)}{' '} - + */} } > - )} { rules={[ { required: true, - message: ( - - ), + message: '规则名称为必填项', }, ]} width="md" @@ -348,7 +529,10 @@ const TableList: React.FC = () => { { - const success = await handleUpdate(value); + const success = await handleUpdate({ + ...value, + id: currentRow?.id, + }); if (success) { handleUpdateModalOpen(false); setCurrentRow(undefined); @@ -390,8 +574,13 @@ const TableList: React.FC = () => { /> )} + {/* 历史记录 ProTable 组件 */} + setHistoryModalVisible(false)} + /> ); }; - export default TableList; diff --git a/src/pages/TableList/list.tsx b/src/pages/TableList/list.tsx new file mode 100644 index 0000000000..43413ea2b4 --- /dev/null +++ b/src/pages/TableList/list.tsx @@ -0,0 +1,353 @@ +import { addRule, history, removeRule, updateRule } from '@/services/ant-design-pro/api'; +import { DeleteOutlined, ExportOutlined, PlusOutlined } from '@ant-design/icons'; +import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components'; +import { + FooterToolbar, + ModalForm, + PageContainer, + ProDescriptions, + ProFormText, + ProFormTextArea, + ProTable, +} from '@ant-design/pro-components'; +import '@umijs/max'; +import { Button, Drawer, Image, Modal, Popconfirm, Typography, message } from 'antd'; +import React, { useRef, useState } from 'react'; +import type { FormValueType } from './components/UpdateForm'; +import UpdateForm from './components/UpdateForm'; +import { request } from '@umijs/max'; + +const { Text, Link } = Typography; + + + +/** + * @en-US Add node + * @zh-CN 添加节点 + * @param fields + */ +const handleAdd = async (fields: API.RuleListItem) => { + const hide = message.loading('正在添加'); + try { + await addRule({ + ...fields, + }); + hide(); + message.success('Added successfully'); + return true; + } catch (error) { + hide(); + message.error('Adding failed, please try again!'); + return false; + } +}; + +/** + * @en-US Update node + * @zh-CN 更新节点 + * + * @param fields + */ +const handleUpdate = async (fields: FormValueType) => { + const hide = message.loading('Configuring'); + try { + await updateRule({ + name: fields.name, + desc: fields.desc, + key: fields.guid, + }); + hide(); + message.success('Configuration is successful'); + return true; + } catch (error) { + hide(); + message.error('Configuration failed, please try again!'); + return false; + } +}; + +/** + * Delete node + * @zh-CN 删除节点 + * + * @param selectedRows + */ +const handleRemove = async (selectedRows: API.RuleListItem[]) => { + const hide = message.loading('正在删除'); + if (!selectedRows) return true; + try { + await removeRule({ + key: selectedRows.map((row) => row.key), + }); + hide(); + message.success('删除成功,即将刷新'); + return true; + } catch (error) { + hide(); + message.error('删除失败,请重试'); + return false; + } +}; + +const handleExport = async () => { + try { + const response = await request('https://867t766n6.zicp.fun/api/exportAccount', { + responseType: 'blob', + }); + const blob = new Blob([response], { type: 'text/csv' }); // 使用 response 而不是 response.data + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', 'export.csv'); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); // 移除创建的链接 + } catch (error) { + console.error('Error exporting file:', error); + } +}; + +const TableList: React.FC = () => { + /** + * @en-US Pop-up window of new window + * @zh-CN 新建窗口的弹窗 + * */ + const [createModalOpen, handleModalOpen] = useState(false); + /** + * @en-US The pop-up window of the distribution update window + * @zh-CN 分布更新窗口的弹窗 + * */ + const [updateModalOpen, handleUpdateModalOpen] = useState(false); + const [showDetail, setShowDetail] = useState(false); + const actionRef = useRef(); + const [currentRow, setCurrentRow] = useState(); + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + const [selectedRowsState, setSelectedRows] = useState([]); + const [historyModalVisible, setHistoryModalVisible] = useState(false); + const handleViewClick = (record) => { + setCurrentRow(record); + setHistoryModalVisible(true); + }; + + /** + * @en-US International configuration + * @zh-CN 国际化配置 + * */ + + const columns: ProColumns[] = [ + { + title: '名称', + dataIndex: 'user_name', + render: (dom, entity) => { + return ( + <> + {/* { + setCurrentRow(entity); + setShowDetail(true); + }} + > + {dom} + */} + {dom} +
{entity.name}
+ + ); + }, + }, + { + title: '类型', + dataIndex: 'format', + valueType: 'select', + valueEnum: { + CF_TEXT: { + text: '文本', + }, + CF_BITMAP: { + text: '图片', + }, + }, + }, + { + title: '内容', + dataIndex: 'content', + sorter: true, + hideInForm: true, + width: '60%', + }, + { + title: '地址', + dataIndex: 'detected_address', + hideInSearch: true, + }, + { + title: '时间', + sorter: true, + dataIndex: 'timestamp', + valueType: 'dateTime', + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => [ + { + await handleRemove(record.id); // 直接传递代理ID + actionRef.current?.reload(); + }} + okText="确定" + cancelText="取消" + > + , + ]} + request={history} + columns={columns} + rowSelection={{ + preserveSelectedRowKeys: true, + selectedRowKeys, + onChange: (keys, selectedRows) => { + setSelectedRowKeys(keys); + setSelectedRows(selectedRows); + }, + }} + /> + {selectedRowsState?.length > 0 && ( + + 已选择{' '} + + {selectedRowsState.length} + {' '} + 项    + {/* + {' '} + {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)}{' '} + + */} + + } + > + + + )} + { + const success = await handleAdd(value as API.RuleListItem); + if (success) { + handleModalOpen(false); + if (actionRef.current) { + actionRef.current.reload(); + } + } + }} + > + + + + { + const success = await handleUpdate({ + ...value, + guid: currentRow?.guid, + }); + if (success) { + handleUpdateModalOpen(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + } + }} + onCancel={() => { + handleUpdateModalOpen(false); + if (!showDetail) { + setCurrentRow(undefined); + } + }} + updateModalOpen={updateModalOpen} + values={currentRow || {}} + /> + + { + setCurrentRow(undefined); + setShowDetail(false); + }} + closable={false} + > + {currentRow?.name && ( + + column={2} + title={currentRow?.name} + request={async () => ({ + data: currentRow || {}, + })} + params={{ + id: currentRow?.name, + }} + columns={columns as ProDescriptionsItemProps[]} + /> + )} + +
+ ); +}; +export default TableList; diff --git a/src/pages/User/Login/index.tsx b/src/pages/User/Login/index.tsx index 0764acfadd..6b3d43630b 100644 --- a/src/pages/User/Login/index.tsx +++ b/src/pages/User/Login/index.tsx @@ -15,13 +15,12 @@ import { ProFormCheckbox, ProFormText, } from '@ant-design/pro-components'; -import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max'; -import { Alert, message, Tabs } from 'antd'; -import Settings from '../../../../config/defaultSettings'; +import { Helmet, history, useModel } from '@umijs/max'; +import { Alert, Tabs, message } from 'antd'; +import { createStyles } from 'antd-style'; import React, { useState } from 'react'; import { flushSync } from 'react-dom'; -import { createStyles } from 'antd-style'; - +import Settings from '../../../../config/defaultSettings'; const useStyles = createStyles(({ token }) => { return { action: { @@ -57,10 +56,8 @@ const useStyles = createStyles(({ token }) => { }, }; }); - const ActionIcons = () => { const { styles } = useStyles(); - return ( <> @@ -69,17 +66,10 @@ const ActionIcons = () => { ); }; - const Lang = () => { const { styles } = useStyles(); - - return ( -
- {SelectLang && } -
- ); + return; }; - const LoginMessage: React.FC<{ content: string; }> = ({ content }) => { @@ -94,14 +84,11 @@ const LoginMessage: React.FC<{ /> ); }; - const Login: React.FC = () => { const [userLoginState, setUserLoginState] = useState({}); const [type, setType] = useState('account'); const { initialState, setInitialState } = useModel('@@initialState'); const { styles } = useStyles(); - const intl = useIntl(); - const fetchUserInfo = async () => { const userInfo = await initialState?.fetchUserInfo?.(); if (userInfo) { @@ -113,16 +100,19 @@ const Login: React.FC = () => { }); } }; - const handleSubmit = async (values: API.LoginParams) => { try { // 登录 - const msg = await login({ ...values, type }); + const msg = await login({ + ...values, + type, + }); if (msg.status === 'ok') { - const defaultLoginSuccessMessage = intl.formatMessage({ - id: 'pages.login.success', - defaultMessage: '登录成功!', - }); + // 假设令牌存储在 msg 中,确保替换 msg.token 为实际令牌字段 + const token = msg.token; + localStorage.setItem('authToken', token || ''); + + const defaultLoginSuccessMessage = '登录成功!'; message.success(defaultLoginSuccessMessage); await fetchUserInfo(); const urlParams = new URL(window.location.href).searchParams; @@ -133,25 +123,17 @@ const Login: React.FC = () => { // 如果失败去设置用户错误信息 setUserLoginState(msg); } catch (error) { - const defaultLoginFailureMessage = intl.formatMessage({ - id: 'pages.login.failure', - defaultMessage: '登录失败,请重试!', - }); + const defaultLoginFailureMessage = '登录失败,请重试!'; console.log(error); message.error(defaultLoginFailureMessage); } }; const { status, type: loginType } = userLoginState; - return (
- {intl.formatMessage({ - id: 'menu.login', - defaultMessage: '登录页', - })} - - {Settings.title} + {'登录'}- {Settings.title} @@ -167,19 +149,12 @@ const Login: React.FC = () => { maxWidth: '75vw', }} logo={logo} - title="Ant Design" - subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })} + title="管理端" + subTitle="舟窗尽落,清风徐来" initialValues={{ autoLogin: true, }} - actions={[ - , - , - ]} + actions={['其他登录方式 :', ]} onFinish={async (values) => { await handleSubmit(values as API.LoginParams); }} @@ -191,28 +166,17 @@ const Login: React.FC = () => { items={[ { key: 'account', - label: intl.formatMessage({ - id: 'pages.login.accountLogin.tab', - defaultMessage: '账户密码登录', - }), + label: '账户密码登录', }, { key: 'mobile', - label: intl.formatMessage({ - id: 'pages.login.phoneLogin.tab', - defaultMessage: '手机号登录', - }), + label: '手机号登录', }, ]} /> {status === 'error' && loginType === 'account' && ( - + )} {type === 'account' && ( <> @@ -222,19 +186,11 @@ const Login: React.FC = () => { size: 'large', prefix: , }} - placeholder={intl.formatMessage({ - id: 'pages.login.username.placeholder', - defaultMessage: '用户名: admin or user', - })} + placeholder="用户名" rules={[ { required: true, - message: ( - - ), + message: '用户名是必填项!', }, ]} /> @@ -244,19 +200,11 @@ const Login: React.FC = () => { size: 'large', prefix: , }} - placeholder={intl.formatMessage({ - id: 'pages.login.password.placeholder', - defaultMessage: '密码: ant.design', - })} + placeholder="密码" rules={[ { required: true, - message: ( - - ), + message: '密码是必填项!', }, ]} /> @@ -272,28 +220,15 @@ const Login: React.FC = () => { prefix: , }} name="mobile" - placeholder={intl.formatMessage({ - id: 'pages.login.phoneNumber.placeholder', - defaultMessage: '手机号', - })} + placeholder={'请输入手机号!'} rules={[ { required: true, - message: ( - - ), + message: '手机号是必填项!', }, { pattern: /^1\d{10}$/, - message: ( - - ), + message: '不合法的手机号!', }, ]} /> @@ -305,32 +240,18 @@ const Login: React.FC = () => { captchaProps={{ size: 'large', }} - placeholder={intl.formatMessage({ - id: 'pages.login.captcha.placeholder', - defaultMessage: '请输入验证码', - })} + placeholder={'请输入验证码!'} captchaTextRender={(timing, count) => { if (timing) { - return `${count} ${intl.formatMessage({ - id: 'pages.getCaptchaSecondText', - defaultMessage: '获取验证码', - })}`; + return `${count} ${'秒后重新获取'}`; } - return intl.formatMessage({ - id: 'pages.login.phoneLogin.getVerificationCode', - defaultMessage: '获取验证码', - }); + return '获取验证码'; }} name="captcha" rules={[ { required: true, - message: ( - - ), + message: '验证码是必填项!', }, ]} onGetCaptcha={async (phone) => { @@ -351,14 +272,14 @@ const Login: React.FC = () => { }} > - + 自动登录 - + 忘记密码 ?
@@ -367,5 +288,4 @@ const Login: React.FC = () => { ); }; - export default Login; diff --git a/src/pages/Welcome.tsx b/src/pages/Welcome.tsx index d0c49f7a1c..244f5b44ca 100644 --- a/src/pages/Welcome.tsx +++ b/src/pages/Welcome.tsx @@ -88,75 +88,7 @@ const Welcome: React.FC = () => { const { initialState } = useModel('@@initialState'); return ( - -
-
- 欢迎使用 Ant Design Pro -
-

- Ant Design Pro 是一个整合了 umi,Ant Design 和 ProComponents - 的脚手架方案。致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。 -

-
- - - -
-
-
+
); }; diff --git a/src/pages/dashboard.tsx b/src/pages/dashboard.tsx new file mode 100644 index 0000000000..2f896f29eb --- /dev/null +++ b/src/pages/dashboard.tsx @@ -0,0 +1,84 @@ +import { fetchStats } from '@/services/ant-design-pro/api'; +import React, { useEffect, useState } from 'react'; +import { ProCard, StatisticCard } from '@ant-design/pro-components'; +import { Button, message } from 'antd'; +import axios from 'axios'; + +interface StatsData { + online: number; + offline: number; + total: number; +} + +const StatsPage: React.FC = () => { + const [stats, setStats] = useState(null); + const [loading, setLoading] = useState(false); + + // 通过 request 属性模拟远程请求 + // const fetchStats = async () => { + // try { + // setLoading(true); + // const response = await axios.get('https://867t766n6.zicp.fun/computers/stats'); // 更新为实际的 API 地址 + // setStats(response.data); + // setLoading(false); + // } catch (error) { + // message.error('无法获取统计数据,请稍后再试。'); + // setLoading(false); + // } + // }; + + // 获取统计数据 + const getStats = async () => { + setLoading(true); + try { + const response = await fetchStats(); + setStats(response); + } catch (error) { + message.error('无法获取统计数据,请稍后再试。'); + } finally { + setLoading(false); + } + }; + + // 初始化时获取统计数据 + useEffect(() => { + getStats(); + }, []); + + return ( +
+ + + + + + +
+ ); +}; + +export default StatsPage; diff --git a/src/services/ant-design-pro/api.ts b/src/services/ant-design-pro/api.ts index b42bdfcffa..3f65495ee0 100644 --- a/src/services/ant-design-pro/api.ts +++ b/src/services/ant-design-pro/api.ts @@ -6,7 +6,7 @@ import { request } from '@umijs/max'; export async function currentUser(options?: { [key: string]: any }) { return request<{ data: API.CurrentUser; - }>('/api/currentUser', { + }>('https://867t766n6.zicp.fun/api/currentUser', { method: 'GET', ...(options || {}), }); @@ -14,7 +14,7 @@ export async function currentUser(options?: { [key: string]: any }) { /** 退出登录接口 POST /api/login/outLogin */ export async function outLogin(options?: { [key: string]: any }) { - return request>('/api/login/outLogin', { + return request>('https://867t766n6.zicp.fun/api/login/outLogin', { method: 'POST', ...(options || {}), }); @@ -22,7 +22,7 @@ export async function outLogin(options?: { [key: string]: any }) { /** 登录接口 POST /api/login/account */ export async function login(body: API.LoginParams, options?: { [key: string]: any }) { - return request('/api/login/account', { + return request('https://867t766n6.zicp.fun/api/login/account2', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -51,7 +51,7 @@ export async function rule( }, options?: { [key: string]: any }, ) { - return request('/api/rule', { + return request('https://867t766n6.zicp.fun/online', { method: 'GET', params: { ...params, @@ -62,7 +62,7 @@ export async function rule( /** 更新规则 PUT /api/rule */ export async function updateRule(options?: { [key: string]: any }) { - return request('/api/rule', { + return request('https://867t766n6.zicp.fun/api/rule', { method: 'POST', data:{ method: 'update', @@ -84,7 +84,7 @@ export async function addRule(options?: { [key: string]: any }) { /** 删除规则 DELETE /api/rule */ export async function removeRule(options?: { [key: string]: any }) { - return request>('/api/rule', { + return request>('https://867t766n6.zicp.fun/api/rule', { method: 'POST', data:{ method: 'delete', @@ -92,3 +92,31 @@ export async function removeRule(options?: { [key: string]: any }) { } }); } + +/** 获取规则列表 GET /api/rule */ +export async function history( + params: { + // query + /** 当前的页码 */ + current?: number; + /** 页面的容量 */ + pageSize?: number; + }, + options?: { [key: string]: any }, +) { + return request('https://867t766n6.zicp.fun/history', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + + +// 获取设备统计数据 +export async function fetchStats() { + return request('https://867t766n6.zicp.fun/computers/stats', { + method: 'GET', + }); +} \ No newline at end of file diff --git a/src/services/ant-design-pro/typings.d.ts b/src/services/ant-design-pro/typings.d.ts index 13e5a680c4..c1e5aa6dcf 100644 --- a/src/services/ant-design-pro/typings.d.ts +++ b/src/services/ant-design-pro/typings.d.ts @@ -27,6 +27,7 @@ declare namespace API { status?: string; type?: string; currentAuthority?: string; + token?: string; }; type PageParams = { @@ -36,12 +37,15 @@ declare namespace API { type RuleListItem = { key?: number; + id?: number; + guid?: string; disabled?: boolean; href?: string; avatar?: string; name?: string; owner?: string; desc?: string; + group_id?: number; callNo?: number; status?: number; updatedAt?: string;