diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml new file mode 100644 index 0000000..8d902f1 --- /dev/null +++ b/.github/workflows/push.yml @@ -0,0 +1,51 @@ +name: 部署api前端项目 + +# 只有master分支发生push主分支或pull_request关闭后事件时,才会触发workflow +on: + push: + branches: + # 你的主分支名 + - master + pull_request: + branches: + # 你的主分支名 + - master + types: + - closed +jobs: + build: + # runs-on 指定job任务运行所需要的虚拟机环境(必填字段) + runs-on: ubuntu-latest + steps: + # 获取源码 + - name: 迁出代码 + # 使用action库 actions/checkout获取源码 + uses: actions/checkout@v3 + + # 安装Node10 + - name: 安装node.js + # 使用action库 actions/setup-node安装node + uses: actions/setup-node@v3 + with: + node-version: '16.x' + + # 安装依赖 + - name: 安装依赖 + run: npm install + + # 打包 + - name: 打包 + run: npm run build + + # 上传阿里云 + - name: 发布项目 + uses: easingthemes/ssh-deploy@main + with: + SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} + ARGS: "-rlgoDzvc -i --delete" + SOURCE: "dist/" + REMOTE_HOST: ${{ secrets.REMOTE_HOST }} + REMOTE_USER: ${{ secrets.REMOTE_USER }} + TARGET: ${{ secrets.REMOTE_TARGET }} + # 排除项 + EXCLUDE: "/dist/, /node_modules/" diff --git a/config/routes.ts b/config/routes.ts index 8377c40..ceb5ee7 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -1,8 +1,12 @@ export default [ + { path: '/', name: '主页',icon: 'smile' ,component: './Index' }, + { path: '/interface_info/:id', name: '查看接口',icon: 'smile' ,component: './InterfaceInfo', hideInMenu: true}, { path: '/user', layout: false, - routes: [{ name: '登录', path: '/user/login', component: './User/Login' }], + routes: [ + { name: '登录', path: '/user/login', component: './User/Login' } + ], }, // { path: '/welcome', name: '欢迎', icon: 'smile', component: './Welcome' }, { @@ -12,10 +16,10 @@ export default [ // 权限控制可以去看 and design pro 的官方文档,不用纠结为什么这么写,就是人家设定的规则而已 access: 'canAdmin', routes: [ - { name: '接口管理', icon: 'table', path: '/admin/interface_info', component: './InterfaceInfo' }, + { name: '接口管理', icon: 'table', path: '/admin/interface_info', component: './Admin/InterfaceInfo' }, + { name: '接口分析', icon: 'analysis', path: '/admin/interface_analysis', component: './Admin/InterfaceAnalysis' } ], }, - // { path: '/', redirect: '/welcome' }, { path: '*', layout: false, component: './404' }, ]; diff --git a/package.json b/package.json index 983f4a7..2a65c3b 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,15 @@ }, "lint-staged": { "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", - "**/*.{js,jsx,tsx,ts,less,md,json}": ["prettier --write"] + "**/*.{js,jsx,tsx,ts,less,md,json}": [ + "prettier --write" + ] }, - "browserslist": ["> 1%", "last 2 versions", "not ie <= 10"], + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 10" + ], "dependencies": { "@ant-design/icons": "^4.8.1", "@ant-design/pro-components": "^2.6.48", @@ -46,6 +52,8 @@ "antd": "^5.13.2", "antd-style": "^3.6.1", "classnames": "^2.5.1", + "echarts": "^5.5.0", + "echarts-for-react": "^3.0.2", "lodash": "^4.17.21", "moment": "^2.30.1", "omit.js": "^2.0.2", @@ -87,5 +95,7 @@ "umi-presets-pro": "^2.0.3", "umi-serve": "^1.9.11" }, - "engines": { "node": ">=12.0.0" } + "engines": { + "node": ">=12.0.0" + } } diff --git a/src/pages/Admin.tsx b/src/pages/Admin.tsx deleted file mode 100644 index e0a1aae..0000000 --- a/src/pages/Admin.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { HeartTwoTone, SmileTwoTone } from '@ant-design/icons'; -import { PageContainer } from '@ant-design/pro-components'; -import '@umijs/max'; -import { Alert, Card, Typography } from 'antd'; -import React from 'react'; -const Admin: React.FC = () => { - return ( - - - - - Ant Design Pro You - - - - Want to add more pages? Please refer to{' '} - - use block - - 。 - - - ); -}; -export default Admin; diff --git a/src/pages/Admin/InterfaceAnalysis/index.tsx b/src/pages/Admin/InterfaceAnalysis/index.tsx new file mode 100644 index 0000000..870c88f --- /dev/null +++ b/src/pages/Admin/InterfaceAnalysis/index.tsx @@ -0,0 +1,71 @@ +import { PageContainer } from '@ant-design/pro-components'; +import '@umijs/max'; +import React, {useEffect, useState} from 'react'; +import ReactECharts from 'echarts-for-react'; +import {listTopInvokeInterfaceInfoUsingGet} from "@/services/linger-api-backend/analysisController"; + +/** + * 接口分析 + * @constructor + */ +const InterfaceAnalysis: React.FC = () => { + + const [data, setData] = useState([]); + + useEffect(() => { + try { + listTopInvokeInterfaceInfoUsingGet().then(res => { + if (res.data) { + setData(res.data); + } + }) + } catch (e: any) { + + } + // todo 从远程获取数据 + }, []) + + // 映射:{ value: 1048, name: 'Search Engine' }, + const chartData = data.map(item => { + return { + value: item.totalNum, + name: item.name, + } + }) + + const option = { + title: { + text: '调用次数最多的接口TOP3', + left: 'center', + }, + tooltip: { + trigger: 'item', + }, + legend: { + orient: 'vertical', + left: 'left', + }, + series: [ + { + name: 'Access From', + type: 'pie', + radius: '50%', + data: chartData, + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)', + }, + }, + }, + ], + }; + + return ( + + + + ); +}; +export default InterfaceAnalysis; diff --git a/src/pages/InterfaceInfo/components/CreateModal.tsx b/src/pages/Admin/InterfaceInfo/components/CreateModal.tsx similarity index 100% rename from src/pages/InterfaceInfo/components/CreateModal.tsx rename to src/pages/Admin/InterfaceInfo/components/CreateModal.tsx diff --git a/src/pages/InterfaceInfo/components/UpdateModal.tsx b/src/pages/Admin/InterfaceInfo/components/UpdateModal.tsx similarity index 100% rename from src/pages/InterfaceInfo/components/UpdateModal.tsx rename to src/pages/Admin/InterfaceInfo/components/UpdateModal.tsx diff --git a/src/pages/Admin/InterfaceInfo/index.tsx b/src/pages/Admin/InterfaceInfo/index.tsx new file mode 100644 index 0000000..f8983d5 --- /dev/null +++ b/src/pages/Admin/InterfaceInfo/index.tsx @@ -0,0 +1,477 @@ +import {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, message} from 'antd'; +import React, {useRef, useState} from 'react'; +import { + addInterfaceInfoUsingPost, + deleteInterfaceInfoUsingPost, + listInterfaceInfoByPageUsingGet, + offlineInterfaceInfoUsingPost, + onlineInterfaceInfoUsingPost, + updateInterfaceInfoUsingPost +} from '@/services/linger-api-backend/interfaceInfoController'; +import CreateModal from "@/pages/Admin/InterfaceInfo/components/CreateModal"; +import UpdateModal from "@/pages/Admin/InterfaceInfo/components/UpdateModal"; + + +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, handleUpdateFormOpen] = useState(false); + const [showDetail, setShowDetail] = useState(false); + const actionRef = useRef(); + const [currentRow, setCurrentRow] = useState(); + const [selectedRowsState, setSelectedRows] = useState([]); + /** + * @en-US Add node + * @zh-CN 添加节点 + * @param fields + */ + const handleAdd = async (fields: API.InterfaceInfo) => { + const hide = message.loading('正在添加'); + try { + await addInterfaceInfoUsingPost({ + ...fields, + }); + hide(); + message.success('创建成功'); + handleUpdateFormOpen(false); + return true; + } catch (error:any) { + hide(); + message.error('创建失败,' + error.message); + return false; + } + }; + + /** + * @en-US Update node + * @zh-CN 更新节点 + * + * @param fields + */ + const handleUpdate = async (fields: API.InterfaceInfo) => { + // 如果没有选中,直接返回 + if (!currentRow){ + return; + } + const hide = message.loading('修改中'); + try { + await updateInterfaceInfoUsingPost({ + id:currentRow.id, + ...fields, + }) + hide(); + message.success('操作成功'); + return true; + } catch (error:any) { + hide(); + message.error('操作失败,' + error.message); + return false; + } + }; + + /** + * 发布接口 + * + * @param record + */ + const handleOnline = async (record: API.IdRequest) => { + // 显示正在发布的加载提示 + const hide = message.loading('发布中'); + // 如果接口数据为空,直接返回true + if (!record) return true; + try { + // 调用发布接口的POST请求方法 + await onlineInterfaceInfoUsingPost({ + // 传递接口的id参数 + id: record.id + }); + hide(); + // 显示操作成功的提示信息 + message.success('操作成功'); + // 重新加载数据 + actionRef.current?.reload(); + // 返回true表示发布成功 + return true; + } catch (error: any) { + hide(); + // 显示操作失败的错误提示信息 + message.error('操作失败,' + error.message); + // 返回false表示发布失败 + return false; + } + }; + + /** + * 下线接口 + * + * @param record + */ + const handleOffline = async (record: API.IdRequest) => { + // 显示正在下线的加载提示 + const hide = message.loading('发布中'); + // 如果接口数据为空,直接返回true + if (!record) return true; + try { + // 调用下线接口的POST请求方法 + await offlineInterfaceInfoUsingPost({ + // 传递接口的id参数 + id: record.id + }); + hide(); + // 显示操作成功的提示信息 + message.success('操作成功'); + // 重新加载数据 + actionRef.current?.reload(); + // 返回true表示下线成功 + return true; + } catch (error: any) { + hide(); + // 显示操作失败的错误提示信息 + message.error('操作失败,' + error.message); + // 返回false表示下线失败 + return false; + } + }; + + /** + * Delete node + * @zh-CN 删除节点 + * + * @param selectedRows + */ + const handleRemove = async (record: API.InterfaceInfo) => { + const hide = message.loading('正在删除'); + if (!record) return true; + try { + await deleteInterfaceInfoUsingPost({ + id: record.id, + }); + hide(); + message.success('删除成功'); + // 删除成功自动刷新表单 + actionRef.current?.reload(); + return true; + } catch (error: any) { + hide(); + message.error('删除失败,' + error.message); + return false; + } + }; + + /** + * @en-US International configuration + * @zh-CN 国际化配置 + * */ + + const columns: ProColumns[] = [ + { + title: 'id', + dataIndex: 'id', + valueType: 'index', + }, + { + title: '接口名称', + dataIndex: 'name', + valueType: 'text', + formItemProps:{ + rules:[{ + // 必填项 + required: true, + // 不设置提示信息,就默认提示‘请输入’ + title + // message:'阿里巴巴', + }] + } + }, + { + title: '描述', + dataIndex: 'description', + valueType: 'textarea', + }, + { + title: '请求方法', + dataIndex: 'method', + valueType: 'text', + }, + { + title: 'url', + dataIndex: 'url', + valueType: 'text', + }, + { + title: '请求参数', + dataIndex: 'requestParams', + valueType: 'jsonCode', + }, + { + title: '请求头', + dataIndex: 'requestHeader', + valueType: 'jsonCode', + }, + { + title: '响应头', + dataIndex: 'responseHeader', + valueType: 'jsonCode', + }, + { + title: '状态', + dataIndex: 'status', + hideInForm: true, + valueEnum: { + 0: { + text: '关闭', + status: 'Default', + }, + 1 : { + text: '开启', + status: 'Processing', + }, + }, + }, + { + title: '创建时间', + dataIndex: 'createTime', + valueType: 'dateTime', + hideInForm: true, + }, + { + title: '更新时间', + dataIndex: 'updateTime', + valueType: 'dateTime', + hideInForm: true, + }, + { + title: '操作', + dataIndex: 'option', + valueType: 'option', + render: (_, record) => [ + { + handleUpdateFormOpen(true); + setCurrentRow(record); + }} + > + 修改 + , + record.status === 0 ? + { + handleOnline(record); + }} + > + 发布 + :null, + record.status === 1? + { + handleOffline(record); + }} + > + 下线 + :null, + { + handleRemove(record); + }} + > + 删除 + + ], + }, + ]; + return ( + + + headerTitle={'查询表格'} + actionRef={actionRef} + rowKey="key" + search={{ + labelWidth: 120, + }} + toolBarRender={() => [ + { + handleModalOpen(true); + }} + > + 新建 + , + ]} + request={async (params, sort: Record, filter: Record) => { + const res: any = await listInterfaceInfoByPageUsingGet({ + ...params + }) + // 如果后端请求给你返回了接口信息 + if (res?.data) { + // 返回一个包含数据、成功状态和总数的对象 + return { + data: res?.data.records || [], + success: true, + total: res?.data.total || 0, + }; + } else { + // 如果数据不存在,返回一个空数组,失败状态和零总数 + return { + data: [], + success: false, + total: 0, + }; + } + }} + columns={columns} + rowSelection={{ + onChange: (_, selectedRows) => { + setSelectedRows(selectedRows); + }, + }} + /> + {selectedRowsState?.length > 0 && ( + + 已选择{' '} + + {selectedRowsState.length} + {' '} + 项 + + 服务调用次数总计 {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)} 万 + + + } + > + { + await handleRemove(selectedRowsState); + setSelectedRows([]); + actionRef.current?.reloadAndRest?.(); + }} + > + 批量删除 + + 批量审批 + + )} + { + const success = await handleAdd(value as API.RuleListItem); + if (success) { + handleModalOpen(false); + if (actionRef.current) { + actionRef.current.reload(); + } + } + }} + > + + + + { + const success = await handleUpdate(value); + if (success) { + handleUpdateFormOpen(false); + setCurrentRow(undefined); + if (actionRef.current) { + actionRef.current.reload(); + } + } + }} + onCancel={() => { + handleUpdateFormOpen(false); + if (!showDetail) { + setCurrentRow(undefined); + } + }} + visible={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[]} + /> + )} + + {/* 创建一个CreateModal组件,用于在点击新增按钮时弹出 */} + { + handleModalOpen(false); + }} + // 当用户点击提交按钮之后,调用handleAdd函数处理提交的数据,去请求后端添加数据(这里的报错不用管,可能里面组件的属性和外层的不一致) + onSubmit={(values) => { + handleAdd(values); + }} + // 根据更新窗口的值决定模态窗口是否显示 + visible={createModalOpen} + /> + + ); +}; +export default TableList; diff --git a/src/pages/InterfaceInfo/index.tsx b/src/pages/InterfaceInfo/index.tsx index ef92d27..75704c9 100644 --- a/src/pages/InterfaceInfo/index.tsx +++ b/src/pages/InterfaceInfo/index.tsx @@ -1,384 +1,120 @@ -import {removeRule} from '@/services/ant-design-pro/api'; -import {PlusOutlined} from '@ant-design/icons'; -import type {ActionType, ProColumns, ProDescriptionsItemProps} from '@ant-design/pro-components'; +import {PageContainer} from '@ant-design/pro-components'; +import {Button, Descriptions, Divider, Form, Input, message} from 'antd'; +import React, {useEffect, useState} from 'react'; +import {useParams} from 'react-router'; +import Card from "@ant-design/pro-card/es/components/Card"; import { - FooterToolbar, - ModalForm, - PageContainer, - ProDescriptions, - ProFormText, - ProFormTextArea, - ProTable, -} from '@ant-design/pro-components'; -import '@umijs/max'; -import {Button, Drawer, message} from 'antd'; -import React, {useRef, useState} from 'react'; -import { - addInterfaceInfoUsingPost, deleteInterfaceInfoUsingPost, - listInterfaceInfoByPageUsingGet, - updateInterfaceInfoUsingPost -} from '@/services/linger-api-backend/interfaceInfoController'; -import CreateModal from "@/pages/InterfaceInfo/components/CreateModal"; -import UpdateModal from "@/pages/InterfaceInfo/components/UpdateModal"; + getInterfaceInfoByIdUsingGet, + invokeInterfaceInfoUsingPost +} from "@/services/linger-api-backend/interfaceInfoController"; +/** + * 主页 + * @constructor + */ +const Index: React.FC = () => { + // 定义状态和钩子函数 + const [loading, setLoading] = useState(false); + const [data, setData] = useState(); + const [invokeRes, setInvokeRes] = useState(); + const [invokeLoading, setInvokeLoading] = useState(false); -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, handleUpdateFormOpen] = useState(false); - const [showDetail, setShowDetail] = useState(false); - const actionRef = useRef(); - const [currentRow, setCurrentRow] = useState(); - const [selectedRowsState, setSelectedRows] = useState([]); - /** - * @en-US Add node - * @zh-CN 添加节点 - * @param fields - */ - const handleAdd = async (fields: API.InterfaceInfo) => { - const hide = message.loading('正在添加'); - try { - await addInterfaceInfoUsingPost({ - ...fields, - }); - hide(); - message.success('创建成功'); - handleUpdateFormOpen(false); - return true; - } catch (error:any) { - hide(); - message.error('创建失败,' + error.message); - return false; - } - }; + // 使用 useParams 钩子函数获取动态路由参数 + const params = useParams(); - /** - * @en-US Update node - * @zh-CN 更新节点 - * - * @param fields - */ - const handleUpdate = async (fields: API.InterfaceInfo) => { - // 如果没有选中,直接返回 - if (!currentRow){ + const loadData = async () => { + // 检查动态路由参数是否存在 + if (!params.id) { + message.error('参数不存在'); return; } - const hide = message.loading('修改中'); + setLoading(true); try { - await updateInterfaceInfoUsingPost({ - id:currentRow.id, - ...fields, - }) - hide(); - message.success('操作成功'); - return true; - } catch (error:any) { - hide(); - message.error('操作失败,' + error.message); - return false; + // 发起请求获取接口信息,接受一个包含 id 参数的对象作为参数 + const res = await getInterfaceInfoByIdUsingGet({ + id: Number(params.id), + }); + // 将获取到的接口信息设置到 data 状态中 + setData(res.data); + } catch (error: any) { + // 请求失败处理 + message.error('请求失败,' + error.message); } + // 请求完成,设置 loading 状态为 false,表示请求结束,可以停止加载状态的显示 + setLoading(false); }; - /** - * Delete node - * @zh-CN 删除节点 - * - * @param selectedRows - */ - const handleRemove = async (record: API.InterfaceInfo) => { - const hide = message.loading('正在删除'); - if (!record) return true; + useEffect(() => { + loadData(); + }, []); + + const onFinish = async (values: any) => { + // 检查是否存在接口id + if (!params.id) { + message.error('接口不存在'); + return; + } + //在开始调用接口之前,将invokeLoading设置为true,表示正在加载中 + setInvokeLoading(true); try { - await deleteInterfaceInfoUsingPost({ - id: record.id, + // 发起接口调用请求,传入一个对象作为参数,这个对象包含了id和values的属性, + // 其中,id 是从 params 中获取的,而 values 是函数的参数 + const res = await invokeInterfaceInfoUsingPost({ + id: params.id, + ...values, }); - hide(); - message.success('删除成功'); - // 删除成功自动刷新表单 - actionRef.current?.reload(); - return true; + //将接口调用的结果(res.data)更新到invokeRes状态变量中 + setInvokeRes(res.data); + message.success('请求成功'); } catch (error: any) { - hide(); - message.error('删除失败,' + error.message); - return false; + message.error('操作失败,' + error.message); } + //无论成功或失败,最后将invokeLoading设置为false,表示加载完成 + setInvokeLoading(false); }; - /** - * @en-US International configuration - * @zh-CN 国际化配置 - * */ - - const columns: ProColumns[] = [ - { - title: 'id', - dataIndex: 'id', - valueType: 'index', - }, - { - title: '接口名称', - dataIndex: 'name', - valueType: 'text', - formItemProps:{ - rules:[{ - // 必填项 - required: true, - // 不设置提示信息,就默认提示‘请输入’ + title - // message:'阿里巴巴', - }] - } - }, - { - title: '描述', - dataIndex: 'description', - valueType: 'textarea', - }, - { - title: '请求方法', - dataIndex: 'method', - valueType: 'text', - }, - { - title: 'url', - dataIndex: 'url', - valueType: 'text', - }, - { - title: '请求头', - dataIndex: 'requestHeader', - valueType: 'textarea', - }, - { - title: '响应头', - dataIndex: 'responseHeader', - valueType: 'textarea', - }, - { - title: '状态', - dataIndex: 'status', - hideInForm: true, - valueEnum: { - 0: { - text: '关闭', - status: 'Default', - }, - 1 : { - text: '开启', - status: 'Processing', - }, - }, - }, - { - title: '创建时间', - dataIndex: 'createTime', - valueType: 'dateTime', - hideInForm: true, - }, - { - title: '更新时间', - dataIndex: 'updateTime', - valueType: 'dateTime', - hideInForm: true, - }, - { - title: '操作', - dataIndex: 'option', - valueType: 'option', - render: (_, record) => [ - { - handleUpdateFormOpen(true); - setCurrentRow(record); - }} - > - 修改 - , - { - handleRemove(record); - }} - > - 删除 - - ], - }, - ]; return ( - - - headerTitle={'查询表格'} - actionRef={actionRef} - rowKey="key" - search={{ - labelWidth: 120, - }} - toolBarRender={() => [ - { - handleModalOpen(true); - }} - > - 新建 - , - ]} - request={async (params, sort: Record, filter: Record) => { - const res: any = await listInterfaceInfoByPageUsingGet({ - ...params - }) - // 如果后端请求给你返回了接口信息 - if (res?.data) { - // 返回一个包含数据、成功状态和总数的对象 - return { - data: res?.data.records || [], - success: true, - total: res?.data.total || 0, - }; - } else { - // 如果数据不存在,返回一个空数组,失败状态和零总数 - return { - data: [], - success: false, - total: 0, - }; - } - }} - columns={columns} - rowSelection={{ - onChange: (_, selectedRows) => { - setSelectedRows(selectedRows); - }, - }} - /> - {selectedRowsState?.length > 0 && ( - - 已选择{' '} - - {selectedRowsState.length} - {' '} - 项 - - 服务调用次数总计 {selectedRowsState.reduce((pre, item) => pre + item.callNo!, 0)} 万 - - - } - > - { - await handleRemove(selectedRowsState); - setSelectedRows([]); - actionRef.current?.reloadAndRest?.(); - }} - > - 批量删除 - - 批量审批 - - )} - { - const success = await handleAdd(value as API.RuleListItem); - if (success) { - handleModalOpen(false); - if (actionRef.current) { - actionRef.current.reload(); - } - } - }} - > - - - - { - const success = await handleUpdate(value); - if (success) { - handleUpdateFormOpen(false); - setCurrentRow(undefined); - if (actionRef.current) { - actionRef.current.reload(); - } - } - }} - onCancel={() => { - handleUpdateFormOpen(false); - if (!showDetail) { - setCurrentRow(undefined); - } - }} - visible={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[]} - /> + + + {data ? ( + + {data.status ? '开启' : '关闭'} + {data.description} + {data.url} + {data.method} + {data.requestParams} + {data.requestHeader} + {data.responseHeader} + {data.createTime} + {data.updateTime} + + ) : ( + <>接口不存在> )} - - {/* 创建一个CreateModal组件,用于在点击新增按钮时弹出 */} - { - handleModalOpen(false); - }} - // 当用户点击提交按钮之后,调用handleAdd函数处理提交的数据,去请求后端添加数据(这里的报错不用管,可能里面组件的属性和外层的不一致) - onSubmit={(values) => { - handleAdd(values); - }} - // 根据更新窗口的值决定模态窗口是否显示 - visible={createModalOpen} - /> + + + + {/* 创建一个表单,表单名称为"invoke",布局方式为垂直布局,当表单提交时调用onFinish方法 */} + + {/* 创建一个表单项,用于输入请求参数,表单项名称为"userRequestParams" */} + + + + {/* 创建一个包裹项,设置其宽度占据 16 个栅格列 */} + + {/* 创建调用按钮*/} + + 调用 + + + + + + + {invokeRes} + ); }; -export default TableList; + +export default Index; diff --git a/src/pages/Welcome.tsx b/src/pages/Welcome.tsx deleted file mode 100644 index d0c49f7..0000000 --- a/src/pages/Welcome.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import { PageContainer } from '@ant-design/pro-components'; -import { useModel } from '@umijs/max'; -import { Card, theme } from 'antd'; -import React from 'react'; - -/** - * 每个单独的卡片,为了复用样式抽成了组件 - * @param param0 - * @returns - */ -const InfoCard: React.FC<{ - title: string; - index: number; - desc: string; - href: string; -}> = ({ title, href, index, desc }) => { - const { useToken } = theme; - - const { token } = useToken(); - - return ( - - - - {index} - - - {title} - - - - {desc} - - - 了解更多 {'>'} - - - ); -}; - -const Welcome: React.FC = () => { - const { token } = theme.useToken(); - const { initialState } = useModel('@@initialState'); - return ( - - - - - 欢迎使用 Ant Design Pro - - - Ant Design Pro 是一个整合了 umi,Ant Design 和 ProComponents - 的脚手架方案。致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。 - - - - - - - - - - ); -}; - -export default Welcome; diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx new file mode 100644 index 0000000..1f442dd --- /dev/null +++ b/src/pages/index/index.tsx @@ -0,0 +1,93 @@ +import {PageContainer} from '@ant-design/pro-components'; +import React, {useEffect, useState} from 'react'; +import {List, message} from 'antd'; +import {listInterfaceInfoByPageUsingGet} from "@/services/linger-api-backend/interfaceInfoController"; + + +/** + * 主页 + * @constructor + */ +const Index: React.FC = () => { + // 使用 useState 和泛型来定义组件内的状态 + // 加载状态 + const [loading, setLoading] = useState(false); + // 列表数据 + const [list, setList] = useState([]); + // 总数 + const [total, setTotal] = useState(0); + + // 定义异步加载数据的函数 + const loadData = async (current = 1, pageSize = 5) => { + // 开始加载数据,设置 loading 状态为 true + setLoading(true); + try { + // 调用接口获取数据 + const res = await listInterfaceInfoByPageUsingGet({ + current, + pageSize, + }); + // 将请求返回的数据设置到列表数据状态中 + setList(res?.data?.records ?? []); + // 将请求返回的总数设置到总数状态中 + setTotal(res?.data?.total ?? 0); + // 捕获请求失败的错误信息 + } catch (error: any) { + // 请求失败时提示错误信息 + message.error('请求失败,' + error.message); + } + // 数据加载成功或失败后,设置 loading 状态为 false + setLoading(false); + }; + + useEffect(() => { + // 页面加载完成后调用加载数据的函数 + loadData(); + }, []); + + return ( + // 使用 antd 的 PageContainer 组件作为页面容器 + + { + const apiLink = `/interface_info/${item.id}`; + return ( + 查看]}> + {item.name}} + description={item.description} + /> + + ); + }} + // 分页配置 + pagination={{ + // 自定义显示总数 + // eslint-disable-next-line @typescript-eslint/no-shadow + showTotal(total: number) { + return '总数:' + total; + }, + // 每页显示条数 + pageSize: 5, + // 总数,从状态中获取 + total, + // 切换页面触发的回调函数 + onChange(page, pageSize) { + // 加载对应页面的数据 + loadData(page, pageSize); + }, + }} + /> + + ); +}; + +export default Index; diff --git a/src/services/linger-api-backend/analysisController.ts b/src/services/linger-api-backend/analysisController.ts new file mode 100644 index 0000000..5ece006 --- /dev/null +++ b/src/services/linger-api-backend/analysisController.ts @@ -0,0 +1,11 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from '@umijs/max'; + +/** ListTopInvokeInterfaceInfo GET /api/analysis/top/interface/invoke */ +export async function listTopInvokeInterfaceInfoUsingGet(options?: { [key: string]: any }) { + return request('/api/analysis/top/interface/invoke', { + method: 'GET', + ...(options || {}), + }); +} diff --git a/src/services/linger-api-backend/index.ts b/src/services/linger-api-backend/index.ts index 76fa49a..6b44478 100644 --- a/src/services/linger-api-backend/index.ts +++ b/src/services/linger-api-backend/index.ts @@ -2,13 +2,17 @@ /* eslint-disable */ // API 更新时间: // API 唯一标识: +import * as analysisController from './analysisController'; import * as basicErrorController from './basicErrorController'; import * as interfaceInfoController from './interfaceInfoController'; import * as postController from './postController'; import * as userController from './userController'; +import * as userInterfaceInfoController from './userInterfaceInfoController'; export default { + analysisController, basicErrorController, interfaceInfoController, postController, userController, + userInterfaceInfoController, }; diff --git a/src/services/linger-api-backend/interfaceInfoController.ts b/src/services/linger-api-backend/interfaceInfoController.ts index 3518e79..41d14a5 100644 --- a/src/services/linger-api-backend/interfaceInfoController.ts +++ b/src/services/linger-api-backend/interfaceInfoController.ts @@ -47,6 +47,21 @@ export async function getInterfaceInfoByIdUsingGet( }); } +/** invokeInterfaceInfo POST /api/interfaceInfo/invoke */ +export async function invokeInterfaceInfoUsingPost( + body: API.InterfaceInfoInvokeRequest, + options?: { [key: string]: any }, +) { + return request('/api/interfaceInfo/invoke', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + /** listInterfaceInfo GET /api/interfaceInfo/list */ export async function listInterfaceInfoUsingGet( // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) @@ -77,6 +92,36 @@ export async function listInterfaceInfoByPageUsingGet( }); } +/** offlineInterfaceInfo POST /api/interfaceInfo/offline */ +export async function offlineInterfaceInfoUsingPost( + body: API.IdRequest, + options?: { [key: string]: any }, +) { + return request('/api/interfaceInfo/offline', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** onlineInterfaceInfo POST /api/interfaceInfo/online */ +export async function onlineInterfaceInfoUsingPost( + body: API.IdRequest, + options?: { [key: string]: any }, +) { + return request('/api/interfaceInfo/online', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + /** updateInterfaceInfo POST /api/interfaceInfo/update */ export async function updateInterfaceInfoUsingPost( body: API.InterfaceInfoUpdateRequest, diff --git a/src/services/linger-api-backend/typings.d.ts b/src/services/linger-api-backend/typings.d.ts index cb74615..9fe05bc 100644 --- a/src/services/linger-api-backend/typings.d.ts +++ b/src/services/linger-api-backend/typings.d.ts @@ -17,12 +17,24 @@ declare namespace API { message?: string; }; + type BaseResponseListInterfaceInfoVO = { + code?: number; + data?: InterfaceInfoVO[]; + message?: string; + }; + type BaseResponseListPost = { code?: number; data?: Post[]; message?: string; }; + type BaseResponseListUserInterfaceInfo = { + code?: number; + data?: UserInterfaceInfo[]; + message?: string; + }; + type BaseResponseListUserVO = { code?: number; data?: UserVO[]; @@ -35,6 +47,12 @@ declare namespace API { message?: string; }; + type BaseResponseobject = { + code?: number; + data?: Record; + message?: string; + }; + type BaseResponsePageInterfaceInfo = { code?: number; data?: PageInterfaceInfo; @@ -47,6 +65,12 @@ declare namespace API { message?: string; }; + type BaseResponsePageUserInterfaceInfo = { + code?: number; + data?: PageUserInterfaceInfo; + message?: string; + }; + type BaseResponsePageUserVO = { code?: number; data?: PageUserVO; @@ -65,6 +89,12 @@ declare namespace API { message?: string; }; + type BaseResponseUserInterfaceInfo = { + code?: number; + data?: UserInterfaceInfo; + message?: string; + }; + type BaseResponseUserVO = { code?: number; data?: UserVO; @@ -90,6 +120,15 @@ declare namespace API { id?: number; }; + type getUserInterfaceInfoByIdUsingGETParams = { + /** id */ + id?: number; + }; + + type IdRequest = { + id?: number; + }; + type InterfaceInfo = { createTime?: string; description?: string; @@ -98,6 +137,7 @@ declare namespace API { method?: string; name?: string; requestHeader?: string; + requestParams?: string; responseHeader?: string; status?: number; updateTime?: string; @@ -114,15 +154,38 @@ declare namespace API { url?: string; }; + type InterfaceInfoInvokeRequest = { + id?: number; + userRequestParams?: string; + }; + type InterfaceInfoUpdateRequest = { description?: string; id?: number; method?: string; name?: string; requestHeader?: string; + requestParams?: string; + responseHeader?: string; + status?: number; + url?: string; + }; + + type InterfaceInfoVO = { + createTime?: string; + description?: string; + id?: number; + isDeleted?: number; + method?: string; + name?: string; + requestHeader?: string; + requestParams?: string; responseHeader?: string; status?: number; + totalNum?: number; + updateTime?: string; url?: string; + userId?: number; }; type listInterfaceInfoByPageUsingGETParams = { @@ -206,6 +269,32 @@ declare namespace API { userRole?: string; }; + type listUserInterfaceInfoByPageUsingGETParams = { + current?: number; + id?: number; + interfaceInfoId?: number; + leftNum?: number; + pageSize?: number; + sortField?: string; + sortOrder?: string; + status?: number; + totalNum?: number; + userId?: number; + }; + + type listUserInterfaceInfoUsingGETParams = { + current?: number; + id?: number; + interfaceInfoId?: number; + leftNum?: number; + pageSize?: number; + sortField?: string; + sortOrder?: string; + status?: number; + totalNum?: number; + userId?: number; + }; + type listUserUsingGETParams = { createTime?: string; current?: number; @@ -330,6 +419,19 @@ declare namespace API { total?: number; }; + type PageUserInterfaceInfo = { + countId?: string; + current?: number; + maxLimit?: number; + optimizeCountSql?: boolean; + orders?: OrderItem[]; + pages?: number; + records?: UserInterfaceInfo[]; + searchCount?: boolean; + size?: number; + total?: number; + }; + type PageUserVO = { countId?: string; current?: number; @@ -392,10 +494,12 @@ declare namespace API { }; type User = { + accessKey?: string; createTime?: string; gender?: number; id?: number; isDelete?: number; + secretKey?: string; updateTime?: string; userAccount?: string; userAvatar?: string; @@ -413,6 +517,32 @@ declare namespace API { userRole?: string; }; + type UserInterfaceInfo = { + createTime?: string; + id?: number; + interfaceInfoId?: number; + isDelete?: number; + leftNum?: number; + status?: number; + totalNum?: number; + updateTime?: string; + userId?: number; + }; + + type UserInterfaceInfoAddRequest = { + interfaceInfoId?: number; + leftNum?: number; + totalNum?: number; + userId?: number; + }; + + type UserInterfaceInfoUpdateRequest = { + id?: number; + leftNum?: number; + status?: number; + totalNum?: number; + }; + type UserLoginRequest = { userAccount?: string; userPassword?: string; @@ -449,10 +579,3 @@ declare namespace API { contentType?: string; }; } - -/* - 全局状态类型 - */ -interface InitialState { - loginUser?: API.UserVO; -} diff --git a/src/services/linger-api-backend/userInterfaceInfoController.ts b/src/services/linger-api-backend/userInterfaceInfoController.ts new file mode 100644 index 0000000..f73045b --- /dev/null +++ b/src/services/linger-api-backend/userInterfaceInfoController.ts @@ -0,0 +1,93 @@ +// @ts-ignore +/* eslint-disable */ +import { request } from '@umijs/max'; + +/** addUserInterfaceInfo POST /api/userinterfaceinfo/add */ +export async function addUserInterfaceInfoUsingPost( + body: API.UserInterfaceInfoAddRequest, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/add', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** deleteUserInterfaceInfo POST /api/userinterfaceinfo/delete */ +export async function deleteUserInterfaceInfoUsingPost( + body: API.DeleteRequest, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/delete', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +} + +/** getUserInterfaceInfoById GET /api/userinterfaceinfo/get */ +export async function getUserInterfaceInfoByIdUsingGet( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.getUserInterfaceInfoByIdUsingGETParams, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/get', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** listUserInterfaceInfo GET /api/userinterfaceinfo/list */ +export async function listUserInterfaceInfoUsingGet( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.listUserInterfaceInfoUsingGETParams, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/list', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** listUserInterfaceInfoByPage GET /api/userinterfaceinfo/list/page */ +export async function listUserInterfaceInfoByPageUsingGet( + // 叠加生成的Param类型 (非body参数swagger默认没有生成对象) + params: API.listUserInterfaceInfoByPageUsingGETParams, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/list/page', { + method: 'GET', + params: { + ...params, + }, + ...(options || {}), + }); +} + +/** updateUserInterfaceInfo POST /api/userinterfaceinfo/update */ +export async function updateUserInterfaceInfoUsingPost( + body: API.UserInterfaceInfoUpdateRequest, + options?: { [key: string]: any }, +) { + return request('/api/userinterfaceinfo/update', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + data: body, + ...(options || {}), + }); +}
- Want to add more pages? Please refer to{' '} - - use block - - 。 -
- Ant Design Pro 是一个整合了 umi,Ant Design 和 ProComponents - 的脚手架方案。致力于在设计规范和基础组件的基础上,继续向上构建,提炼出典型模板/业务组件/配套设计资源,进一步提升企业级中后台产品设计研发过程中的『用户』和『设计者』的体验。 -