From 49bfe975bca15c1c9b4de4e66cd431f91dc5b5fb Mon Sep 17 00:00:00 2001 From: donghao Date: Mon, 29 Apr 2024 17:53:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E6=9E=84?= =?UTF-8?q?=E5=BB=BA=E8=8A=82=E7=82=B9=E8=AE=BE=E5=A4=87=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/routes.ts | 8 +- mock/device.ts | 33 ++ mock/deviceGroup.ts | 13 +- mock/dict.ts | 15 +- mock/pools/deviceData.ts | 35 ++ mock/pools/deviceGroupData.ts | 479 +++++++++++++++--- mock/pools/dictData.ts | 13 +- public/home/business_arrow.svg | 4 + public/home/business_arrow_default.svg | 1 + public/home/business_big_logo.svg | 44 ++ public/home/menu_footer_bg.png | Bin 0 -> 28788 bytes src/app.css | 8 +- src/app.less | 12 + src/app.tsx | 2 +- src/base.less | 4 +- src/components/MenuBar/index.css | 7 +- src/components/MenuBar/index.less | 1 - src/components/MenuBar/index.tsx | 25 +- src/components/Tree/index.ts | 3 + src/components/Tree/src/baseTree.css | 47 ++ src/components/Tree/src/baseTree.less | 53 ++ src/components/Tree/src/baseTree.tsx | 247 +++++++++ src/components/Tree/src/deviceGroupTree.tsx | 72 +++ src/components/Tree/typing.ts | 25 + src/enums/deviceGroup.ts | 23 + src/global.css | 46 +- src/global.less | 66 ++- src/locales/zh-CN/device.ts | 111 ++-- src/locales/zh-CN/menu.ts | 4 +- .../DeviceGroup/components/baseInfo.tsx | 62 +++ .../components/createDeviceForm.tsx | 175 +++++++ .../DeviceGroup/components/createForm.tsx | 176 +++++++ .../DeviceGroup/components/deviceList.tsx | 246 +++++++++ src/pages/Business/DeviceGroup/index.css | 37 ++ src/pages/Business/DeviceGroup/index.less | 45 ++ src/pages/Business/DeviceGroup/index.tsx | 136 +++++ src/pages/Business/NodeSetting/index.tsx | 14 - src/pages/Model/ModelDetail/index.tsx | 6 +- .../BusinessInfo/components/baseInfo.tsx | 4 +- src/services/testApi/device.ts | 31 ++ src/services/testApi/deviceGroup.ts | 60 ++- src/services/testApi/dict.ts | 22 +- src/utils/baseTree.ts | 13 + 43 files changed, 2214 insertions(+), 214 deletions(-) create mode 100644 mock/device.ts create mode 100644 mock/pools/deviceData.ts create mode 100644 public/home/business_arrow.svg create mode 100644 public/home/business_arrow_default.svg create mode 100644 public/home/business_big_logo.svg create mode 100644 public/home/menu_footer_bg.png create mode 100644 src/components/Tree/index.ts create mode 100644 src/components/Tree/src/baseTree.css create mode 100644 src/components/Tree/src/baseTree.less create mode 100644 src/components/Tree/src/baseTree.tsx create mode 100644 src/components/Tree/src/deviceGroupTree.tsx create mode 100644 src/components/Tree/typing.ts create mode 100644 src/enums/deviceGroup.ts create mode 100644 src/pages/Business/DeviceGroup/components/baseInfo.tsx create mode 100644 src/pages/Business/DeviceGroup/components/createDeviceForm.tsx create mode 100644 src/pages/Business/DeviceGroup/components/createForm.tsx create mode 100644 src/pages/Business/DeviceGroup/components/deviceList.tsx create mode 100644 src/pages/Business/DeviceGroup/index.css create mode 100644 src/pages/Business/DeviceGroup/index.less create mode 100644 src/pages/Business/DeviceGroup/index.tsx delete mode 100644 src/pages/Business/NodeSetting/index.tsx create mode 100644 src/services/testApi/device.ts create mode 100644 src/utils/baseTree.ts diff --git a/config/routes.ts b/config/routes.ts index dc5c569..504786e 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-03-27 14:56:27 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-22 16:50:40 + * @LastEditTime: 2024-04-26 09:33:39 * @FilePath: \general-ai-manage\config\routes.ts * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -103,9 +103,9 @@ export const innerMenuRoutes = [ menuIcon: 'TestIcon', }, { - name: 'business-node-setting', - path: '/business/nodeSetting', - component: './Business/NodeSetting', + name: 'business-device-group', + path: '/business/deviceGroup', + component: './Business/DeviceGroup', access: 'canReadMenu', key: '1002', menuIcon: '', diff --git a/mock/device.ts b/mock/device.ts new file mode 100644 index 0000000..423c51c --- /dev/null +++ b/mock/device.ts @@ -0,0 +1,33 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-25 15:45:17 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-28 17:15:19 + * @FilePath: \general-ai-platform-web\mock\device.ts + * @Description: mock设备数据 + */ +import { mockGetDeviceListByGroup } from './pools/deviceData'; + +import { successMockApiProps } from './typing'; +import { fetchCurrPageByList } from './utils/apiMock'; + +export default { + // 设备列表 + 'GET /api/device/listByGroup': async (req: Request, res: Response) => { + const { page, pageSize } = req.query; + const resData: successMockApiProps = { + ...fetchCurrPageByList({ + ...mockGetDeviceListByGroup, + data: { ...mockGetDeviceListByGroup.data, page, pageSize: pageSize || 10 }, + }), + }; + res.json(resData); + }, + // // 设备分类 + // 'GET /api/dict/deviceType': async (req: Request, res: Response) => { + // const resData: successMockApiProps = { + // ...fetchMockSuccessFullByOther(mockGetDeviceTypeDictData), + // }; + // res.json(resData); + // }, +}; diff --git a/mock/deviceGroup.ts b/mock/deviceGroup.ts index d1eaf50..0da5dbb 100644 --- a/mock/deviceGroup.ts +++ b/mock/deviceGroup.ts @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-01-25 16:53:15 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-25 15:50:16 + * @LastEditTime: 2024-04-26 16:35:54 * @FilePath: \general-ai-platform-web\mock\deviceGroup.ts * @Description: 节点设备设置 mock */ @@ -12,6 +12,7 @@ import { mockGetDeviceGroupData3, mockGetDeviceGroupFkSelectData, mockGetDeviceGroupListData, + mockGetDeviceGroupSettingData, mockGetDeviceGroupTreeData, } from './pools/deviceGroupData'; import { successMockApiProps } from './typing'; @@ -29,6 +30,15 @@ export default { res.json(resData); }, + // 设备组网点树列表 + 'GET /api/device_group/setting_data': async (req: Request, res: Response) => { + const resData: successMockApiProps = { + ...fetchMockSuccessFullByOther(mockGetDeviceGroupSettingData), + }; + res.json(resData); + }, + + /** 未启用 */ // 设备组网点选项列表 'GET /api/device_group/getDeviceGroupFkSelect': async (req: Request, res: Response) => { const resData: successMockApiProps = { @@ -43,6 +53,7 @@ export default { }; res.json(resData); }, + // 设备组详情 'GET /api/device_group/getDeviceGroupById': async (req: Request, res: Response) => { const { id } = req.query; diff --git a/mock/dict.ts b/mock/dict.ts index 66323f5..10ad869 100644 --- a/mock/dict.ts +++ b/mock/dict.ts @@ -2,21 +2,28 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-17 14:01:39 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-17 14:01:47 + * @LastEditTime: 2024-04-28 14:08:45 * @FilePath: \general-ai-manage\mock\dict.ts * @Description: 字典表mock数据处理 */ -import { mockGetIndustryDictData } from './pools/dictData'; +import { mockGetDeviceTypeDictData, mockGetIndustryDictData } from './pools/dictData'; import { successMockApiProps } from './typing'; import { fetchMockSuccessFullByOther } from './utils/apiMock'; export default { - // 实时分析告警列表分页 - 'GET /api/dict/industry/': async (req: Request, res: Response) => { + // 行业分类 + 'GET /api/dict/industry': async (req: Request, res: Response) => { const resData: successMockApiProps = { ...fetchMockSuccessFullByOther(mockGetIndustryDictData), }; res.json(resData); }, + // 设备分类 + 'GET /api/dict/deviceType': async (req: Request, res: Response) => { + const resData: successMockApiProps = { + ...fetchMockSuccessFullByOther(mockGetDeviceTypeDictData), + }; + res.json(resData); + }, }; diff --git a/mock/pools/deviceData.ts b/mock/pools/deviceData.ts new file mode 100644 index 0000000..e64e2c9 --- /dev/null +++ b/mock/pools/deviceData.ts @@ -0,0 +1,35 @@ +// 节点下设备列表数据 +// 节点设备列表 +export const mockGetDeviceListByGroup = { + data: { + count: 2, + results: [ + { + id: '10001', + name: '海康威视环球摄像头', // 设备名称 + deviceType: '摄像头', // 设备类型 + isEnable: true, // 是否部署 + createTime: '2023-12-17T13:37:31.758471+08:00', + updateTime: '2024-04-25T15:22:16.530494+08:00', + deviceSite: '东区左侧', // 设备位置 + deviceModel: 'haikang_video_2024', // 设备型号 + deviceParams: '627663_aduh237298', // 设备参数 + remark: '', // 备注 + }, + { + id: '10002', + name: '海康威视环球摄像头', + deviceType: '控制器', + isEnable: false, + createTime: '2023-12-17T13:37:31.758471+08:00', + updateTime: '2024-04-25T15:22:16.530494+08:00', + deviceSite: '南区前侧', + deviceModel: 'haikang_video_2024', + deviceParams: '627663_aduh237298', + remark: '', + }, + ], + page: 1, + pageSize: 10, + }, +}; diff --git a/mock/pools/deviceGroupData.ts b/mock/pools/deviceGroupData.ts index b815405..6146b05 100644 --- a/mock/pools/deviceGroupData.ts +++ b/mock/pools/deviceGroupData.ts @@ -1,40 +1,257 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-25 15:45:31 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-29 14:44:39 + * @FilePath: \general-ai-platform-web\mock\pools\deviceGroupData.ts + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ /* * @Author: donghao donghao@supervision.ltd * @Date: 2024-01-25 16:32:31 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-25 15:51:57 + * @LastEditTime: 2024-04-28 13:21:47 * @FilePath: \general-ai-platform-web\mock\pools\deviceGroupData.ts * @Description: 节点设备设置 */ -// 设备组节点选项列表 -export const mockGetDeviceGroupFkSelectData = { - data: { - list: [ - { - name: '南京节点', - id: 1, - }, - { - name: '秦淮节点', - id: 2, - }, - { - name: '江宁节点', - id: 3, - }, - { - name: '安徽节点', - id: 4, - }, - { - name: '合肥节点', - id: 5, - }, - ], - }, -}; // 设备组节点树 +export const mockGetDeviceGroupSettingData = { + data: [ + { + name: '安徽省', + id: '340000', + groupList: [ + { + name: '合肥市', + id: '340100', + groupList: [ + { name: '瑶海区', id: '340102', groupList: [] }, + { name: '庐阳区', id: '340103', groupList: [] }, + { name: '蜀山区', id: '340104', groupList: [] }, + { name: '包河区', id: '340111', groupList: [] }, + { name: '长丰县', id: '340121', groupList: [] }, + { name: '肥东县', id: '340122', groupList: [] }, + { name: '肥西县', id: '340123', groupList: [] }, + { name: '庐江县', id: '340124', groupList: [] }, + { name: '巢湖市', id: '340181', groupList: [] }, + ], + }, + { + name: '芜湖市', + id: '340200', + groupList: [ + { name: '镜湖区', id: '340202', groupList: [] }, + { name: '弋江区', id: '340203', groupList: [] }, + { name: '鸠江区', id: '340207', groupList: [] }, + { name: '三山区', id: '340208', groupList: [] }, + { name: '芜湖县', id: '340221', groupList: [] }, + { name: '繁昌县', id: '340222', groupList: [] }, + { name: '南陵县', id: '340223', groupList: [] }, + { name: '无为县', id: '340225', groupList: [] }, + ], + }, + { + name: '蚌埠市', + id: '340300', + groupList: [ + { name: '龙子湖区', id: '340302', groupList: [] }, + { name: '蚌山区', id: '340303', groupList: [] }, + { name: '禹会区', id: '340304', groupList: [] }, + { name: '淮上区', id: '340311', groupList: [] }, + { name: '怀远县', id: '340321', groupList: [] }, + { name: '五河县', id: '340322', groupList: [] }, + { name: '固镇县', id: '340323', groupList: [] }, + ], + }, + { + name: '淮南市', + id: '340400', + groupList: [ + { name: '大通区', id: '340402', groupList: [] }, + { name: '田家庵区', id: '340403', groupList: [] }, + { name: '谢家集区', id: '340404', groupList: [] }, + { name: '八公山区', id: '340405', groupList: [] }, + { name: '潘集区', id: '340406', groupList: [] }, + { name: '凤台县', id: '340421', groupList: [] }, + { name: '寿县', id: '340422', groupList: [] }, + ], + }, + { + name: '马鞍山市', + id: '340500', + groupList: [ + { name: '花山区', id: '340503', groupList: [] }, + { name: '雨山区', id: '340504', groupList: [] }, + { name: '博望区', id: '340506', groupList: [] }, + { name: '当涂县', id: '340521', groupList: [] }, + { name: '含山县', id: '340522', groupList: [] }, + { name: '和县', id: '340523', groupList: [] }, + ], + }, + { + name: '淮北市', + id: '340600', + groupList: [ + { name: '杜集区', id: '340602', groupList: [] }, + { name: '相山区', id: '340603', groupList: [] }, + { name: '烈山区', id: '340604', groupList: [] }, + { name: '濉溪县', id: '340621', groupList: [] }, + ], + }, + { + name: '铜陵市', + id: '340700', + groupList: [ + { name: '铜官区', id: '340705', groupList: [] }, + { name: '义安区', id: '340706', groupList: [] }, + { name: '郊区', id: '340711', groupList: [] }, + { name: '枞阳县', id: '340722', groupList: [] }, + ], + }, + { + name: '安庆市', + id: '340800', + groupList: [ + { name: '迎江区', id: '340802', groupList: [] }, + { name: '大观区', id: '340803', groupList: [] }, + { name: '宜秀区', id: '340811', groupList: [] }, + { name: '怀宁县', id: '340822', groupList: [] }, + { name: '潜山市', id: '340882', groupList: [] }, + { name: '太湖县', id: '340825', groupList: [] }, + { name: '宿松县', id: '340826', groupList: [] }, + { name: '望江县', id: '340827', groupList: [] }, + { name: '岳西县', id: '340828', groupList: [] }, + { name: '桐城市', id: '340881', groupList: [] }, + ], + }, + { + name: '滁州市', + id: '341100', + groupList: [ + { name: '琅琊区', id: '341102', groupList: [] }, + { name: '南谯区', id: '341103', groupList: [] }, + { name: '来安县', id: '341122', groupList: [] }, + { name: '全椒县', id: '341124', groupList: [] }, + { name: '定远县', id: '341125', groupList: [] }, + { name: '凤阳县', id: '341126', groupList: [] }, + { name: '天长市', id: '341181', groupList: [] }, + { name: '明光市', id: '341182', groupList: [] }, + ], + }, + { + name: '阜阳市', + id: '341200', + groupList: [ + { name: '颍州区', id: '341202', groupList: [] }, + { name: '颍东区', id: '341203', groupList: [] }, + { name: '颍泉区', id: '341204', groupList: [] }, + { name: '临泉县', id: '341221', groupList: [] }, + { name: '太和县', id: '341222', groupList: [] }, + { name: '阜南县', id: '341225', groupList: [] }, + { name: '颍上县', id: '341226', groupList: [] }, + { name: '界首市', id: '341282', groupList: [] }, + ], + }, + { + name: '宿州市', + id: '341300', + groupList: [ + { name: '埇桥区', id: '341302', groupList: [] }, + { name: '砀山县', id: '341321', groupList: [] }, + { name: '萧县', id: '341322', groupList: [] }, + { name: '灵璧县', id: '341323', groupList: [] }, + { name: '泗县', id: '341324', groupList: [] }, + ], + }, + { + name: '六安市', + id: '341500', + groupList: [ + { name: '金安区', id: '341502', groupList: [] }, + { name: '裕安区', id: '341503', groupList: [] }, + { name: '叶集区', id: '341504', groupList: [] }, + { name: '霍邱县', id: '341522', groupList: [] }, + { name: '舒城县', id: '341523', groupList: [] }, + { name: '金寨县', id: '341524', groupList: [] }, + { name: '霍山县', id: '341525', groupList: [] }, + ], + }, + { + name: '亳州市', + id: '341600', + groupList: [ + { name: '谯城区', id: '341602', groupList: [] }, + { name: '涡阳县', id: '341621', groupList: [] }, + { name: '蒙城县', id: '341622', groupList: [] }, + { name: '利辛县', id: '341623', groupList: [] }, + ], + }, + { + name: '池州市', + id: '341700', + groupList: [ + { name: '贵池区', id: '341702', groupList: [] }, + { name: '东至县', id: '341721', groupList: [] }, + { name: '石台县', id: '341722', groupList: [] }, + { name: '青阳县', id: '341723', groupList: [] }, + ], + }, + { + name: '宣城市', + id: '341800', + groupList: [ + { name: '宣州区', id: '341802', groupList: [] }, + { name: '郎溪县', id: '341821', groupList: [] }, + { name: '广德县', id: '341822', groupList: [] }, + { name: '泾县', id: '341823', groupList: [] }, + { name: '绩溪县', id: '341824', groupList: [] }, + { name: '旌德县', id: '341825', groupList: [] }, + { name: '宁国市', id: '341881', groupList: [] }, + ], + }, + { + name: '黄山市', + id: '341000', + groupList: [ + { name: '屯溪区', id: '341002', groupList: [] }, + { name: '黄山区', id: '341003', groupList: [] }, + { name: '徽州区', id: '341004', groupList: [] }, + { name: '歙县', id: '341021', groupList: [] }, + { name: '休宁县', id: '341022', groupList: [] }, + { name: '黟县', id: '341023', groupList: [] }, + { name: '祁门县', id: '341024', groupList: [] }, + ], + }, + ], + }, + + { + name: '江苏省', + id: '320000', + groupList: [ + { + name: '南京市', + id: '320100', + groupList: [ + { name: '玄武区', id: '320102', groupList: [] }, + { name: '秦淮区', id: '320104', groupList: [] }, + { name: '建邺区', id: '320105', groupList: [] }, + { name: '鼓楼区', id: '320106', groupList: [] }, + { name: '浦口区', id: '320111', groupList: [] }, + { name: '栖霞区', id: '320113', groupList: [] }, + { name: '雨花台区', id: '320114', groupList: [] }, + { name: '江宁区', id: '320115', groupList: [] }, + { name: '六合区', id: '320116', groupList: [] }, + { name: '溧水区', id: '320117', groupList: [] }, + { name: '高淳区', id: '320118', groupList: [] }, + ], + }, + ], + }, + ], +}; + export const mockGetDeviceGroupTreeData = { data: { tree: [ @@ -72,17 +289,34 @@ export const mockGetDeviceGroupTreeData = { // 设备组列表分页 export const mockGetDeviceGroupListData = { data: { - list: [ + results: [ { - id: 1, + level: 1, + id: '0001', + createTime: '2023-10-17T10:43:31.254107+08:00', + updateTime: '2023-10-17T10:45:25.030034+08:00', + name: '上海节点', + address: '中国上海市浦东新区申迪北路', + fatherName: '无', + fatherId: '', + lon: 121.667987, + lat: 31.144417, + managerName: '刘芳', + managerPhone: '16526365632', + remark: '--', + // TODO 完成设备节点列表数据的构建 + }, + { + level: 1, + id: '0002', createTime: '2023-10-17T10:43:31.254107+08:00', updateTime: '2023-10-17T10:45:25.030034+08:00', name: '南京节点', code: 'DG00002', - address: '江苏省南京市南京市栖霞区紫东路南京紫东国际创意园', + address: '江苏省南京市南京市栖霞区紫东路南京紫东国际创意园', // 地址 telephone: '12345', - lon: '118.914349', - lat: '32.086019', + lon: '118.914349', // 经度 + lat: '32.086019', // 纬度 managerName: '张三', managerPhone: '111111111', isEnable: true, @@ -90,7 +324,8 @@ export const mockGetDeviceGroupListData = { remark: '', children: [ { - id: 2, + level: 2, + id: '20001', createTime: '2023-10-17T13:37:31.758471+08:00', updateTime: '2023-10-17T13:39:31.530494+08:00', name: '秦淮节点', @@ -105,10 +340,10 @@ export const mockGetDeviceGroupListData = { parentFkId: 1, remark: '', children: null, - key: '2', }, { - id: 3, + level: 2, + id: '20002', createTime: '2023-10-17T13:40:28.823372+08:00', updateTime: '2023-10-17T13:40:28.823372+08:00', name: '江宁节点', @@ -123,52 +358,42 @@ export const mockGetDeviceGroupListData = { parentFkId: 1, remark: '', children: null, - key: '3', }, ], - key: '1', + }, + ], + count: 2, + page: 1, + pageSize: 10, + }, +}; + +/** 未启用 */ +// 设备组节点选项列表 +export const mockGetDeviceGroupFkSelectData = { + data: { + list: [ + { + name: '南京节点', + id: 1, + }, + { + name: '秦淮节点', + id: 2, + }, + { + name: '江宁节点', + id: 3, }, { - id: 4, - createTime: '2023-10-17T15:02:30.725705+08:00', - updateTime: '2023-10-17T15:02:30.725705+08:00', name: '安徽节点', - code: 'DG00005', - address: '', - telephone: '', - lon: '', - lat: '', - managerName: '', - managerPhone: '', - isEnable: true, - parentFkId: 0, - remark: '', - children: [ - { - id: 5, - createTime: '2023-10-17T15:05:13.542992+08:00', - updateTime: '2023-10-17T15:08:01.071315+08:00', - name: '合肥节点', - code: 'DG00006', - address: '安徽省合肥市包河区马鞍山路130号', - telephone: '', - lon: '117.309214', - lat: '31.862594', - managerName: '', - managerPhone: '', - isEnable: true, - parentFkId: 4, - remark: '', - children: null, - key: '5', - }, - ], - key: '4', + id: 4, + }, + { + name: '合肥节点', + id: 5, }, ], - total: 0, - page: 1, - pageSize: 10, }, }; @@ -239,3 +464,107 @@ export const mockGetDeviceGroupData3 = { }, }, }; + +// 节点信息 +export const mockGetNodeInfo = [ + { + name: '南京中山陵', + address: '中国江苏省南京市玄武区明孝陵路1号', + fatherName: '南京', + fatherId: 'NJ002', + lon: 118.835383, + lat: 32.036853, + managerName: '赵刚', + managerPhone: '025-8443 5328', + remark: '中山陵是中国江苏省南京市的一处著名纪念建筑,是国父孙中山的陵墓。', + }, + { + name: '南京总统府', + address: '中国江苏省南京市玄武区长江路292号', + fatherName: '南京', + fatherId: 'NJ003', + lon: 118.796492, + lat: 32.054979, + managerName: '陈霞', + managerPhone: '025-8462 3951', + remark: + '南京总统府是中国南京市玄武区长江路292号的一座历史建筑,是中华民国时期南京国民政府的办公地点。', + }, + { + name: '东方明珠塔', + address: '中国上海市浦东新区陆家嘴环路1号', + fatherName: '上海', + fatherId: 'SH004', + lon: 121.506377, + lat: 31.239722, + managerName: '王静', + managerPhone: '021-5879 1888', + remark: '东方明珠塔是位于中国上海市浦东陆家嘴金融贸易区的一座电视塔,是上海的标志性建筑之一。', + }, + { + name: '南京雨花台', + address: '中国江苏省南京市雨花台区雨花路78号', + fatherName: '南京', + fatherId: 'NJ004', + lon: 118.748754, + lat: 31.997532, + managerName: '张磊', + managerPhone: '025-5275 0088', + remark: '雨花台是中国江苏省南京市雨花台区的一个丘陵,也是南京市的一个知名旅游景点。', + }, + { + name: '上海科技馆', + address: '中国上海市浦东新区世纪大道2000号', + fatherName: '上海', + fatherId: 'SH005', + lon: 121.537235, + lat: 31.216444, + managerName: '周洋', + managerPhone: '021-6854 6916', + remark: '上海科技馆是位于中国上海市浦东新区的一座科技展示馆,是上海市的科普教育基地之一。', + }, + { + name: '南京中华门', + address: '中国江苏省南京市秦淮区中华门', + fatherName: '南京', + fatherId: 'NJ005', + lon: 118.790325, + lat: 32.046384, + managerName: '李明', + managerPhone: '025-8357 8845', + remark: '中华门是中国江苏省南京市秦淮区的一处历史古迹,是南京古城墙的门。', + }, + { + name: '上海外滩观景台', + address: '中国上海市黄浦区中山东一路20号', + fatherName: '上海', + fatherId: 'SH006', + lon: 121.489562, + lat: 31.240737, + managerName: '王红', + managerPhone: '021-5879 8901', + remark: '上海外滩观景台位于上海市黄浦区外滩20号,是游览上海外滩天际线的最佳地点之一。', + }, + { + name: '南京中山陵石象路', + address: '中国江苏省南京市玄武区石象路', + fatherName: '南京', + fatherId: 'NJ006', + lon: 118.835168, + lat: 32.041867, + managerName: '刘军', + managerPhone: '025-8463 2211', + remark: '南京中山陵石象路是中国江苏省南京市玄武区的一条道路,沿路有许多历史建筑和景点。', + }, + { + name: '上海豫园', + address: '中国上海市黄浦区安仁街137号', + fatherName: '上海', + fatherId: 'SH007', + lon: 121.492783, + lat: 31.227565, + managerName: '张艳', + managerPhone: '021-6328 8888', + remark: '上海豫园是位于上海市黄浦区的一座古典式园林,是上海市的主要旅游景点之一。', + }, +]; diff --git a/mock/pools/dictData.ts b/mock/pools/dictData.ts index 233bf66..c350347 100644 --- a/mock/pools/dictData.ts +++ b/mock/pools/dictData.ts @@ -2,10 +2,12 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-17 13:58:57 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-17 14:05:50 + * @LastEditTime: 2024-04-28 14:03:58 * @FilePath: \general-ai-manage\mock\pools\dictData.ts * @Description: 字典表mock数据 */ + +// 行业分类 export const mockGetIndustryDictData = { data: { results: [ @@ -186,3 +188,12 @@ export const mockGetIndustryDictData = { ], }, }; +// 设备分类 +export const mockGetDeviceTypeDictData = { + data: { + results: [ + { id: 1002000, name: '摄像头' }, + { id: 1002002, name: '控制器' }, + ], + }, +}; diff --git a/public/home/business_arrow.svg b/public/home/business_arrow.svg new file mode 100644 index 0000000..81e46bd --- /dev/null +++ b/public/home/business_arrow.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/public/home/business_arrow_default.svg b/public/home/business_arrow_default.svg new file mode 100644 index 0000000..1be62d1 --- /dev/null +++ b/public/home/business_arrow_default.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/home/business_big_logo.svg b/public/home/business_big_logo.svg new file mode 100644 index 0000000..abfc5bc --- /dev/null +++ b/public/home/business_big_logo.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/home/menu_footer_bg.png b/public/home/menu_footer_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..03d0aa53b01ed0c25346efc660b3e3235eb83d70 GIT binary patch literal 28788 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 DjhAl7 literal 0 HcmV?d00001 diff --git a/src/app.css b/src/app.css index 28c310c..0058e65 100644 --- a/src/app.css +++ b/src/app.css @@ -12,6 +12,12 @@ background-color: transparent; padding-inline: 0 !important; } +.app_page_wrap .page_menu .ant-menu { + background-image: url(../public/home/menu_footer_bg.png); + background-repeat: no-repeat; + background-position: left bottom; + background-size: cover; +} .app_page_wrap .page_body { width: calc(100vw - 200px); } @@ -19,10 +25,10 @@ position: fixed; top: 0; right: 0; + z-index: 999; width: calc(100vw - 200px); min-width: 100px; height: 50px; - z-index: 999; padding: 0 24px 0 20px; background-color: #f8fafd; } diff --git a/src/app.less b/src/app.less index 9eae460..f1c874d 100644 --- a/src/app.less +++ b/src/app.less @@ -12,6 +12,17 @@ background-color: transparent; padding-inline: 0 !important; } + .page_menu { + // menu_footer_bg.png + + .ant-menu { + // background-color: red; + background-image: url(../public/home/menu_footer_bg.png); + background-repeat: no-repeat; + background-position: left bottom; + background-size: cover; + } + } .page_body { width: calc(100vw - 200px); .body_nav_bar { @@ -23,6 +34,7 @@ min-width: 100px; height: 50px; padding: 0 24px 0 20px; + background-color: #f8fafd; .avatar_box { & > img { diff --git a/src/app.tsx b/src/app.tsx index fc50d7a..44f72d4 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -145,7 +145,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) = // if (initialState?.loading) return ; return (
-
+
setCurrMenu(record)} diff --git a/src/base.less b/src/base.less index 6f5334b..9e293ff 100644 --- a/src/base.less +++ b/src/base.less @@ -39,6 +39,7 @@ text-align: left; text-transform: none; } + .head5 { color: #333333; font-weight: bold; @@ -61,6 +62,3 @@ text-align: left; text-transform: none; } - -body { -} diff --git a/src/components/MenuBar/index.css b/src/components/MenuBar/index.css index b3f42fd..22158f9 100644 --- a/src/components/MenuBar/index.css +++ b/src/components/MenuBar/index.css @@ -1,11 +1,11 @@ .menubar_wrap { position: fixed; - left: 0; top: 0; - height: 100vh; - display: flex; + left: 0; z-index: 999; + display: flex; width: 200px; + height: 100vh; padding: 0; background-color: #fff; border-radius: 0px 0px 32px 0px; @@ -46,7 +46,6 @@ display: flex; flex: 1; width: 100%; - padding-top: 10px; } .menubar_wrap .menu_bottom { width: 96px; diff --git a/src/components/MenuBar/index.less b/src/components/MenuBar/index.less index 5cb0639..7cdd32f 100644 --- a/src/components/MenuBar/index.less +++ b/src/components/MenuBar/index.less @@ -52,7 +52,6 @@ display: flex; flex: 1; width: 100%; - padding-top: 10px; } .menu_bottom { width: 96px; diff --git a/src/components/MenuBar/index.tsx b/src/components/MenuBar/index.tsx index ded5dd3..8270ed9 100644 --- a/src/components/MenuBar/index.tsx +++ b/src/components/MenuBar/index.tsx @@ -2,19 +2,20 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-03-27 16:03:20 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-23 10:48:58 + * @LastEditTime: 2024-04-28 09:44:23 * @FilePath: \general-ai-manage\src\components\Header\index.tsx * @Description: 内层layout菜单配置 */ import { useBusinessInfo } from '@/hooks/useBusinessInfo'; import { history, useIntl } from '@umijs/max'; +import { ReactComponent as BusinessLogoIcon } from '/public/home/business_logo.svg'; import type { MenuProps } from 'antd'; import { Menu } from 'antd'; import React, { useEffect, useState } from 'react'; -import { ReactComponent as BusinessLogoIcon } from '/public/home/business_logo.svg'; +import { ReactComponent as BusinessBigLogo } from '/public/home/business_big_logo.svg'; // import menuFooter from '/public/menuFooter.svg'; import './index.less'; @@ -104,10 +105,21 @@ const MenuBar: React.FC = ({ menuData, changeMenu }) => { return (
-
- - {getStoreBusinessInfo()?.name} +
+
{ + history.replace('/'); + }} + > + +
+
+ + {getStoreBusinessInfo()?.name} +
+ {/* // TODO 菜单需要补充路由聚焦状态 */}
= ({ menuData, changeMenu }) => { ))}
- {/*
- -
*/}
); }; diff --git a/src/components/Tree/index.ts b/src/components/Tree/index.ts new file mode 100644 index 0000000..53c59fd --- /dev/null +++ b/src/components/Tree/index.ts @@ -0,0 +1,3 @@ +import deviceGroupTree from './src/deviceGroupTree'; + +export const DeviceGroupTree = deviceGroupTree; diff --git a/src/components/Tree/src/baseTree.css b/src/components/Tree/src/baseTree.css new file mode 100644 index 0000000..e309232 --- /dev/null +++ b/src/components/Tree/src/baseTree.css @@ -0,0 +1,47 @@ +.base_tree_wrap { + font-size: 14px; +} +.base_tree_wrap > .ant-form-item { + margin-bottom: 0; +} +.base_tree_wrap > .ant-form-item .ant-input-outlined { + border: none; +} +.base_tree_wrap > .ant-form-item .ant-input:focus, +.base_tree_wrap > .ant-form-item .ant-input-focused { + border: none; + box-shadow: none; + /* 去掉聚焦时的阴影效果 */ + /* 如果需要,你也可以调整其他聚焦时的样式 */ +} +.base_tree_wrap > .ant-form-item .ant-input-outlined:focus, +.base_tree_wrap > .ant-form-item .ant-input-outlined:focus-within { + box-shadow: none; + /* 去掉聚焦时的阴影效果 */ +} +.base_tree_wrap .tree_node_1 { + width: 100%; + margin: 12px 0; + padding: 8px 17px; + background: #f5f5f5; + border-radius: 4px; + cursor: pointer; +} +.base_tree_wrap .tree_node_1 .ant-tree-switcher-noop { + opacity: 0; +} +.base_tree_wrap .tree_node_item .action_list { + display: none; +} +.base_tree_wrap .tree_node_1:hover, +.base_tree_wrap .ant-tree-treenode-selected { + color: #154ddd; + background: rgba(21, 77, 221, 0.1); + border-radius: 8px; +} +.base_tree_wrap .tree_node_item:hover .action_list { + display: block; +} +.base_tree_wrap .tree_node_item:hover .action_list .anticon-delete { + color: #e80d0d; +} diff --git a/src/components/Tree/src/baseTree.less b/src/components/Tree/src/baseTree.less new file mode 100644 index 0000000..ddc6b68 --- /dev/null +++ b/src/components/Tree/src/baseTree.less @@ -0,0 +1,53 @@ +.base_tree_wrap { + font-size: 14px; + & > .ant-form-item { + margin-bottom: 0; + .ant-input-outlined { + border: none; + } + .ant-input:focus, + .ant-input-focused { + border: none; + box-shadow: none; /* 去掉聚焦时的阴影效果 */ + /* 如果需要,你也可以调整其他聚焦时的样式 */ + } + .ant-input-outlined:focus, + .ant-input-outlined:focus-within { + box-shadow: none; /* 去掉聚焦时的阴影效果 */ + } + } + + .tree_node_1 { + width: 100%; + margin: 12px 0; + padding: 8px 17px; + background: #f5f5f5; + border-radius: 4px; + cursor: pointer; + .ant-tree-switcher-noop { + opacity: 0; + } + } + .tree_node_item { + .action_list { + display: none; + } + } + .tree_node_1:hover, + .ant-tree-treenode-selected { + color: #154ddd; + background: rgba(21, 77, 221, 0.1); + border-radius: 8px; + } + .tree_node_item:hover { + // color: #154ddd; + // background: rgba(21, 77, 221, 0.1); + // border-radius: 8px; + .action_list { + display: block; + .anticon-delete { + color: #e80d0d; + } + } + } +} diff --git a/src/components/Tree/src/baseTree.tsx b/src/components/Tree/src/baseTree.tsx new file mode 100644 index 0000000..7712e38 --- /dev/null +++ b/src/components/Tree/src/baseTree.tsx @@ -0,0 +1,247 @@ +import { formatTreeValByKey } from '@/utils/baseTree'; +import { DeleteFilled, SearchOutlined } from '@ant-design/icons'; +import { Button, Form, Input, Modal, Tree } from 'antd'; +import _debounce from 'lodash/debounce'; +import React, { useEffect, useState } from 'react'; +import { BaseTreeProps } from '../typing'; + +import { ProFormText } from '@ant-design/pro-components'; +import './baseTree.less'; +const { TreeNode } = Tree; + +const BaseTree: React.FC = (props) => { + /**state */ + // const { token } = theme.useToken(); + + const { treeData, ...defaultProps } = props; + console.log(treeData, 'treeData', defaultProps); + const [currTreeData, setCurrTreeData] = useState([ + // { title: '节点1', key: '1' }, + // { title: '节点2', key: '2', children: [{ title: '子节点1', key: '3' }] }, + ]); + + const [visible, setVisible] = useState(false); + const [editNodeKey, setEditNodeKey] = useState(null); + const [form] = Form.useForm(); + const action_add_key = ''; + + /**工具方法集 */ + // 柯里化-树的节点数值 + function formatTreeValByNodeKey( + key: 'title' | 'key' | 'children', + node: Record, + ): any { + return formatTreeValByKey(key, node, props.fieldNames); + } + + /**查询树节点 */ + // 定义一个防抖处理函数,500ms 后执行 handleChange 函数 + const debouncedHandleChange = _debounce((value) => { + // TODO 查询所有匹配的节点 + console.log('debouncedHandleChange_value:', value); + }, 500); + // 搜索节点 + function handleSearch(val) { + debouncedHandleChange(val); + } + + const handleAddNode = () => { + // setVisible(true); + // form.resetFields(); + }; + + // const getNodeByKey = (key) => { + // return currTreeData.find((node) => node.key === key); + // }; + + // const removeNodeByKey = (data, key) => { + // return data.filter((node) => { + // if (node.key === key) { + // return false; + // } + // if (node.children) { + // node.children = removeNodeByKey(node.children, key); + // } + // return true; + // }); + // }; + + // const handleEditNode = (key) => { + // setEditNodeKey(key); + // setVisible(true); + // form.setFieldsValue({ nodeTitle: getNodeByKey(key).title }); + // }; + + // const handleDeleteNode = (key) => { + // const newData = removeNodeByKey(currTreeData, key); + // setCurrTreeData(newData); + // }; + + // const handleAddChildNode = (key) => { + // setEditNodeKey(key); + // setVisible(true); + // form.resetFields(); + // }; + + // 组装节点数据 + const handleModalOk = () => { + form.validateFields().then((values) => { + const { nodeTitle } = values; + let newData; + if (editNodeKey) { + // 编辑节点标题 + newData = currTreeData.map((node) => { + if (node.key === editNodeKey) { + return { ...node, title: nodeTitle }; + } + return node; + }); + } else if (editNodeKey === null) { + // 新增根节点 + newData = [...currTreeData, { title: nodeTitle, key: Date.now().toString() }]; + } else { + // 新增子节点 + newData = currTreeData.map((node) => { + if (node.key === editNodeKey) { + return { + ...node, + children: [ + ...(node.children || []), + { title: nodeTitle, key: Date.now().toString() }, + ], + }; + } + return node; + }); + } + console.log('handleModalOk_newData', newData); + setCurrTreeData(newData); + setVisible(false); + setEditNodeKey(''); + }); + }; + + const handleModalCancel = () => { + setVisible(false); + setEditNodeKey(''); + }; + + // render 新增节点操作 + const renderAddAction = (node?: Record) => { + // console.log(node, 'renderAddAction_node'); + return props?.addRender ? ( + props?.addRender(node) + ) : ( +
+ +
+ ); + }; + + // 定义每个节点内容 递归操作 + const renderTreeNodes = (data) => { + if (Array.isArray(data) && data.length) { + return data.map((node) => { + return ( + + {formatTreeValByNodeKey('children', node) && + renderTreeNodes(formatTreeValByNodeKey('children', node))} + + + + ); + }); + } + return <>; + }; + // 渲染每个节点内容 + const renderTreeItem = (node) => { + return ( +
+ {node.title} + {!props?.hideInDelete ? ( + { + props.handleDelete(node); + }} + > + + + ) : ( + <> + )} +
+ ); + }; + + useEffect(() => { + setCurrTreeData(props.treeData); + console.log(props.treeData, 'props_treeData'); + }, [props.treeData]); + + return ( +
+ {!props?.hideInSearch ? ( + handleSearch(e.target.value)} + key="name" + name="name" + label="" + fieldProps={{ + style: { + margin: 0, + }, + prefix: , + }} + /> + ) : ( + <> + )} + { + console.log('selected', selectedKeys); + props.selectTree(selectedKeys, info); + }} + titleRender={(node) => { + if (node.title) { + return renderTreeItem(node); + } + return renderAddAction(node); + }} + {...defaultProps} + > + {renderTreeNodes(currTreeData)} + +
{renderAddAction()}
+ {/*
添加一级节点
*/} + + {/* TODO 使用ProForm */} + +
+ + + +
+
+
+ ); +}; + +export default BaseTree; diff --git a/src/components/Tree/src/deviceGroupTree.tsx b/src/components/Tree/src/deviceGroupTree.tsx new file mode 100644 index 0000000..b0568ea --- /dev/null +++ b/src/components/Tree/src/deviceGroupTree.tsx @@ -0,0 +1,72 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-26 11:11:05 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-29 16:26:05 + * @FilePath: \general-ai-manage\src\components\Tree\src\deviceGroupTree.tsx + * @Description: 设备节点树 + * @交互说明 + * 1、树形展示 + * 2、可新增、删除 + * 3、可编辑 + * 4、可拖拽 + */ +import { PlusCircleOutlined } from '@ant-design/icons'; +import React from 'react'; + +import { theme } from 'antd'; +import { DeviceGroupTreeProps } from '../typing'; +import BaseTree from './baseTree'; +const DeviceGroupTree: React.FC = (props) => { + const { token } = theme.useToken(); + console.log('token', token); + + // async function loadTree() { + // const resp = await getDeviceGroupSettingTree() + // setDeviceGroupList(resp.data) + // } + + // useEffect(()=>{ + // loadTree() + // },[]) + + // const [expandedKeys] = useState(['0-0', '0-0-0', '0-0-0-0']); + function handleAdd(node) { + // 当前节点的父节点 可以添加数据 + console.log(node, 'handleAdd_node'); + props.addTreeNode(node); + } + + return ( +
+ { + return ( +
{ + handleAdd(node); + }} + style={{ color: token.colorPrimary }} + key={node?.key || 'add'} + > + + {node?.key ? '添加子节点' : '添加节点'} +
+ ); + }} + handleDelete={(node) => { + // 提示删除 + console.log('handleDelete_node', node); + }} + selectTree={(selectedKeys, info) => { + props.selectTree(selectedKeys, info); + }} + >
+ {/* 新增节点 修改节点 */} +
+ ); +}; + +export default DeviceGroupTree; diff --git a/src/components/Tree/typing.ts b/src/components/Tree/typing.ts new file mode 100644 index 0000000..96961cc --- /dev/null +++ b/src/components/Tree/typing.ts @@ -0,0 +1,25 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-26 11:09:49 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-29 16:24:05 + * @FilePath: \general-ai-platform-web\src\components\Tree\typing.ts + * @Description: 树的类型文件 + */ + +// 增删改查基础树 +export interface BaseTreeProps extends TreeProps { + hideInAdd?: boolean; // 是否隐藏新增节点 + // hideInEdit?: boolean // 是否隐藏编辑节点 + hideInDelete?: boolean; // 是否隐藏删除节点 + hideInSearch?: boolean; // 是否隐藏筛选节点 + addRender?: React.ReactNode; // 新增操作自定义 + addText?: string | React.ReactNode; // 新增按钮文案自定义 + deleteRender?: React.ReactNode; // 删除操作自定义 + deleteText?: string | React.ReactNode; // 删除按钮文案自定义 +} +// 节点树 +export interface DeviceGroupTreeProps extends BaseTreeProps { + addTreeNode?: (arg1: Record) => void; + selectTree: (arg1: any, arg2: any) => void; +} diff --git a/src/enums/deviceGroup.ts b/src/enums/deviceGroup.ts new file mode 100644 index 0000000..9e8f4e6 --- /dev/null +++ b/src/enums/deviceGroup.ts @@ -0,0 +1,23 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-28 15:30:31 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-28 15:32:43 + * @FilePath: \general-ai-platform-web\src\enums\device.ts + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +// 告警规则 +export const deviceGroupEnums: Record[] = [ + { + label: '设备列表', + key: '1', + }, + { + label: '业务模型部署', + key: '2', + }, + { + label: '告警设置', + key: '3', + }, +]; diff --git a/src/global.css b/src/global.css index fe98fc1..1137dec 100644 --- a/src/global.css +++ b/src/global.css @@ -88,6 +88,9 @@ ol { .gn_form .ant-pro-form-group-container { gap: 0px 12px !important; } +.gn_modal_form { + margin-top: 16px; +} .gn_table_query_filter { padding: 20px 0; } @@ -114,14 +117,12 @@ ol { margin-right: 0; } .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item .ant-steps-item-container { + position: relative; display: flex; align-items: center; justify-content: center; margin: 8px 0; } -.gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item .ant-steps-item-tail { - display: none; -} .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item .ant-steps-item-icon { margin: 0 8px; } @@ -137,6 +138,21 @@ ol { color: #666666; font-size: 12px; } +.gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item .ant-steps-item-tail { + position: absolute; + top: auto; + left: calc(100% - 30px); + width: 16px; + height: 16px; + margin: 0; + padding: 0; + background: url('../public/home/business_arrow_default.svg') no-repeat; + background-size: cover; + border: none; +} +.gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item .ant-steps-item-tail:after { + background: transparent; +} .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-finish { background: #e5edff; border: 1px solid #154ddd; @@ -153,6 +169,10 @@ ol { .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-finish .ant-steps-item-description { color: #154ddd; } +.gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-finish .ant-steps-item-tail { + background: url('../public/home/business_arrow.svg') no-repeat; + background-size: cover; +} .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-active { background: #e5edff; border: 1px solid #154ddd; @@ -163,10 +183,15 @@ ol { .gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-active .ant-steps-item-description { color: #154ddd; } +.gn_model_steps_form .ant-modal-content .ant-modal-body .ant-steps .ant-steps-item-active .ant-steps-item-tail { + background: url('../public/home/business_arrow.svg') no-repeat; + background-size: cover; +} /* Descriptions */ .gn_table_descriptions { padding: 16px 16px 0; background: #ffffff; + border: 1px solid rgba(21, 77, 221, 0.1); border-radius: 8px; } /* ProTable ProList */ @@ -188,6 +213,21 @@ ol { padding: 0; } /* 主题样式 */ +.ant-btn-primary, +.ant-btn-primary:not(:disabled):not(.ant-btn-disabled):hover { + background-color: #154ddd; +} +.ant-btn-default:not(:disabled):not(.ant-btn-disabled):hover, +.ant-btn-link { + color: #154ddd; +} +:where(.css-dev-only-do-not-override-42nv3w).ant-btn-default:not(:disabled):not( + .ant-btn-disabled + ):hover { + color: #154ddd; + background: #ffffff; + border-color: #154ddd; +} /* 单行文本溢出显示省略号 */ .single_line { overflow: hidden; diff --git a/src/global.less b/src/global.less index 37f1a3f..f9b5053 100644 --- a/src/global.less +++ b/src/global.less @@ -114,6 +114,9 @@ ol { gap: 0px 12px !important; } } +.gn_modal_form { + margin-top: 16px; +} // 筛选表单 .gn_table_query_filter { @@ -147,14 +150,13 @@ ol { } .ant-steps-item-container { + position: relative; display: flex; align-items: center; justify-content: center; margin: 8px 0; } - .ant-steps-item-tail { - display: none; - } + .ant-steps-item-icon { margin: 0 8px; } @@ -170,6 +172,25 @@ ol { color: #666666; font-size: 12px; } + + .ant-steps-item-tail { + // display: none; + position: absolute; + top: auto; + left: calc(100% - 30px); + width: 16px; + height: 16px; + margin: 0; + padding: 0; + // background-color: red; + background: url('../public/home/business_arrow_default.svg') no-repeat; + background-size: cover; + border: none; + // right: -10px; + &:after { + background: transparent; + } + } } // 已完成 @@ -188,6 +209,10 @@ ol { .ant-steps-item-description { color: #154ddd; } + .ant-steps-item-tail { + background: url('../public/home/business_arrow.svg') no-repeat; + background-size: cover; + } } // 当前选中 .ant-steps-item-active { @@ -199,6 +224,10 @@ ol { .ant-steps-item-description { color: #154ddd; } + .ant-steps-item-tail { + background: url('../public/home/business_arrow.svg') no-repeat; + background-size: cover; + } } } } @@ -208,6 +237,7 @@ ol { .gn_table_descriptions { padding: 16px 16px 0; background: #ffffff; + border: 1px solid rgba(21, 77, 221, 0.1); border-radius: 8px; } @@ -235,21 +265,21 @@ ol { } /* 主题样式 */ -// .ant-btn-primary, -// .ant-btn-primary:not(:disabled):not(.ant-btn-disabled):hover { -// background-color: @theme_color; -// } -// .ant-btn-default:not(:disabled):not(.ant-btn-disabled):hover, -// .ant-btn-link { -// color: @theme_color; -// } -// :where(.css-dev-only-do-not-override-42nv3w).ant-btn-default:not(:disabled):not( -// .ant-btn-disabled -// ):hover { -// color: @theme_color; -// background: #ffffff; -// border-color: @theme_color; -// } +.ant-btn-primary, +.ant-btn-primary:not(:disabled):not(.ant-btn-disabled):hover { + background-color: @theme_color; +} +.ant-btn-default:not(:disabled):not(.ant-btn-disabled):hover, +.ant-btn-link { + color: @theme_color; +} +:where(.css-dev-only-do-not-override-42nv3w).ant-btn-default:not(:disabled):not( + .ant-btn-disabled + ):hover { + color: @theme_color; + background: #ffffff; + border-color: @theme_color; +} /* 单行文本溢出显示省略号 */ .single_line { diff --git a/src/locales/zh-CN/device.ts b/src/locales/zh-CN/device.ts index e0a575b..36647e9 100644 --- a/src/locales/zh-CN/device.ts +++ b/src/locales/zh-CN/device.ts @@ -1,28 +1,74 @@ /* * @Author: zhoux zhouxia@supervision.ltd * @Date: 2023-11-01 13:56:33 - * @LastEditors: zhoux zhouxia@supervision.ltd - * @LastEditTime: 2023-11-21 14:23:38 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-29 17:37:55 * @FilePath: \general-ai-platform-web\src\locales\zh-CN\device.ts - * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + * @Description: 设备相关 */ -export const device: { [key: string]: string } = { - 'device.device.table.list.id': 'ID', - 'device.device.table.list.name': '设备名称', - 'device.device.table.list.code': '设备代码', - 'device.device.table.list.position': '位置', - 'device.device.table.list.param': '设备参数', - 'device.device.table.list.spec': '设备规格', - 'device.device.table.list.categoryFkId': '设备类别', - 'device.device.table.list.groupFkId': '设备分组', - 'device.device.table.list.isEnable': '是否启用', - 'device.device.table.list.remark': '备注', - 'device.device.table.list.createTime': '创建时间', - 'device.device.table.list.updateTime': '更新时间', - 'device.device.table.rule.required.name': '设备名称为必填项', - 'device.device.table.rule.required.code': '设备代码为必填项', - 'device.device.table.list.add': '新建设备', - 'device.device.table.list.update': '更新设备', +// 节点设置 +export const device_group: { [key: string]: string } = { + 'device_group.tree_node.name': '节点名称', + 'device_group.tree_node.rule.required.name': '请填写节点名称', + 'device_group.tree_node.fatherName': '上级节点', + 'device_group.tree_node.lon': '经度', + 'device_group.tree_node.lat': '纬度', + 'device_group.tree_node.address': '地址', + 'device_group.tree_node.lonlat': '经纬度', + 'device_group.tree_node.managerName': '负责人', + 'device_group.tree_node.managerPhone': '联系方式', + 'device_group.tree_node.remark': '简介', + 'device_group.tree_node.createForm.add': '新建节点', + // 未启用 + + 'device_group.table.list.id': 'ID', + 'device_group.table.list.name': '分组名称', + 'device_group.table.list.code': '分组代码', + 'device_group.table.list.address': '地址', + 'device_group.table.list.telephone': '电话', + 'device_group.table.list.lon': '经度', + 'device_group.table.list.lat': '纬度', + 'device_group.table.list.managerName': '负责人姓名', + 'device_group.table.list.managerPhone': '负责人联系方式', + 'device_group.table.list.isEnable': '是否启用', + 'device_group.table.list.parentFkId': '父节点', + 'device_group.table.list.remark': '备注', + 'device_group.table.list.createTime': '创建时间', + 'device_group.table.list.updateTime': '更新时间', + 'device_group.table.rule.required.name': '分组名称为必填项', + 'device_group.table.rule.required.code': '分组代码为必填项', + 'device_group.table.rule.required.managerName': '负责人姓名为必填项', + 'device_group.table.rule.required.managerPhone': '负责人联系方式为必填项', + 'device_group.table.rule.required.parentFkId': '父节点为必填项', + 'device_group.table.list.add': '新建设备分组', + 'device_group.table.list.update': '更新设备分组', + 'device_group.table.list.treeAdd': '添加根节点', +}; + +export const device_group_list: { [key: string]: string } = { + 'device_group_list.table.list.name': '设备名称', + 'device_group_list.table.list.deviceType': '设备类型', + 'device_group_list.table.list.isEnable': '模型部署', + 'device_group_list.table.list.deployed.isEnable': '已部署', + 'device_group_list.table.list.undeployed.isEnable': '未部署', + 'device_group_list.table.list.action.setModel': '基础模型配置', + 'device_group_list.table.list.action.new': '新建设备', + 'device_group_list.table.list.action.modelType': '设备分类', + + // 未启用 + 'device_group_list.table.list.code': '设备代码', + 'device_group_list.table.list.position': '位置', + 'device_group_list.table.list.param': '设备参数', + 'device_group_list.table.list.spec': '设备规格', + 'device_group_list.table.list.categoryFkId': '设备类别', + 'device_group_list.table.list.groupFkId': '设备分组', + 'device_group_list.table.list.remark': '备注', + 'device_group_list.table.list.createTime': '创建时间', + 'device_group_list.table.list.updateTime': '更新时间', + 'device_group_list.table.rule.required.name': '设备名称为必填项', + 'device_group_list.table.rule.required.code': '设备代码为必填项', + 'device_group_list.table.list.add': '新建设备', + 'device_group_list.table.list.update': '更新设备', }; export const device_category: { [key: string]: string } = { 'device.device_category.table.list.id': 'ID', @@ -36,30 +82,7 @@ export const device_category: { [key: string]: string } = { 'device.device_category.table.list.add': '新建设备类别', 'device.device_category.table.list.update': '更新设备类别', }; -export const device_group: { [key: string]: string } = { - 'device.device_group.table.list.id': 'ID', - 'device.device_group.table.list.name': '分组名称', - 'device.device_group.table.list.code': '分组代码', - 'device.device_group.table.list.address': '地址', - 'device.device_group.table.list.telephone': '电话', - 'device.device_group.table.list.lon': '经度', - 'device.device_group.table.list.lat': '纬度', - 'device.device_group.table.list.managerName': '负责人姓名', - 'device.device_group.table.list.managerPhone': '负责人联系方式', - 'device.device_group.table.list.isEnable': '是否启用', - 'device.device_group.table.list.parentFkId': '父节点', - 'device.device_group.table.list.remark': '备注', - 'device.device_group.table.list.createTime': '创建时间', - 'device.device_group.table.list.updateTime': '更新时间', - 'device.device_group.table.rule.required.name': '分组名称为必填项', - 'device.device_group.table.rule.required.code': '分组代码为必填项', - 'device.device_group.table.rule.required.managerName': '负责人姓名为必填项', - 'device.device_group.table.rule.required.managerPhone': '负责人联系方式为必填项', - 'device.device_group.table.rule.required.parentFkId': '父节点为必填项', - 'device.device_group.table.list.add': '新建设备分组', - 'device.device_group.table.list.update': '更新设备分组', - 'device.device_group.table.list.treeAdd': '添加根节点', -}; + export const device_relation: { [key: string]: string } = { 'device.device_relation.table.list.id': 'ID', 'device.device_relation.table.list.deviceParentFkId': '设备父节点', diff --git a/src/locales/zh-CN/menu.ts b/src/locales/zh-CN/menu.ts index 253d18f..4d81026 100644 --- a/src/locales/zh-CN/menu.ts +++ b/src/locales/zh-CN/menu.ts @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-01 11:20:09 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-23 10:51:24 + * @LastEditTime: 2024-04-26 09:36:38 * @FilePath: \uighur-recognition-web2\src\locales\zh-CN\menu.ts * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ @@ -64,7 +64,7 @@ export default { 'menu.model-runtime-lib': '模型运行库', 'menu.business-info-index': '企业信息', - 'menu.business-node-setting': '节点设置', + 'menu.business-device-group': '节点设置', 'menu.business-model-index': '业务模型', // 待废弃 'menu.realTime': '实时分析', diff --git a/src/pages/Business/DeviceGroup/components/baseInfo.tsx b/src/pages/Business/DeviceGroup/components/baseInfo.tsx new file mode 100644 index 0000000..e44801c --- /dev/null +++ b/src/pages/Business/DeviceGroup/components/baseInfo.tsx @@ -0,0 +1,62 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-23 17:00:00 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-28 17:55:58 + * @FilePath: \general-ai-platform-web\src\pages\Business\DeviceGroup\components\baseInfo.tsx + * @Description: 基本信息展示 + * + */ + +import { ProDescriptions } from '@ant-design/pro-components'; +import { FormattedMessage } from '@umijs/max'; + +type BaseInfoProps = { + info: Record; +}; + +const BaseInfo: React.FC = ({ info }) => { + // 设备基本信息 + const DeviceDetailColumns = [ + { + title: , + dataIndex: 'name', + }, + { + title: , + dataIndex: 'fatherName', + }, + { + title: , + dataIndex: 'address', + }, + { + title: , + dataIndex: 'lonlat', + render: (_, record) => { + return record?.lon + ',' + record?.lat; + }, + }, + { + title: , + dataIndex: 'managerName', + }, + { + title: ( + + ), + dataIndex: 'managerPhone', + }, + { + title: , + dataIndex: 'remark', + }, + ]; + return ( +
+ +
+ ); +}; + +export default BaseInfo; diff --git a/src/pages/Business/DeviceGroup/components/createDeviceForm.tsx b/src/pages/Business/DeviceGroup/components/createDeviceForm.tsx new file mode 100644 index 0000000..4e8ecad --- /dev/null +++ b/src/pages/Business/DeviceGroup/components/createDeviceForm.tsx @@ -0,0 +1,175 @@ +// import { postModelCategoryCreateModelCategory } from '@/services/resource/ModelCategory'; +import { ModalForm, ProForm, ProFormText, ProFormTextArea } from '@ant-design/pro-components'; +import { FormattedMessage, useIntl } from '@umijs/max'; +import { Form } from 'antd'; +import React from 'react'; +import { + proFormSmallItemStyleProps, + proFormSmallModelWidth, +} from '../../../../../config/defaultForm'; +// @ts-ignore + +export type CreateDeviceFormProps = { + createModalOpen: boolean; + handleModal: () => void; + reload: any; +}; +const CreateDeviceForm: React.FC = (props) => { + const intl = useIntl(); + // const [isAuto, setIsAuto] = useState(true); + const [form] = Form.useForm(); + + return ( + + className="gn_modal_form gn_form" + width={proFormSmallModelWidth} + title={intl.formatMessage({ + id: 'device_group.tree_node.CreateDeviceForm.add', + defaultMessage: '新建', + })} + open={props.createModalOpen} + form={form} + autoFocusFirstInput + modalProps={{ + destroyOnClose: true, + onCancel: () => props.handleModal(), + }} + submitTimeout={2000} + onFinish={async (values) => { + console.log(values, 'add_finish_values'); + // TODO 对接新增接口 + // postModelCategoryCreateModelCategory(values) + // .then(() => { + // message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' })); + // props.reload(); + // }) + // .catch(() => { + // message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' })); + // }); + props.handleModal(); + return true; + }} + > + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.name', + defaultMessage: '$$$', + })}`} + required={true} + rules={[ + { + required: true, + message: ( + + ), + }, + ]} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.fatherName', + defaultMessage: '$$$', + })}`} + disabled + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.address', + defaultMessage: '$$$', + })}`} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.lon', + defaultMessage: '$$$', + })}`} + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.lat', + defaultMessage: '$$$', + })}`} + /> + + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.managerName', + defaultMessage: '$$$', + })}`} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.managerPhone', + defaultMessage: '$$$', + })}`} + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.remark', + defaultMessage: '$$$', + })}`} + /> + + + ); +}; +export default CreateDeviceForm; diff --git a/src/pages/Business/DeviceGroup/components/createForm.tsx b/src/pages/Business/DeviceGroup/components/createForm.tsx new file mode 100644 index 0000000..abaabd3 --- /dev/null +++ b/src/pages/Business/DeviceGroup/components/createForm.tsx @@ -0,0 +1,176 @@ +// import { postModelCategoryCreateModelCategory } from '@/services/resource/ModelCategory'; +import { ModalForm, ProForm, ProFormText, ProFormTextArea } from '@ant-design/pro-components'; +import { FormattedMessage, useIntl } from '@umijs/max'; +import { Form } from 'antd'; +import React from 'react'; +import { + proFormSmallItemStyleProps, + proFormSmallModelWidth, +} from '../../../../../config/defaultForm'; +// @ts-ignore + +export type CreateFormProps = { + createModalOpen: boolean; + handleModal: () => void; + parentInfo?: Record; + reload: any; +}; +const CreateForm: React.FC = (props) => { + const intl = useIntl(); + // const [isAuto, setIsAuto] = useState(true); + const [form] = Form.useForm(); + + return ( + + className="gn_modal_form gn_form" + width={proFormSmallModelWidth} + title={intl.formatMessage({ + id: 'device_group.tree_node.createForm.add', + defaultMessage: '新建', + })} + open={props.createModalOpen} + form={form} + autoFocusFirstInput + modalProps={{ + destroyOnClose: true, + onCancel: () => props.handleModal(), + }} + submitTimeout={2000} + onFinish={async (values) => { + console.log(values, 'add_finish_values'); + // TODO 对接新增接口 + // postModelCategoryCreateModelCategory(values) + // .then(() => { + // message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' })); + // props.reload(); + // }) + // .catch(() => { + // message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' })); + // }); + props.handleModal(); + return true; + }} + > + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.name', + defaultMessage: '$$$', + })}`} + required={true} + rules={[ + { + required: true, + message: ( + + ), + }, + ]} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.fatherName', + defaultMessage: '$$$', + })}`} + disabled + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.address', + defaultMessage: '$$$', + })}`} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.lon', + defaultMessage: '$$$', + })}`} + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.lat', + defaultMessage: '$$$', + })}`} + /> + + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.managerName', + defaultMessage: '$$$', + })}`} + /> + + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.managerPhone', + defaultMessage: '$$$', + })}`} + /> + } + placeholder={`${intl.formatMessage({ + id: 'common.please_input', + defaultMessage: '$$$', + })}${intl.formatMessage({ + id: 'device_group.tree_node.remark', + defaultMessage: '$$$', + })}`} + /> + + + ); +}; +export default CreateForm; diff --git a/src/pages/Business/DeviceGroup/components/deviceList.tsx b/src/pages/Business/DeviceGroup/components/deviceList.tsx new file mode 100644 index 0000000..6e412ba --- /dev/null +++ b/src/pages/Business/DeviceGroup/components/deviceList.tsx @@ -0,0 +1,246 @@ +import TableActionCard from '@/components/TableActionCard'; +import { getDeviceListByGroup } from '@/services/testApi/device'; +import { ProTable } from '@ant-design/pro-components'; +import { Access, FormattedMessage, history, useAccess } from '@umijs/max'; +import { Button } from 'antd'; +import { useRef, useState } from 'react'; + +import { proTablePaginationOptions } from '../../../../../config/defaultTable'; + +import IsDelete from '@/components/TableActionCard/isDelete'; +import CreateDeviceForm from './createDeviceForm'; + +type DeviceListProps = { + info: Record; +}; + +const DeviceList: React.FC = () => { + const access = useAccess(); + // const intl = useIntl(); + const actionRef = useRef(); + + const [createModalOpen, setCreateModalOpen] = useState(false); + // const [categoryFkIdIds, setCategoryFkIdIds] = useState([]); + // 动态设置每页数量 + const [currentPageSize, setCurrentPageSize] = useState(10); + + /**新增 编辑 删除 */ + // 新增 + const handleCreateModal = () => { + setCreateModalOpen(!createModalOpen); + }; + + function reloadList() { + actionRef.current?.reload(); + } + + const columns: ProColumns>[] = [ + { + title: , + dataIndex: 'name', + hideInSearch: true, + // width: 80, + // key: 'fixedName', + // fixed: 'left', + }, + { + title: ( + + ), + dataIndex: 'deviceType', + hideInSearch: true, + // width: 120, + }, + { + title: ( + + ), + dataIndex: 'isEnable', + hideInSearch: true, + // width: 80, + render: (dom, record) => { + return ( +
+ + + {record.isEnable ? ( + + ) : ( + + )} + +
+ ); + }, + }, + + { + title: , + dataIndex: 'option', + valueType: 'option', + fixed: 'right', + key: 'option', + render: (_, record) => [ + { + // setCurrentRow(record); + // history.push('/home/model-detail'); + // doToDetail(record); + // setShowDetail(true); + }} + > + + + ), + }, + { + key: 'updateDetail', + renderDom: ( + + ), + }, + { + key: 'destroy', + renderDom: ( + { + handleDestroy(record).then(() => {}); + }} + > + ), + }, + ]} + >, + ], + }, + ]; + + return ( +
+ [ + +
+ + +
+
, + ]} + search={false} + // scroll={{ y: proTableCommonOptions.commscrollY, x: proTableCommonOptions.commscrollX }} + options={{ fullScreen: false, setting: false, density: false, reload: false }} + actionRef={actionRef} + rowKey="key" + onDataSourceChange={(data) => { + console.log(data, 'onDataSourceChange_data'); + // let CategoryFkIdIds: any = data.map((v) => { + // return v.categoryFkId; + // }); + // setCategoryFkIdIds(CategoryFkIdIds); + }} + pagination={{ + ...proTablePaginationOptions, + pageSize: currentPageSize, + onChange: (page, pageSize) => setCurrentPageSize(pageSize), + }} + columnsState={{ + persistenceKey: 'algorithm_model_list', + persistenceType: 'localStorage', + }} + request={async (params = {}) => { + const { current, ...rest } = params; + const reqParams = { + page: current, + ...rest, + }; + let resp = await getDeviceListByGroup({ ...reqParams }); + console.log(resp, 'getDeviceListByGroup_resp'); + return { + data: resp.data?.results.map((v: Record) => { + return { ...v, key: v.id }; + }), + success: resp.success, + total: resp.data.count, + current: current, + pageSize: currentPageSize, + }; + }} + columns={columns} + /> + +
+ ); +}; + +export default DeviceList; diff --git a/src/pages/Business/DeviceGroup/index.css b/src/pages/Business/DeviceGroup/index.css new file mode 100644 index 0000000..77af702 --- /dev/null +++ b/src/pages/Business/DeviceGroup/index.css @@ -0,0 +1,37 @@ +.deviceGroup_page { + height: calc(100vh - 92px); + /* 节点列表 */ + /* 节点信息 */ +} +.deviceGroup_page .dg_content .gn_card { + height: calc(100% - 8px); +} +.deviceGroup_page .node_list > .gn_card { + box-shadow: 0px 2px 8px 0px rgba(0, 79, 178, 0.15); +} +.deviceGroup_page .node_info { + padding-left: 0; +} +.dg_deviceList_wrap .model_index_type_tag { + width: 82px; + height: 24px; + color: #52C41A; + background: #E8F7E6; + border: 1px solid #BAEEA1; + border-radius: 12px; +} +.dg_deviceList_wrap .model_index_type_tag .dot { + width: 6px; + height: 6px; + margin-right: 4px; + background: #52C41A; + border-radius: 50%; +} +.dg_deviceList_wrap .model_index_type_tag.active2 { + color: #E80D0D; + background: #FEEFEE; + border: 1px solid #F9B2AE; +} +.dg_deviceList_wrap .model_index_type_tag.active2 .dot { + background: #E80D0D; +} diff --git a/src/pages/Business/DeviceGroup/index.less b/src/pages/Business/DeviceGroup/index.less new file mode 100644 index 0000000..b17d451 --- /dev/null +++ b/src/pages/Business/DeviceGroup/index.less @@ -0,0 +1,45 @@ +.deviceGroup_page { + height: calc(100vh - 92px); + .dg_content { + .gn_card { + height: calc(100% - 8px); + } + } + /* 节点列表 */ + .node_list { + & > .gn_card { + box-shadow: 0px 2px 8px 0px rgba(0, 79, 178, 0.15); + } + } + /* 节点信息 */ + .node_info { + padding-left: 0; + } +} + +.dg_deviceList_wrap { + .model_index_type_tag { + width: 82px; + height: 24px; + color: #52c41a; + background: #e8f7e6; + border: 1px solid #baeea1; + border-radius: 12px; + + .dot { + width: 6px; + height: 6px; + margin-right: 4px; + background: #52c41a; + border-radius: 50%; + } + &.active2 { + color: #e80d0d; + background: #feefee; + border: 1px solid #f9b2ae; + .dot { + background: #e80d0d; + } + } + } +} diff --git a/src/pages/Business/DeviceGroup/index.tsx b/src/pages/Business/DeviceGroup/index.tsx new file mode 100644 index 0000000..e59db12 --- /dev/null +++ b/src/pages/Business/DeviceGroup/index.tsx @@ -0,0 +1,136 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-22 15:23:36 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-29 16:50:22 + * @FilePath: \general-ai-platform-web\src\pages\Business\DeviceGroup\index.tsx + * @Description: 设备节点设置 关键词 deviceGroup(dg) + * @交互说明 + * 1、节点列表的查看、添加、删除 + * 2、节点基本信息展示 + * 3、设备列表分页查看、新建、编辑、删除、设备分类、基础模型配置 + * 4、业务模型部署配置参数 + * 5、企业告警设置 + */ +import { DeviceGroupTree } from '@/components/Tree'; +import { deviceGroupEnums } from '@/enums/deviceGroup'; +import { getDeviceGroupList } from '@/services/testApi/deviceGroup'; +import { ProCard } from '@ant-design/pro-components'; +import { Button, Tabs } from 'antd'; +import { useEffect, useState } from 'react'; +import BaseInfo from './components/baseInfo'; +import CreateForm from './components/createForm'; +import DeviceList from './components/deviceList'; + +import './index.less'; + +const DeviceGroup: React.FC = () => { + /**state */ + // 节点信息 + const [deviceTreeList, setDeviceTreeList] = useState[]>([]); + const [nodeInfo, setNodeInfo] = useState>({}); // 当前节点信息 + const [createModalOpen, setCreateModalOpen] = useState(false); // 创建新增窗口是否打开 + + // 切换模块 + const [tabKey, setTabKey] = useState(deviceGroupEnums[0].key); + const [tabs] = useState([...deviceGroupEnums]); + const changeTabMode = (key: string) => { + setTabKey(key); + console.log(key); + // eslint-disable-next-line @typescript-eslint/no-use-before-define + // initList(key); + }; + /**节点列表 */ + // 设备节点树 + async function loadDeviceTree() { + const resp = await getDeviceGroupList({ page: 1, pageSize: 100 }); + console.log(resp.data, 'loadDeviceTree'); + setDeviceTreeList(resp?.data.results); + setNodeInfo(resp?.data.results[0]); + } + + // 新增 + const handleCreateModal = () => { + setCreateModalOpen(!createModalOpen); + }; + + // 节点信息展示 + + // 切换 + + // 初始化加载 + useEffect(() => { + loadDeviceTree(); + }, []); + + return ( +
+ {/* 节点列表 */} +
+ 节点列表}> +
+ { + setNodeInfo(record); + }} + addTreeNode={(node) => { + //TODO 判断是根节点还是子节点 调用新增接口 + console.log('addTreeNode_node', node); + handleCreateModal(); + }} + selectTree={(selectedKeys, info) => { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + info?.node && setNodeInfo(info?.node); + // handleSelectNode(selectedKeys, info) + console.log('selectTree_selected', selectedKeys, info); + }} + > +
+
+
+ + {/* 节点信息 */} +
+ 节点信息} + extra={ + + } + > +
+ + { + changeTabMode(key); + }} + > + {tabKey === '1' && } +
+
+
+ {/* 弹窗 */} + { + // TODO 调用获取节点列表的接口 + }} + /> +
+ ); +}; + +export default DeviceGroup; diff --git a/src/pages/Business/NodeSetting/index.tsx b/src/pages/Business/NodeSetting/index.tsx deleted file mode 100644 index fc2478b..0000000 --- a/src/pages/Business/NodeSetting/index.tsx +++ /dev/null @@ -1,14 +0,0 @@ -/* - * @Author: donghao donghao@supervision.ltd - * @Date: 2024-04-22 15:23:36 - * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-22 15:34:36 - * @FilePath: \general-ai-platform-web\src\pages\Node\NodeSetting\index.tsx - * @Description: 节点设置 - * @交互说明 - */ -const NodeSetting: React.FC = () => { - return
节点设置
; -}; - -export default NodeSetting; diff --git a/src/pages/Model/ModelDetail/index.tsx b/src/pages/Model/ModelDetail/index.tsx index 092863d..1fe0c13 100644 --- a/src/pages/Model/ModelDetail/index.tsx +++ b/src/pages/Model/ModelDetail/index.tsx @@ -45,11 +45,7 @@ const ModelDetail: React.FC = () => { /**新增 编辑 删除 */ // 新增 const handleCreateModal = () => { - if (createModalOpen) { - setCreateModalOpen(false); - } else { - setCreateModalOpen(true); - } + setCreateModalOpen(!createModalOpen); }; function reloadList() { diff --git a/src/pages/Project/BusinessInfo/components/baseInfo.tsx b/src/pages/Project/BusinessInfo/components/baseInfo.tsx index 9f6a041..a0895e5 100644 --- a/src/pages/Project/BusinessInfo/components/baseInfo.tsx +++ b/src/pages/Project/BusinessInfo/components/baseInfo.tsx @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-23 17:00:00 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-24 17:14:48 + * @LastEditTime: 2024-04-28 09:33:34 * @FilePath: \general-ai-platform-web\src\pages\Project\BusinessInfo\components\baseInfo.tsx * @Description: 基本信息展示 * @@ -45,7 +45,7 @@ const BaseInfo: React.FC = ({ info }) => { }, ]; return ( -
+
); diff --git a/src/services/testApi/device.ts b/src/services/testApi/device.ts new file mode 100644 index 0000000..4140541 --- /dev/null +++ b/src/services/testApi/device.ts @@ -0,0 +1,31 @@ +/* + * @Author: donghao donghao@supervision.ltd + * @Date: 2024-04-25 15:39:42 + * @LastEditors: donghao donghao@supervision.ltd + * @LastEditTime: 2024-04-28 17:14:06 + * @FilePath: \general-ai-platform-web\src\services\testApi\device.ts + * @Description: 设备api + */ +// @ts-ignore +/* eslint-disable */ +import { request } from '@umijs/max'; + +/** 节点下设备分页列表 */ +export async function getDeviceListByGroup( + body: Record, // + options?: { [key: string]: any }, +) { + return request( + `/api/device/listByGroup`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + params: { + ...body, + }, + ...(options || {}), + }, + ); +} diff --git a/src/services/testApi/deviceGroup.ts b/src/services/testApi/deviceGroup.ts index b8491b6..60ff8d2 100644 --- a/src/services/testApi/deviceGroup.ts +++ b/src/services/testApi/deviceGroup.ts @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-25 15:39:42 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-25 15:49:38 + * @LastEditTime: 2024-04-28 11:19:40 * @FilePath: \general-ai-platform-web\src\services\testApi\deviceGroup.ts * @Description: 节点设置api */ @@ -11,26 +11,26 @@ import { request } from '@umijs/max'; /** 节点设置分页列表 */ -// export async function getDeviceGroupList( -// body: Record, // -// options?: { [key: string]: any }, -// ) { -// return request( -// `/api/device_group/list`, -// { -// method: 'GET', -// headers: { -// 'Content-Type': 'application/json', -// }, -// params: { -// ...body, -// }, -// ...(options || {}), -// }, -// ); -// } +export async function getDeviceGroupList( + body: Record, // + options?: { [key: string]: any }, +) { + return request( + `/api/device_group/getDeviceGroupList`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + params: { + ...body, + }, + ...(options || {}), + }, + ); +} -/** 获取设备组树 POST /device_group/getDeviceGroupTree */ +/** 获取设备组树 GET /device_group/getDeviceGroupTree */ export async function getDeviceGroupTree( body: Record, // options?: { [key: string]: any }, @@ -49,3 +49,23 @@ export async function getDeviceGroupTree( }, ); } + +/** 获取节点树 GET /device_group/getDeviceGroupTree */ +export async function getDeviceGroupSettingTree( + body: Record, // + options?: { [key: string]: any }, +) { + return request( + `/api/device_group/setting_data`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + params: { + ...body, + }, + ...(options || {}), + }, + ); +} diff --git a/src/services/testApi/dict.ts b/src/services/testApi/dict.ts index c91511f..5dbaada 100644 --- a/src/services/testApi/dict.ts +++ b/src/services/testApi/dict.ts @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-04-09 13:46:44 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-04-17 14:09:35 + * @LastEditTime: 2024-04-28 14:24:40 * @FilePath: \general-ai-manage\src\services\testApi\businessProject.ts * @Description: 字典表mock数据映射 */ @@ -10,12 +10,28 @@ /* eslint-disable */ import { request } from '@umijs/max'; -/** 企业项目分页列表 */ +/** 行业分类列表 */ export async function getDictIndustry( body: Record, // options?: { [key: string]: any }, ) { - return request(`/api/dict/industry/`, { + return request(`/api/dict/industry`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + params: { + ...body, + }, + ...(options || {}), + }); +} +/** 设备类型列表 */ +export async function getDictDeviceType( + body: Record, // + options?: { [key: string]: any }, +) { + return request(`/api/dict/deviceType`, { method: 'GET', headers: { 'Content-Type': 'application/json', diff --git a/src/utils/baseTree.ts b/src/utils/baseTree.ts new file mode 100644 index 0000000..58c43ff --- /dev/null +++ b/src/utils/baseTree.ts @@ -0,0 +1,13 @@ +export const formatTreeValByKey = ( + key: string, + node: Record, + fieldNames?: string, +): any => { + if (fieldNames && Object.keys(fieldNames).includes(key)) { + return node[fieldNames[key]]; + } + if (Object.keys(node).includes(key)) { + return node[key]; + } + return null; +};