feat: 设备和服务器静态交互完成

develop2
donghao 12 months ago
parent d8590ee313
commit bd9a81e0a6

@ -2,7 +2,7 @@
* @Author: zhoux zhouxia@supervision.ltd
* @Date: 2023-11-13 14:19:57
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-25 16:25:44
* @LastEditTime: 2024-05-09 11:33:23
* @FilePath: \general-ai-platform-web\config\defaultForm.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE2
*/
@ -41,7 +41,7 @@ export const proFormItemStyleProps: Record<string, any> = {
column2Width: (proFormModelWidth - formBoxMargin - formItemGap) / 2, // 两列
};
// max 968
// max 920
export const proFormMaxModelWidth: number = 920;
export const proFormMaxItemStyleProps: Record<string, any> = {
width: proFormMaxModelWidth - formBoxMargin,

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-27 14:56:27
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-26 09:33:39
* @LastEditTime: 2024-05-10 13:41:47
* @FilePath: \general-ai-manage\config\routes.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
@ -90,7 +90,7 @@ export const outerMenuRoute = {
};
/**
* @
* @
*/
export const innerMenuRoutes = [
{
@ -99,8 +99,7 @@ export const innerMenuRoutes = [
component: './Project/BusinessInfo',
access: 'canReadMenu',
key: '1001',
// icon: 'TestIcon',
menuIcon: 'TestIcon',
menuIcon: 'icon-qiyexinxi',
},
{
name: 'business-device-group',
@ -108,7 +107,7 @@ export const innerMenuRoutes = [
component: './Business/DeviceGroup',
access: 'canReadMenu',
key: '1002',
menuIcon: '',
menuIcon: 'icon-jiedianshezhi',
},
{
name: 'business-model-index',
@ -116,7 +115,23 @@ export const innerMenuRoutes = [
component: './Business/BusinessModel',
access: 'canReadMenu',
key: '1003',
menuIcon: '',
menuIcon: 'icon-yewumoxing',
},
{
name: 'business-server-state',
path: '/business/serverState',
component: './Business/BusinessState',
access: 'canReadMenu',
key: '1004',
menuIcon: 'icon-fuwuqizhuangtai',
},
{
name: 'business-device-state',
path: '/business/deviceState',
component: './Business/BusinessState/deviceSate',
access: 'canReadMenu',
key: '1005',
menuIcon: 'icon-shebeizhuangtai',
},
];

@ -0,0 +1,152 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-08 14:21:42
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:17:08
* @FilePath: \general-ai-platform-web\mock\businessState.ts
* @Description:
*/
import {
deviceListData,
deviceStateLogListData,
serverListData,
serverStateLogListData,
} from './pools/businessStateData';
import { successMockApiProps } from './typing';
import { fetchCurrPageByList } from './utils/apiMock';
export default {
// 服务器列表
'GET /api/business/serverState/list': async (req: Request, res: Response) => {
// get 使用 query 读取参数
const { page, pageSize, status } = req.query;
let finalData = serverListData;
let { onlineCount, outlineCount } = serverListData.data;
if (status && ['1', '2'].includes(status)) {
onlineCount = 0;
outlineCount = 0;
let newArr = [];
serverListData.data.results.forEach((item) => {
if (status === item.state) {
newArr.push(item);
}
if (item.state === '1') {
onlineCount++;
} else {
outlineCount++;
}
});
finalData = {
...serverListData,
data: {
...serverListData.data,
onlineCount,
outlineCount,
results: newArr,
},
};
}
const resData: successMockApiProps = {
...fetchCurrPageByList({
...finalData,
data: { ...finalData.data, page, pageSize: pageSize || 10 },
}),
};
res.json(resData);
},
// 服务器日志分页列表
'GET /api/business/serverState/logList': async (req: Request, res: Response) => {
// get 使用 query 读取参数
const { page, pageSize } = req.query;
const resData: successMockApiProps = {
...fetchCurrPageByList({
...serverStateLogListData,
data: { ...serverStateLogListData.data, page, pageSize: pageSize || 10 },
}),
};
res.json(resData);
},
// 设备列表
'GET /api/business/deviceState/list': async (req: Request, res: Response) => {
// get 使用 query 读取参数
const { page, pageSize, status } = req.query;
let finalData = deviceListData;
let { onlineCount, outlineCount, processCount, errorCount } = deviceListData.data;
if (status && ['1', '2', '3', '4'].includes(status)) {
onlineCount = 0;
outlineCount = 0;
processCount = 0;
errorCount = 0;
let newArr = [];
deviceListData.data.results.forEach((item) => {
if (status === item.state) {
newArr.push(item);
}
switch (item.state) {
case '1':
onlineCount++;
break;
case '2':
outlineCount++;
break;
case '3':
processCount++;
break;
default:
errorCount++;
break;
}
});
finalData = {
...deviceListData,
data: {
...deviceListData.data,
onlineCount,
outlineCount,
processCount,
errorCount,
results: newArr,
},
};
}
const resData: successMockApiProps = {
...fetchCurrPageByList({
...finalData,
data: { ...finalData.data, page, pageSize: pageSize || 10 },
}),
};
res.json(resData);
},
// 服务器日志分页列表
'GET /api/business/deviceState/logList': async (req: Request, res: Response) => {
// get 使用 query 读取参数
const { page, pageSize } = req.query;
const resData: successMockApiProps = {
...fetchCurrPageByList({
...deviceStateLogListData,
data: { ...deviceStateLogListData.data, page, pageSize: pageSize || 10 },
}),
};
res.json(resData);
},
// 未启用
// 企业详情
// 'GET /api/business/serverState/detail': async (req: Request, res: Response) => {
// // get 使用 query 读取参数
// const { id } = req.query;
// let finalData = {};
// serverListData.data.results.forEach((item) => {
// if (Number(item.id) === Number(id)) {
// finalData = item;
// // break;
// }
// });
// const resData: successMockApiProps = fetchMockSuccessFullByOther({
// data: finalData,
// });
// res.json(resData);
// },
};

@ -2,14 +2,14 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-25 15:45:17
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-28 17:15:19
* @LastEditTime: 2024-05-10 17:13:12
* @FilePath: \general-ai-platform-web\mock\device.ts
* @Description: mock
*/
import { mockGetDeviceListByGroup } from './pools/deviceData';
import { mockGetAllDeviceList, mockGetDeviceListByGroup } from './pools/deviceData';
import { successMockApiProps } from './typing';
import { fetchCurrPageByList } from './utils/apiMock';
import { fetchCurrPageByList, fetchMockSuccessFullByOther } from './utils/apiMock';
export default {
// 设备列表
@ -24,10 +24,10 @@ export default {
res.json(resData);
},
// // 设备分类
// 'GET /api/dict/deviceType': async (req: Request, res: Response) => {
// const resData: successMockApiProps = {
// ...fetchMockSuccessFullByOther(mockGetDeviceTypeDictData),
// };
// res.json(resData);
// },
'GET /api/device/allDevice': async (req: Request, res: Response) => {
const resData: successMockApiProps = {
...fetchMockSuccessFullByOther(mockGetAllDeviceList),
};
res.json(resData);
},
};

@ -2,14 +2,27 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-24 17:51:07
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 16:59:44
* @LastEditTime: 2024-05-10 16:45:05
* @FilePath: \general-ai-platform-web\mock\pools\businessModelData.ts
* @Description: mock
*/
import { generateRandomString } from '../utils/mockHash';
import { generateRandomDateTimeByYear } from '../utils/mockMoment';
// 模型列表
const generatrModels = () => {
const currList: Record<string, any>[] = [];
const count = 1 + Math.floor(Math.random() * 8);
for (let i = 0; i < count; i++) {
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
name: '基础模型' + (i + 1), // 设备名称
});
}
return currList;
};
// 业务模型列表
const startBusinessModelList = () => {
const currList: Record<string, any>[] = [];
const nameArr = ['陌生人群检测', '在岗打瞌睡检测', '上班离岗检测'];
@ -24,14 +37,15 @@ const startBusinessModelList = () => {
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
isEnable: Math.floor(Math.random() * 8) % 2 === 0,
bussnessName: '目标检测',
industry: '通用',
name: nameArr[i],
deviceSort: '文字识别',
remark:
'光学字符识别OCR是可进行字体训练的工具用于自动识别字符。它可以防止误读、处理流程变化并提供轻松的字体管理。',
remark: '精确定位装配部件的中心位置并检测可能的缺陷,确保装配精度。',
defaultVersionFkId: 'V1.6.25',
type: '经典算法',
provider: '苏胜天',
linkModels: generatrModels(),
});
}
return {
@ -40,14 +54,6 @@ const startBusinessModelList = () => {
};
};
export const mockGetBusinessModelListData = {
data: {
next: null,
previous: null,
...JSON.parse(JSON.stringify(startBusinessModelList())),
},
};
// 基础模型列表
const startBaseBusinessModelList = () => {
const currList: Record<string, any>[] = [];
@ -77,6 +83,15 @@ const startBaseBusinessModelList = () => {
};
};
// 业务模型
export const mockGetBusinessModelListData = {
data: {
next: null,
previous: null,
...JSON.parse(JSON.stringify(startBusinessModelList())),
},
};
// 基础模型
export const mockGetBaseBusinessModelListData = {
data: {
next: null,

@ -0,0 +1,240 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-01 16:34:06
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:23:17
* @FilePath: \General-AI-Platform-Web\mock\pools\serverData.ts
* @Description: mock
*/
import { generateRandomString } from '../utils/mockHash';
import { generateRandomDateTimeByYear } from '../utils/mockMoment';
const generateRandomTwoDecimal = () => {
// 生成一个在 [0, 1) 范围内的随机数
const randomFraction = Math.random();
// 乘以一个倍数,例如 100以增加小数位数
const multipliedValue = randomFraction * 100;
// 使用 Math.round() 进行四舍五入,并将结果除以倍数,得到两位小数
return Math.round(multipliedValue) / 100;
};
const progressData = () => {
const finalArr = [
{
label: 'CPU',
percent: generateRandomTwoDecimal(),
strokeColor: 'rgb(243,48,5)',
usedColors: ['#FFAB00', '#FF4409'],
freeColors: ['#477BFF', '#0048FE'],
},
{
label: '内存',
percent: (15 + Math.floor(Math.random() * 85)) / 100,
strokeColor: 'rgb(33,169,122)',
usedColors: ['#47A3FF', '#0D6EFF'],
freeColors: ['#00C45A ', '#4AE003'],
},
{
label: '存储',
percent: (15 + Math.floor(Math.random() * 85)) / 100,
strokeColor: 'rgb(33,169,122)',
usedColors: ['#FF8110', '#EB0404'],
freeColors: ['#4200FF', '#9520F0'],
},
{
label: 'GPU',
percent: (85 + Math.floor(Math.random() * 15)) / 100,
strokeColor: 'rgb(250,173,20)',
usedColors: ['#AE47FF', '#F008AF'],
freeColors: ['#FF4D00', '#F2B721'],
},
];
return finalArr;
};
// 服务器状态列表生成数据
const fetchServerList = () => {
const currList: Record<string, any>[] = [];
const count = 30;
const baseVersion = 'V' + Math.floor(Math.random() * 10);
const currFileTime = new Date().getTime();
const randomString = generateRandomString(20);
const ip1 = Math.floor(Math.random() * 255);
const ip2 = Math.floor(Math.random() * 255);
let onlineCount = 0;
let outlineCount = 0;
for (let i = 0; i < count; i++) {
const currState = Math.floor(Math.random() * 8) % 2 === 0 ? '1' : '2';
if (currState === '1') {
onlineCount++;
} else {
outlineCount++;
}
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
isEnable: Math.floor(Math.random() * 8) % 2 === 0,
deviceSort: '服务器' + (i + 1),
index: i,
provider: '苏胜天',
type: 4,
banner: 'https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg',
state: currState,
IP: `192.168.${ip1}.${ip2}`,
port: 80,
userName: 'admin',
pwd: '123456',
description:
'SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部',
progressData: progressData(),
});
}
return {
count,
results: currList,
onlineCount,
outlineCount,
};
};
// 设备状态列表生成数据
const fetchDeviceList = () => {
const currList: Record<string, any>[] = [];
const count = 120;
const baseVersion = 'V' + Math.floor(Math.random() * 10);
const currFileTime = new Date().getTime();
const randomString = generateRandomString(20);
const ip1 = Math.floor(Math.random() * 255);
const ip2 = Math.floor(Math.random() * 255);
let onlineCount = 0;
let outlineCount = 0;
let processCount = 0;
let errorCount = 0;
for (let i = 0; i < count; i++) {
const currState = 1 + (Math.floor(Math.random() * 30) % 4) + '';
switch (currState) {
case '1':
onlineCount++;
break;
case '2':
outlineCount++;
break;
case '3':
processCount++;
break;
default:
errorCount++;
break;
}
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
isEnable: Math.floor(Math.random() * 8) % 2 === 0,
name: '设备' + (i + 1),
groupName: '设备组0' + ((Math.floor(Math.random() * 8) % 3) + 1),
deviceType: '设备分类' + ((Math.floor(Math.random() * 8) % 4) + 1),
index: i,
provider: '苏胜天',
type: 4,
banner: 'https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg',
state: currState,
IP: `192.168.${ip1}.${ip2}`,
port: 80,
remark: '暂无',
description:
'SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部',
progressData: progressData(),
});
}
return {
count,
results: currList,
onlineCount,
outlineCount,
processCount,
errorCount,
};
};
// 服务器日志列表数据生成
const fetchServerStateLogList = () => {
const count = 1 + Math.floor(Math.random() * 80);
let currList = [];
for (let i = 0; i < count; i++) {
const ip1 = Math.floor(Math.random() * 255);
const ip2 = Math.floor(Math.random() * 255);
const port = 80;
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
IP: `192.168.${ip1}.${ip2}`,
port,
deviceSort: '服务器',
provider: '苏胜天',
});
}
return {
count: currList.length,
results: currList,
};
};
// 设备日志列表数据生成
const fetchDeviceStateLogList = () => {
const count = 1 + Math.floor(Math.random() * 80);
let currList = [];
for (let i = 0; i < count; i++) {
const ip1 = Math.floor(Math.random() * 255);
const ip2 = Math.floor(Math.random() * 255);
const port = 80;
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
IP: `192.168.${ip1}.${ip2}`,
port,
deviceSort: '设备',
provider: '苏胜天',
runTime: `${Math.floor(Math.random() * 100)}${Math.floor(Math.random() * 24)}小时`,
});
}
return {
count: currList.length,
results: currList,
};
};
/**服务器 */
export const serverListData = {
data: {
...fetchServerList(),
},
};
export const serverParamsListData = {
data: {
results: progressData(),
},
};
export const serverStateLogListData = {
data: {
...fetchServerStateLogList(),
},
};
/**设备 */
export const deviceListData = {
data: {
...fetchDeviceList(),
},
};
export const deviceStateLogListData = {
data: {
...fetchDeviceStateLogList(),
},
};

@ -1,5 +1,70 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-26 16:18:26
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 17:13:03
* @FilePath: \general-ai-platform-web\mock\pools\deviceData.ts
* @Description: mock
*/
// 节点下设备列表数据
// 节点设备列表
import { generateRandomDateTimeByYear } from '../utils/mockMoment';
const fetchAllDeviceListByGroup = () => {
const nameArr = [
'海康威视球形摄像头',
'海康威视摄像头',
'大华摄像头',
'宝盈监控摄像头',
'安迅达监控摄像头',
'华为监控摄像头',
'海思监控摄像头',
'中维监控摄像头',
'罗普斯金监控摄像头',
'美电贝斯监控摄像头',
'索尼监控摄像头',
'松下监控摄像头',
'三星监控摄像头',
'小米监控摄像头',
'TP-Link监控摄像头',
'Vivotek监控摄像头',
'网视通监控摄像头',
'微拓监控摄像头',
'云从监控摄像头',
'摩托罗拉监控摄像头',
'新大陆监控摄像头',
];
const count = 1 + Math.floor(Math.random() * (nameArr.length - 1));
let currList = [];
for (let i = 0; i < count; i++) {
const ip1 = Math.floor(Math.random() * 255);
const ip2 = Math.floor(Math.random() * 255);
const port = 80;
currList.push({
id: i + '1',
createTime: generateRandomDateTimeByYear(2022),
updateTime: generateRandomDateTimeByYear(2023),
name: nameArr[i], // 设备名称
deviceType: '摄像头', // 设备类型
isEnable: true, // 是否部署
deviceSite: '东区左侧', // 设备位置
deviceModel: 'video_2024', // 设备型号
deviceParams: '627663_aduh237298', // 设备参数
remark: '精确定位装配部件的中心位置并检测可能的缺陷,确保装配精度。', // 备注
});
}
return {
count: currList.length,
results: currList,
};
};
export const mockGetAllDeviceList = {
data: {
...fetchAllDeviceListByGroup(),
},
};
export const mockGetDeviceListByGroup = {
data: {
count: 2,
@ -7,6 +72,7 @@ export const mockGetDeviceListByGroup = {
{
id: '10001',
name: '海康威视环球摄像头', // 设备名称
bussnessName: '装配目标检测',
deviceType: '摄像头', // 设备类型
isEnable: true, // 是否部署
createTime: '2023-12-17T13:37:31.758471+08:00',
@ -14,11 +80,12 @@ export const mockGetDeviceListByGroup = {
deviceSite: '东区左侧', // 设备位置
deviceModel: 'haikang_video_2024', // 设备型号
deviceParams: '627663_aduh237298', // 设备参数
remark: '', // 备注
remark: '精确定位装配部件的中心位置并检测可能的缺陷,确保装配精度。', // 备注
},
{
id: '10002',
name: '海康威视环球摄像头',
bussnessName: '控制目标检测',
deviceType: '控制器',
isEnable: false,
createTime: '2023-12-17T13:37:31.758471+08:00',
@ -26,7 +93,7 @@ export const mockGetDeviceListByGroup = {
deviceSite: '南区前侧',
deviceModel: 'haikang_video_2024',
deviceParams: '627663_aduh237298',
remark: '',
remark: '精确定位装配部件的中心位置并检测可能的缺陷,确保装配精度。',
},
],
page: 1,

@ -53,8 +53,11 @@
"antd": "^5.13.2",
"antd-style": "^3.6.1",
"classnames": "^2.5.1",
"echarts": "^5.5.0",
"echarts-for-react": "^3.0.2",
"js-yaml": "^4.1.0",
"less": "^4.2.0",
"lottie-web": "^5.12.2",
"omit.js": "^2.0.2",
"querystring": "^0.2.1",
"rc-menu": "^9.12.4",
@ -62,7 +65,8 @@
"react": "^18.2.0",
"react-cookies": "^0.1.1",
"react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0"
"react-helmet-async": "^1.3.0",
"react-lottie-web": "^1.3.2"
},
"devDependencies": {
"@ant-design/pro-cli": "^3.3.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -17,6 +17,7 @@ import { RequestConfig } from 'umi';
import defaultSettings from '../config/defaultSettings';
import './app.less';
import './base.less';
import './iconfont.less';
import { errorConfig } from './requestErrorConfig';
const isDev = true;
@ -153,7 +154,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
</div>
<div className="page_body">
<div className="flex items-center justify-between body_nav_bar">
<span className="head4">
<span className="head2">
{currMenu?.name &&
intl.formatMessage({ id: `menu.${currMenu?.name}`, defaultMessage: '首页' })}
</span>

@ -1,20 +1,92 @@
/* 基准量 */
/* 颜色 */
.color_0 {
.text_color_0 {
color: #000000;
}
.color_1 {
.text_color_1 {
color: #333333;
}
.color_2 {
.text_color_2 {
color: #666666;
}
.color_3 {
.text_color_3 {
color: #999999;
}
.text_primary {
color: #154ddd;
}
.text_active_1 {
color: #52c41a;
}
.text_active_2 {
color: #f15d53;
}
.text_active_3 {
color: #ff8413;
}
.text_active_3 {
color: #ebf3ff;
}
.bg_active_1 {
background: #52c41a;
}
.bg_active_2 {
background: #f15d53;
}
.bg_active_3 {
background: #ff8413;
}
.bg_active_4 {
background: #ebf3ff;
}
.bg_gray_color_1 {
background: #cccccc;
}
/* 边框 */
.primary_border {
border: 1px solid #154ddd;
}
/* 标题 */
.head1 {
color: #333333;
font-weight: bold;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-align: left;
text-transform: none;
font-size: 20px;
line-height: 28px;
}
.head2 {
color: #333333;
font-weight: bold;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-align: left;
text-transform: none;
font-size: 18px;
line-height: 25px;
}
.head3 {
color: #333333;
font-weight: bold;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-align: left;
text-transform: none;
font-size: 16px;
line-height: 22px;
}
.head4 {
color: #333333;
font-weight: bold;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-align: left;
text-transform: none;
font-size: 14px;
line-height: 18px;
}
.h1 {
color: #000000;
font-weight: bold;
@ -25,25 +97,33 @@
text-align: left;
text-transform: none;
}
.head4 {
.text1 {
color: #333333;
font-weight: bold;
font-size: 18px;
font-family: PingFang SC, PingFang SC;
font-style: normal;
line-height: 22px;
text-align: left;
text-transform: none;
font-size: 14px;
line-height: 20px;
}
.head5 {
.text2 {
color: #333333;
font-weight: bold;
font-size: 16px;
font-family: PingFang SC, PingFang SC;
font-style: normal;
line-height: 19px;
text-align: left;
text-transform: none;
font-size: 14px;
font-family: PingFang SC-Medium;
line-height: 20px;
}
.text3 {
color: #333333;
font-family: PingFang SC, PingFang SC;
font-style: normal;
text-align: left;
text-transform: none;
font-size: 12px;
line-height: 17px;
}
/* 段落 */
.p1 {
@ -56,6 +136,7 @@
text-align: left;
text-transform: none;
}
/* 自定义组件 */
.gn_list_card_title {
display: flex;
align-items: center;
@ -73,3 +154,56 @@
font-family: PingFang SC, PingFang SC;
line-height: 22px;
}
.gn_list_type_tag {
width: 82px;
height: 24px;
color: #52c41a;
background: #e8f7e6;
border: 1px solid #baeea1;
border-radius: 12px;
}
.gn_list_type_tag .dot {
width: 6px;
height: 6px;
margin-right: 4px;
background: #52c41a;
border-radius: 50%;
}
.gn_list_type_tag.active2 {
color: #f15d53;
background: #feefee;
border: 1px solid #f9b2ae;
}
.gn_list_type_tag.active2 .dot {
background: #f15d53;
}
.gn_list_type_tag.active3 {
color: #ff8413;
background: #fff3e8;
border: 1px solid #ffbf84;
}
.gn_list_type_tag.active3 .dot {
background: #ff8413;
}
.gn_list_type_tag.active_primary {
color: #154ddd;
background: rgba(21, 77, 221, 0.1);
border: 1px solid rgba(21, 77, 221, 0.4);
}
.gn_list_type_tag.active_primary .dot {
background: #154ddd;
}
.gn_card_tag {
padding: 2px 4px;
font-size: 12px;
border-radius: 2px;
}
/* 进度条 */
.rectProgress_box .ant-progress .ant-progress-inner {
border-radius: 2px;
}
.rectProgress_box .ant-progress .ant-progress-success-bg,
.rectProgress_box .ant-progress .ant-progress-bg {
border-radius: 2px;
}
/* 灰屏效果 */

@ -1,55 +1,144 @@
/* 基准量 */
@primary_color: #154ddd; // 主题色
@active_color_1: #52c41a; // 辅助色1
@active_color_2: #f15d53; // 辅助色2
@active_color_3: #ff8413; // 辅助色3
@active_color_4: #ebf3ff; // 辅助色4
@text_color_1: #333333; // 文本色1
@text_color_2: #666666; // 文本色2
@text_color_3: #999999; // 文本色3
@gray_color_1: #cccccc; // 用于占位性提示性内容
@gray_color_2: #dcdcdc; // 用于描边色值
@gray_color_3: #e0e0e0; // 用于分割线色值
@primary_bg_color: #f5f5f5; // 主题背景色
/* 颜色 */
.color_0 {
.text_color_0 {
color: #000000;
}
.color_1 {
color: #333333;
.text_color_1 {
color: @text_color_1;
}
.color_2 {
color: #666666;
.text_color_2 {
color: @text_color_2;
}
.color_3 {
color: #999999;
.text_color_3 {
color: @text_color_3;
}
.text_primary {
color: @primary_color;
}
.text_active_1 {
color: @active_color_1;
}
.text_active_2 {
color: @active_color_2;
}
.text_active_3 {
color: @active_color_3;
}
.text_active_3 {
color: @active_color_4;
}
// 背景
.bg_active_1 {
background: #ebf3ff;
background: @active_color_1;
}
.bg_active_2 {
background: @active_color_2;
}
.bg_active_3 {
background: @active_color_3;
}
.bg_active_4 {
background: @active_color_4;
}
.bg_gray_color_1 {
background: @gray_color_1;
}
/* 边框 */
.primary_border {
border: 1px solid @primary_color;
}
/* 标题 */
.h1 {
color: #000000;
// 定义一个标题共性集合
.head-mixin() {
color: #333333;
font-weight: bold;
font-size: 20px;
font-family: PingFang SC, PingFang SC;
font-style: normal;
line-height: 23px;
text-align: left;
text-transform: none;
}
.head1 {
.head-mixin();
font-size: 20px;
line-height: 28px;
}
.head2 {
.head-mixin();
font-size: 18px;
line-height: 25px;
}
.head3 {
.head-mixin();
font-size: 16px;
line-height: 22px;
}
.head4 {
color: #333333;
.head-mixin();
font-size: 14px;
line-height: 18px;
}
// .head3 {
// .head-mixin();
// font-size: 16px;
// line-height: 19px;
// }
.h1 {
color: #000000;
font-weight: bold;
font-size: 18px;
font-size: 20px;
font-family: PingFang SC, PingFang SC;
font-style: normal;
line-height: 22px;
line-height: 23px;
text-align: left;
text-transform: none;
}
.head5 {
// 定义一个正文共性集合
.text-mixin() {
color: #333333;
font-weight: bold;
font-size: 16px;
font-family: PingFang SC, PingFang SC;
font-style: normal;
line-height: 19px;
text-align: left;
text-transform: none;
}
.text1 {
.text-mixin();
font-size: 14px;
line-height: 20px;
}
.text2 {
.text-mixin();
font-size: 14px;
font-family: PingFang SC-Medium;
line-height: 20px;
}
.text3 {
.text-mixin();
font-size: 12px;
line-height: 17px;
}
/* 段落 */
.p1 {
@ -63,6 +152,8 @@
text-transform: none;
}
/* 自定义组件 */
// 列表下卡片标题
.gn_list_card_title {
display: flex;
align-items: center;
@ -70,7 +161,7 @@
width: 2px;
height: 16px;
margin-right: 8px;
background: #154ddd;
background: @primary_color;
}
span:nth-child(2) {
color: #333333;
@ -80,3 +171,76 @@
line-height: 22px;
}
}
// 列表下卡片标签
.gn_list_type_tag {
width: 82px;
height: 24px;
color: @active_color_1;
background: #e8f7e6;
border: 1px solid #baeea1;
border-radius: 12px;
.dot {
width: 6px;
height: 6px;
margin-right: 4px;
background: @active_color_1;
border-radius: 50%;
}
&.active2 {
color: @active_color_2;
background: #feefee;
border: 1px solid #f9b2ae;
.dot {
background: @active_color_2;
}
}
&.active3 {
color: @active_color_3;
background: #fff3e8;
border: 1px solid #ffbf84;
.dot {
background: @active_color_3;
}
}
&.active_primary {
color: @primary_color;
background: rgba(21, 77, 221, 0.1);
border: 1px solid rgba(21, 77, 221, 0.4);
.dot {
background: @primary_color;
}
}
}
// 卡片下标签
.gn_card_tag {
padding: 2px 4px;
font-size: 12px;
border-radius: 2px;
}
/* 进度条 */
.rectProgress_box {
.ant-progress .ant-progress-inner {
border-radius: 2px;
}
.ant-progress .ant-progress-success-bg,
.ant-progress .ant-progress-bg {
border-radius: 2px;
}
}
/* 灰屏效果 */
.gray_info_all() {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
-webkit-filter: gray;
-webkit-filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
filter: grayscale(100%);
filter: gray;
filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
}

@ -0,0 +1,5 @@
// import animateServer from './src/animateServer';
import animatePic from './src/animatePic';
// export const AnimateServer = animateServer;
export const AnimatePic = animatePic;

@ -0,0 +1,35 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-08 17:33:43
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-08 17:45:06
* @FilePath: \general-ai-platform-web\src\components\Animate\src\animatePic.tsx
* @Description:
*/
import lottie from 'lottie-web'; //引入动效库
import React from 'react';
import { useEffect, useRef } from 'react';
import { LottieProps } from '../typing';
const AnimatePic: React.FC<LottieProps> = (props) => {
const animationPic = useRef(null);
function initAnimate() {
console.log(lottie, 'lottie', props);
lottie.loadAnimation({
container: animationPic.current, //选择渲染dom
renderer: 'svg', //渲染格式
loop: true, //循环播放
autoplay: true, //是否i自动播放,
animationData: props.value, //渲染动效json
});
}
useEffect(() => {
initAnimate();
}, []);
return <div ref={animationPic} />;
};
export default AnimatePic;

@ -0,0 +1,40 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-08 17:33:43
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-08 17:47:09
* @FilePath: \general-ai-platform-web\src\components\Animate\src\animateServer.tsx
* @Description:
*/
import lottie from 'lottie-web'; //引入动效库
import React from 'react';
// import json01 from '../../../../public/animate/device/01.json'; //引入下载的动效json
import { useEffect, useRef } from 'react';
import { LottieProps } from '../typing';
const AnimateServer: React.FC<LottieProps> = (props) => {
const animation1 = useRef(null);
function initAnimate() {
console.log(lottie, 'lottie', props);
lottie.loadAnimation({
container: animation1.current, //选择渲染dom
renderer: 'svg', //渲染格式
loop: true, //循环播放
autoplay: true, //是否i自动播放,
// animationData: json01, //渲染动效json
});
}
useEffect(() => {
initAnimate();
}, []);
return (
<div style={{ width: 100 }}>
<div ref={animation1} />
</div>
);
};
export default AnimateServer;

@ -0,0 +1,3 @@
export interface LottieProps {
value: any;
}

@ -1,3 +1,5 @@
import commButton from './src/commButton';
import textButton from './src/textButton';
export const CommButton = commButton;
export const TextButton = textButton;

@ -0,0 +1,3 @@
.text_btn_box {
// font-size: 12px;
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-16 10:54:35
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-16 13:57:44
* @LastEditTime: 2024-05-09 13:52:49
* @FilePath: \general-ai-manage\src\components\Button\src\commButton.tsx
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/

@ -0,0 +1,25 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-08 09:42:31
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-09 14:18:48
* @FilePath: \general-ai-platform-web\src\components\Button\src\textButton.tsx
* @Description:
*/
import React from 'react';
import { TextButtonProps } from '../typing';
import './button.less';
const TextButton: React.FC<TextButtonProps> = (props) => {
const { buttonLabel } = props;
return (
<span
className={`text_btn_box ${props?.buttonType === 'danger' ? 'text_active_2' : ''} ${
props?.buttonType === 'primary' ? 'text_primary' : ''
}`}
>
{buttonLabel}
</span>
);
};
export default TextButton;

@ -1,4 +1,17 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-19 17:10:21
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-09 14:07:59
* @FilePath: \general-ai-platform-web\src\components\Button\typing.ts
* @Description:
*/
export interface CommButtonProps extends ButtonProps {
prevIcon?: React.ReactNode;
buttonLabel: string | React.ReactNode;
}
export interface TextButtonProps extends ButtonProps {
buttonLabel: string | React.ReactNode;
buttonType: 'danger' | 'primary' | 'default' | undefined;
}

@ -1,4 +1,4 @@
.menubar_wrap {
@i .menubar_wrap {
position: fixed;
top: 0;
left: 0;
@ -9,44 +9,44 @@
padding: 0;
background-color: #fff;
border-radius: 0px 0px 32px 0px;
}
.menubar_wrap .ant-menu,
.menubar_wrap .ant-menu > .ant-menu,
.menubar_wrap .ant-menu.ant-menu-inline .ant-menu-sub.ant-menu-inline,
.menubar_wrap .ant-menu > .ant-menu.ant-menu-inline .ant-menu-sub.ant-menu-inline {
.ant-menu,
.ant-menu > .ant-menu,
.ant-menu.ant-menu-inline .ant-menu-sub.ant-menu-inline,
.ant-menu > .ant-menu.ant-menu-inline .ant-menu-sub.ant-menu-inline {
font-size: 14px;
background-color: #fff;
}
.menubar_wrap .ant-menu .ant-menu-item-selected,
.menubar_wrap .ant-menu > .ant-menu .ant-menu-item-selected {
}
.ant-menu .ant-menu-item-selected,
.ant-menu > .ant-menu .ant-menu-item-selected {
color: #fff;
background: #154ddd;
border-radius: 0px 8px 8px 0px;
}
.menubar_wrap .menu_top {
}
.menu_top {
width: 100%;
height: 72px;
color: #154ddd;
font-weight: bold;
border-radius: 0px 0px 64px 0px;
box-shadow: 0px 1px 0px 0px rgba(21, 77, 221, 0.15);
}
.menubar_wrap .ant-menu,
.menubar_wrap .ant-menu-item {
}
.ant-menu,
.ant-menu-item {
width: 100%;
margin: 0;
padding: 0;
}
.menubar_wrap .ant-menu-item-icon {
}
.ant-menu-item-icon {
width: 20px;
height: 20px;
font-size: 14px;
}
.menubar_wrap .menu_center {
}
.menu_center {
display: flex;
flex: 1;
width: 100%;
}
.menubar_wrap .menu_bottom {
}
.menu_bottom {
width: 96px;
}
}

@ -1,5 +1,6 @@
@menubar_ThemeColor: #fff;
@themeColor: #154ddd;
// @themeColor: #154ddd;
@import url('@/base.less');
.menubar_wrap {
position: fixed;
top: 0;
@ -14,6 +15,25 @@
border-radius: 0px 0px 32px 0px;
// border-radius: 12px;
// box-shadow: 4px 0px 24px 0px rgba(0, 63, 143, 0.3);
// 自定义实现
.single_menu_box {
& > li {
height: 40px;
border-radius: 0px 8px 8px 0px;
cursor: pointer;
&.active {
color: @menubar_ThemeColor;
background: @primary_color;
}
&:hover {
color: @primary_color;
background: #154ddd1a;
}
}
}
// 基于ant实现
.ant-menu,
.ant-menu > .ant-menu,
.ant-menu.ant-menu-inline .ant-menu-sub.ant-menu-inline,
@ -24,13 +44,13 @@
.ant-menu .ant-menu-item-selected,
.ant-menu > .ant-menu .ant-menu-item-selected {
color: @menubar_ThemeColor;
background: @themeColor;
background: @primary_color;
border-radius: 0px 8px 8px 0px;
}
.menu_top {
width: 100%;
height: 72px;
color: @themeColor;
color: @primary_color;
font-weight: bold;
border-radius: 0px 0px 64px 0px;
box-shadow: 0px 1px 0px 0px rgba(21, 77, 221, 0.15);

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-27 16:03:20
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-28 09:44:23
* @LastEditTime: 2024-05-10 17:46:32
* @FilePath: \general-ai-manage\src\components\Header\index.tsx
* @Description: layout
*/
@ -12,8 +12,6 @@ import { ReactComponent as BusinessLogoIcon } from '/public/home/business_logo.s
import type { MenuProps } from 'antd';
import { Menu } from 'antd';
import React, { useEffect, useState } from 'react';
import { ReactComponent as BusinessBigLogo } from '/public/home/business_big_logo.svg';
// import menuFooter from '/public/menuFooter.svg';
@ -31,7 +29,7 @@ const MenuBar: React.FC<MenuBarProps> = ({ menuData, changeMenu }) => {
const [selectedMenu, setSelectedMenu] = useState([]);
const [stateOpenKeys, setStateOpenKeys] = useState(['1', '2']);
// const [stateOpenKeys, setStateOpenKeys] = useState(['1', '2']);
// 根据路径查找对应的菜单项
const findMenuByPath = (menuData: any, pathname: any) => {
@ -58,39 +56,39 @@ const MenuBar: React.FC<MenuBarProps> = ({ menuData, changeMenu }) => {
}
};
const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => {
console.log(openKeys, 'openKeys');
const currentOpenKey = openKeys.find((key) => stateOpenKeys.indexOf(key) === -1);
console.log(currentOpenKey, 'currentOpenKey');
// open
if (currentOpenKey !== undefined) {
const repeatIndex = openKeys
.filter((key) => key !== currentOpenKey)
.findIndex((key) => levelKeys[key] === levelKeys[currentOpenKey]);
setStateOpenKeys(
openKeys
// remove repeat key
.filter((_, index) => index !== repeatIndex)
// remove current level all child
.filter((key) => levelKeys[key] <= levelKeys[currentOpenKey]),
);
localStorage.setItem(
'openKeys',
JSON.stringify(
openKeys
// remove repeat key
.filter((_, index) => index !== repeatIndex)
// remove current level all child
.filter((key) => levelKeys[key] <= levelKeys[currentOpenKey]),
),
);
} else {
// close
setStateOpenKeys(openKeys);
localStorage.setItem('openKeys', JSON.stringify(openKeys));
}
};
// const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => {
// console.log(openKeys, 'openKeys');
// const currentOpenKey = openKeys.find((key) => stateOpenKeys.indexOf(key) === -1);
// console.log(currentOpenKey, 'currentOpenKey');
// // open
// if (currentOpenKey !== undefined) {
// const repeatIndex = openKeys
// .filter((key) => key !== currentOpenKey)
// .findIndex((key) => levelKeys[key] === levelKeys[currentOpenKey]);
// setStateOpenKeys(
// openKeys
// // remove repeat key
// .filter((_, index) => index !== repeatIndex)
// // remove current level all child
// .filter((key) => levelKeys[key] <= levelKeys[currentOpenKey]),
// );
// localStorage.setItem(
// 'openKeys',
// JSON.stringify(
// openKeys
// // remove repeat key
// .filter((_, index) => index !== repeatIndex)
// // remove current level all child
// .filter((key) => levelKeys[key] <= levelKeys[currentOpenKey]),
// ),
// );
// } else {
// // close
// setStateOpenKeys(openKeys);
// localStorage.setItem('openKeys', JSON.stringify(openKeys));
// }
// };
// 当路由变化时更新当前选中菜单项
useEffect(() => {
@ -121,19 +119,42 @@ const MenuBar: React.FC<MenuBarProps> = ({ menuData, changeMenu }) => {
</div>
{/* // TODO 菜单需要补充路由聚焦状态 */}
<div className="menu_center">
<Menu
<div className="w-full menu_center">
<ul className="w-full single_menu_box">
{menuData &&
menuData?.map((menuItem) => (
<li
className={`text1 flex items-center w-full ${
selectedMenu.includes(menuItem.key) ? 'active' : ''
}`}
key={menuItem.key}
icon={menuItem.icon}
onClick={() => menuClick(menuItem)}
>
<i className={`pl-[24px] pr-[12px] iconfont ${menuItem.menuIcon}`}></i>
<div>
{intl.formatMessage({ id: `menu.${menuItem.name}`, defaultMessage: '菜单' })}
</div>
</li>
))}
</ul>
{/* <Menu
mode="inline"
selectedKeys={selectedMenu}
openKeys={stateOpenKeys}
onOpenChange={onOpenChange}
>
{menuData.map((menuItem) => (
<Menu.Item key={menuItem.key} icon={menuItem.icon} onClick={() => menuClick(menuItem)}>
{menuData &&
menuData?.map((menuItem) => (
<Menu.Item
key={menuItem.key}
icon={menuItem.icon}
onClick={() => menuClick(menuItem)}
>
{intl.formatMessage({ id: `menu.${menuItem.name}`, defaultMessage: '菜单' })}
</Menu.Item>
))}
</Menu>
</Menu> */}
</div>
</div>
);

@ -2,7 +2,7 @@
* @Author: zhoux zhouxia@supervision.ltd
* @Date: 2023-11-16 14:30:15
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-19 09:46:23
* @LastEditTime: 2024-05-10 14:38:08
* @FilePath: \general-ai-platform-web\src\components\BatchOperation\isBatchDelete.tsx
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
@ -19,6 +19,7 @@ type isConfirmActionProps = {
buttonFormatText?: string;
buttonType?: 'link' | 'text' | 'default' | 'primary' | 'dashed' | undefined;
danger?: boolean;
buttonRender?: string | React.ReactNode;
handleContainerClick?: () => void;
};
@ -41,6 +42,10 @@ const IsConfirmAction: React.FC<isConfirmActionProps> = (props) => {
okText={intl.formatMessage({ id: 'common.yes', defaultMessage: '$$$' })}
cancelText={intl.formatMessage({ id: 'common.no', defaultMessage: '$$$' })}
>
{props?.buttonRender}
{props.buttonRender ? (
<></>
) : (
<Button
type={props?.buttonType ? props.buttonType : 'link'}
danger={props?.danger}
@ -56,6 +61,7 @@ const IsConfirmAction: React.FC<isConfirmActionProps> = (props) => {
<FormattedMessage id={props.buttonFormatText} defaultMessage="$$$" />
)}
</Button>
)}
</Popconfirm>
</div>
);

@ -2,7 +2,7 @@
* @Author: zhoux zhouxia@supervision.ltd
* @Date: 2023-11-16 14:30:15
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-19 09:43:26
* @LastEditTime: 2024-05-09 14:13:40
* @FilePath: \general-ai-platform-web\src\components\BatchOperation\isBatchDelete.tsx
* @Description:
*/
@ -15,6 +15,7 @@ import { proIconForTableActionStyle } from '../../../config/defaultIcon';
type IsDeleteProps = {
// eslint-disable-next-line @typescript-eslint/ban-types
buttonType?: 'defalut' | 'deleteIcon';
buttonRender?: string | React.ReactNode;
deleteApi: () => void;
deleteNextText?: string | React.ReactNode;
handleContainerClick?: () => void;
@ -42,7 +43,10 @@ const IsDelete: React.FC<IsDeleteProps> = (props) => {
props.deleteApi();
}}
>
{props.buttonType === 'deleteIcon' ? (
{props?.buttonRender}
{props.buttonRender ? (
<></>
) : props.buttonType === 'deleteIcon' ? (
<span
style={{
color: 'rgba(232, 13, 13, 1)',

@ -45,3 +45,6 @@
.base_tree_wrap .tree_node_item:hover .action_list .anticon-delete {
color: #e80d0d;
}
.base_tree_wrap .tree_search_form .ant-form-item {
margin: 0;
}

@ -50,4 +50,10 @@
}
}
}
.tree_search_form {
.ant-form-item {
margin: 0;
}
}
}

@ -5,7 +5,7 @@ import _debounce from 'lodash/debounce';
import React, { useEffect, useState } from 'react';
import { BaseTreeProps } from '../typing';
import { ProFormText } from '@ant-design/pro-components';
import { ProForm, ProFormText } from '@ant-design/pro-components';
import './baseTree.less';
const { TreeNode } = Tree;
@ -141,12 +141,12 @@ const BaseTree: React.FC<BaseTreeProps> = (props) => {
// 定义每个节点内容 递归操作
const renderTreeNodes = (data) => {
if (Array.isArray(data) && data.length) {
return data.map((node) => {
return data.map((node, index) => {
return (
<TreeNode
{...node}
title={formatTreeValByNodeKey('title', node)}
key={formatTreeValByNodeKey('key', node)}
key={formatTreeValByNodeKey('key', node) + index}
className={`tree_node_item tree_node_${node.level}`}
>
{formatTreeValByNodeKey('children', node) &&
@ -188,8 +188,9 @@ const BaseTree: React.FC<BaseTreeProps> = (props) => {
return (
<div className="base_tree_wrap">
{!props?.hideInSearch ? (
<ProForm className="tree_search_form" submitter={false}>
<ProFormText
className="tree_search_item"
className=" mb-[0px]"
onChange={(e) => handleSearch(e.target.value)}
key="name"
name="name"
@ -201,6 +202,7 @@ const BaseTree: React.FC<BaseTreeProps> = (props) => {
prefix: <SearchOutlined style={{ color: 'rgba(0,0,0,.25)' }} />,
}}
/>
</ProForm>
) : (
<></>
)}
@ -226,7 +228,7 @@ const BaseTree: React.FC<BaseTreeProps> = (props) => {
{/* TODO 使用ProForm */}
<Modal
title={editNodeKey ? '编辑节点' : '新增节点'}
visible={visible}
open={visible}
onOk={handleModalOk}
onCancel={handleModalCancel}
>

@ -0,0 +1,62 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-28 15:30:31
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:03:03
* @FilePath: \general-ai-platform-web\src\enums\device.ts
* @Description:
*/
// 节点设置模块
export const deviceGroupEnums: Record<string, any>[] = [
{
label: '设备列表',
key: '1',
},
{
label: '业务模型部署',
key: '2',
},
{
label: '告警设置',
key: '3',
},
];
// 设备状态
export const deviceStateEnums: DICTENUM.DICT_TAB_ITEM[] = [
{
label: '全部状态',
key: '0',
},
{
label: '在线',
key: '1',
className: 'online_info',
},
{
label: '离线',
key: '2',
className: 'outline_info',
},
{
label: '运行中',
key: '3',
className: 'process_info',
},
{
label: '故障',
key: '4',
className: 'error_info',
},
];
// 服务器状态详情
export const bsDeviceDetailEnums: DICTENUM.DICT_TAB_ITEM[] = [
{
label: '设备信息',
key: '0',
},
{
label: '设备日志',
key: '1',
},
];

@ -1,23 +0,0 @@
/*
* @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<string, any>[] = [
{
label: '设备列表',
key: '1',
},
{
label: '业务模型部署',
key: '2',
},
{
label: '告警设置',
key: '3',
},
];

@ -0,0 +1,36 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-28 15:30:31
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-09 14:35:52
* @FilePath: \general-ai-platform-web\src\enums\server.ts
* @Description:
*/
// 服务器状态
export const serverStateEnums: DICTENUM.DICT_TAB_ITEM[] = [
{
label: '全部状态',
key: '0',
},
{
label: '在线',
key: '1',
className: 'online_info',
},
{
label: '离线',
key: '2',
className: 'outline_info',
},
];
// 服务器状态详情
export const bsServerDetailEnums: DICTENUM.DICT_TAB_ITEM[] = [
{
label: '服务器信息',
key: '0',
},
{
label: '服务器日志',
key: '1',
},
];

@ -188,7 +188,7 @@ ol {
background-size: cover;
}
/* Descriptions */
.gn_table_descriptions {
.gn_active_descriptions {
padding: 16px 16px 0;
background: #ffffff;
border: 1px solid rgba(21, 77, 221, 0.1);

@ -234,7 +234,7 @@ ol {
/* Descriptions */
// 描述展示
.gn_table_descriptions {
.gn_active_descriptions {
padding: 16px 16px 0;
background: #ffffff;
border: 1px solid rgba(21, 77, 221, 0.1);

@ -0,0 +1,102 @@
@font-face {
font-family: "iconfont";
/* Project id 4530966 */
src: url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.woff2?t=1715311346156') format('woff2'), url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.woff?t=1715311346156') format('woff'), url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.ttf?t=1715311346156') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fuzhi:before {
content: "\e719";
}
.icon-zip:before {
content: "\e71a";
}
.icon-shangchuanwenjian:before {
content: "\e718";
}
.icon-you:before {
content: "\e717";
}
.icon-delete:before {
content: "\e716";
}
.icon-tianjiafenlei:before {
content: "\e714";
}
.icon-shanchufenlei:before {
content: "\e715";
}
.icon-tianjiajiedian:before {
content: "\e713";
}
.icon-banbenxinxi:before {
content: "\e711";
}
.icon-shiyonghangye:before {
content: "\e712";
}
.icon-jiedianshezhi:before {
content: "\e70f";
}
.icon-fuwuqizhuangtai:before {
content: "\e710";
}
.icon-yewumoxing:before {
content: "\e70b";
}
.icon-shouye:before {
content: "\e70c";
}
.icon-shebeizhuangtai:before {
content: "\e70d";
}
.icon-qiyexinxi:before {
content: "\e70e";
}
.icon-moxingliebiao-unselected:before {
content: "\e709";
}
.icon-moxingyunhangku-selected:before {
content: "\e70a";
}
.icon-wen:before {
content: "\e704";
}
.icon-xia:before {
content: "\e705";
}
.icon-moxingliebiao-selected:before {
content: "\e706";
}
.icon-moxingyunhangku-unselected:before {
content: "\e707";
}
.icon-close:before {
content: "\e708";
}
.icon-moxingshuliang:before {
content: "\e6fd";
}
.icon-shebeishuliang:before {
content: "\e6fe";
}
.icon-xinjian:before {
content: "\e6ff";
}
.icon-gengduo:before {
content: "\e700";
}
.icon-chuangjianshijian:before {
content: "\e701";
}
.icon-search:before {
content: "\e702";
}
.icon-refresh:before {
content: "\e703";
}

@ -0,0 +1,134 @@
@font-face {
font-family: 'iconfont'; /* Project id 4530966 */
src: url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.woff2?t=1715311346156') format('woff2'),
url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.woff?t=1715311346156') format('woff'),
url('//at.alicdn.com/t/c/font_4530966_1jxithnpibx.ttf?t=1715311346156') format('truetype');
}
.iconfont {
font-size: 16px;
font-family: 'iconfont' !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-fuzhi:before {
content: '\e719';
}
.icon-zip:before {
content: '\e71a';
}
.icon-shangchuanwenjian:before {
content: '\e718';
}
.icon-you:before {
content: '\e717';
}
.icon-delete:before {
content: '\e716';
}
.icon-tianjiafenlei:before {
content: '\e714';
}
.icon-shanchufenlei:before {
content: '\e715';
}
.icon-tianjiajiedian:before {
content: '\e713';
}
.icon-banbenxinxi:before {
content: '\e711';
}
.icon-shiyonghangye:before {
content: '\e712';
}
.icon-jiedianshezhi:before {
content: '\e70f';
}
.icon-fuwuqizhuangtai:before {
content: '\e710';
}
.icon-yewumoxing:before {
content: '\e70b';
}
.icon-shouye:before {
content: '\e70c';
}
.icon-shebeizhuangtai:before {
content: '\e70d';
}
.icon-qiyexinxi:before {
content: '\e70e';
}
.icon-moxingliebiao-unselected:before {
content: '\e709';
}
.icon-moxingyunhangku-selected:before {
content: '\e70a';
}
.icon-wen:before {
content: '\e704';
}
.icon-xia:before {
content: '\e705';
}
.icon-moxingliebiao-selected:before {
content: '\e706';
}
.icon-moxingyunhangku-unselected:before {
content: '\e707';
}
.icon-close:before {
content: '\e708';
}
.icon-moxingshuliang:before {
content: '\e6fd';
}
.icon-shebeishuliang:before {
content: '\e6fe';
}
.icon-xinjian:before {
content: '\e6ff';
}
.icon-gengduo:before {
content: '\e700';
}
.icon-chuangjianshijian:before {
content: '\e701';
}
.icon-search:before {
content: '\e702';
}
.icon-refresh:before {
content: '\e703';
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-01 11:20:09
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-10 17:23:04
* @LastEditTime: 2024-05-09 15:22:39
* @FilePath: \uighur-recognition-web2\src\locales\zh-CN.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
@ -16,6 +16,7 @@ import menu from './zh-CN/menu';
import * as model from './zh-CN/model';
import pages from './zh-CN/pages';
import pwa from './zh-CN/pwa';
import * as server from './zh-CN/server';
import settingDrawer from './zh-CN/settingDrawer';
import settings from './zh-CN/settings';
import * as systems from './zh-CN/system';
@ -40,6 +41,7 @@ export default {
{},
...Object.values(businessProject),
...Object.values(model),
...Object.values(server),
// 待启用
...Object.values(systems),

@ -2,7 +2,7 @@
* @Author: zhoux zhouxia@supervision.ltd
* @Date: 2023-11-01 13:56:33
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-30 14:50:56
* @LastEditTime: 2024-05-10 15:34:33
* @FilePath: \general-ai-platform-web\src\locales\zh-CN\device.ts
* @Description:
*/
@ -60,7 +60,6 @@ export const device_group_list: { [key: string]: string } = {
'device_group_list.table.list.action.deviceType': '设备分类',
'device_group_list.table.list.add': '新建设备',
'device_group_list.table.list.action.setDeviceType': '新建设备分类',
// 未启用
'device_group_list.table.list.code': '设备代码',
'device_group_list.table.list.position': '位置',
@ -74,64 +73,22 @@ export const device_group_list: { [key: string]: string } = {
'device_group_list.table.rule.required.code': '设备代码为必填项',
'device_group_list.table.list.update': '更新设备',
};
export const device_category: { [key: string]: string } = {
'device.device_category.table.list.id': 'ID',
'device.device_category.table.list.name': '类别名称',
'device.device_category.table.list.code': '类别代码',
'device.device_category.table.list.remark': '备注',
'device.device_category.table.list.createTime': '创建时间',
'device.device_category.table.list.updateTime': '更新时间',
'device.device_category.table.rule.required.name': '类别名称为必填项',
'device.device_category.table.rule.required.code': '类别代码为必填项',
'device.device_category.table.list.add': '新建设备类别',
'device.device_category.table.list.update': '更新设备类别',
};
export const device_relation: { [key: string]: string } = {
'device.device_relation.table.list.id': 'ID',
'device.device_relation.table.list.deviceParentFkId': '设备父节点',
'device.device_relation.table.list.deviceSonFkId': '设备父节点',
'device.device_relation.table.list.createTime': '创建时间',
'device.device_relation.table.list.updateTime': '更新时间',
'device.device_relation.table.rule.required.deviceParentFkId': '设备父节点为必填项',
'device.device_relation.table.rule.required.deviceSonFkId': '设备父节点为必填项',
};
// 接口管理
export const interface_manage: { [key: string]: string } = {
'device.interface_manage.table.list.id': 'ID',
'device.interface_manage.table.list.name': '接口名称',
'device.interface_manage.table.list.address': '接口地址',
'device.interface_manage.table.list.ip': 'IP地址',
'device.interface_manage.table.list.createTime': '创建时间',
'device.interface_manage.table.list.testTime': '状态查询时间',
'device.interface_manage.table.list.remark': '备注',
'device.interface_manage.table.list.add': '新建设备/输入源',
'device.interface_manage.table.list.addPic': '新建图像获取接口',
'device.interface_manage.table.list.updatePic': '编辑图像获取接口',
'device.interface_manage.table.list.capture': '最近拍摄',
'device.interface_manage.table.list.port': '端口',
'device.interface_manage.table.list.loginName': '登录名',
'device.interface_manage.table.list.pwd': '密码',
'device.interface_manage.table.list.fileDirectory': '文件目录',
'device.interface_manage.table.list.requestAddress': '请求地址',
'device.interface_manage.table.list.requestKey': '请求Key',
'device.interface_manage.table.list.secretKey': '秘钥',
'device.interface_manage.table.list.bucket': 'Bucket',
'device.interface_manage.table.list.Code': 'Code',
'device.interface_manage.table.list.addVideoSource': '新建视频源',
'device.interface_manage.table.list.updatVideoSource': '编辑视频源',
'device.interface_manage.table.list.videoName': '视频源名称',
'device.interface_manage.table.list.obtainMode': '获取方式',
'device.interface_manage.table.list.obtainStatus': '获取状态',
'device.interface_manage.table.rule.required.name': '接口名称为必填项',
'device.interface_manage.table.rule.required.address': '接口地址为必填项',
'device.interface_manage.table.rule.required.ip': 'IP地址为必填项',
'device.interface_manage.table.rule.required.loginName': '登录名为必填项',
'device.interface_manage.table.rule.required.pwd': '密码为必填项',
'device.interface_manage.table.rule.required.fileDirectory': '文件目录为必填项',
'device.interface_manage.table.rule.required.requestAddress': '请求地址为必填项',
'device.interface_manage.table.rule.required.requestKey': '请求Key为必填项',
'device.interface_manage.table.rule.required.secretKey': '请求Key为必填项',
'device.interface_manage.table.rule.required.bucket': 'Bucket为必填项',
'device.interface_manage.table.rule.required.Code': 'Code为必填项',
// 设备状态
export const device_state: { [key: string]: string } = {
'device_state.table.form.groupName': '设备组',
'device_state.table.form.deviceType': '设备分类',
'device_state.table.form.name': '设备名称',
'device_state.table.form.remark': '备注',
// 日志
'device_state.table.stateLog.list.ip': '设备IP',
'device_state.table.stateLog.list.runTime': '默认端口',
'device_state.table.stateLog.list.updateTime': '更新时间',
'device_state.table.detail.echarts.used': '已占用',
'device_state.table.detail.echarts.free': '未占用',
'device_state.table.detail.echarts.kindName': '名称',
'device_state.table.detail.title.params': '基础信息',
'device_state.table.detail.title.info': '硬件信息',
'device_state.table.detail.title.task': '当前任务',
};

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-01 11:20:09
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-26 09:36:38
* @LastEditTime: 2024-05-07 14:54:37
* @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
*/
@ -57,24 +57,13 @@ export default {
'menu.editor.flow': '流程编辑器',
'menu.editor.mind': '脑图编辑器',
'menu.editor.koni': '拓扑编辑器',
'menu.realTime': '实时分析',
'menu.home-business-project': '企业项目',
'menu.model-index': '模型管理',
'menu.model-runtime-lib': '模型运行库',
'menu.business-info-index': '企业信息',
'menu.business-device-group': '节点设置',
'menu.business-model-index': '业务模型',
// 待废弃
'menu.realTime': '实时分析',
'menu.realTime.realTime-involved-list': '告警汇总',
'menu.realTime.realTime-alarm-list': '告警列表',
'menu.realTime.realTime-alarm-rules': '告警规则',
'menu.realTime.realTime-device-list': '设备管理',
'menu.offline': '离线分析',
'menu.offline.offline-involved-list-upload': '告警汇总',
'menu.offline.offline-alarm-list': '告警列表',
'menu.offline.offline-alarm-rules': '告警规则',
'menu.offline.offline-device-list': '设备管理',
'menu.business-server-state': '服务器状态',
'menu.business-device-state': '设备状态',
};

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-10 17:21:34
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 16:58:50
* @LastEditTime: 2024-05-10 17:18:57
* @FilePath: \general-ai-manage\src\locales\zh-CN\model.ts
* @Description:
*/
@ -93,9 +93,18 @@ export const business_model: { [key: string]: string } = {
'business_model.stepForm.config.description': '配置业务参数',
'business_model.form.modelFkId': '业务模型名称',
'business_model.form.remark': '简介',
'business_model.table.list.isEnable': '模型部署',
'business_model.table.list.isEnable': '部署状态',
'business_model.table.list.deployed.isEnable': '已部署',
'business_model.table.list.undeployed.isEnable': '未部署',
'business_model.table.list.action.config': '配置参数',
// 部署模型
'business_model.deploy.config.bussnessName': '业务名称',
'business_model.deploy.config.remark': '简介',
'business_model.deploy.config.linkModels': '关联基础模型',
'business_model.deploy.config.table.name': '设备名称',
'business_model.deploy.config.table.deviceType': '设备类型',
'business_model.deploy.config.table.title.name': '选择需要模型的设备',
};
export const base_model: { [key: string]: string } = {
@ -110,10 +119,8 @@ export const base_model: { [key: string]: string } = {
'base_model.stepForm.add.title': '基础模型配置',
'base_model.stepForm.runtimeLib': '运行库选择',
'base_model.stepForm.runtimeLib.description': '选择运行库文件',
'base_model.stepForm.modelConfig': '模型参数配置',
'base_model.stepForm.modelConfig.description': '配置模型参数',
'base_model.stepForm.group': '关联节点',
'base_model.stepForm.group.description': '关联相关设备节点',
'base_model.form.modelFkId': '模型',
@ -121,19 +128,26 @@ export const base_model: { [key: string]: string } = {
'base_model.form.required.name': '请填写版本号',
'base_model.form.remark': '备注',
'base_model.list.table.form.rule.required.name': '请填写版本号',
// 待启用
'base_model.stepForm.base': '基本信息',
'base_model.stepForm.base.description': '填写基础信息',
'base_model.stepForm.baseModel': '关联模型',
'base_model.stepForm.baseModel.description': '关联基础模型',
'base_model.stepForm.project_file': '业务代码',
'base_model.stepForm.project_file.description': '上传业务代码',
'base_model.stepForm.config': '参数配置',
'base_model.stepForm.config.description': '配置业务参数',
'base_model.form.modelFkId': '业务模型名称',
'base_model.form.remark': '简介',
'base_model.form.name': '版本号',
'base_model.form.required.name': '请填写版本号',
};
export const server_state: { [key: string]: string } = {
'server_state.table.list.name': '服务器名称',
'server_state.table.list.userName': '用户名',
'server_state.table.list.ip': 'IP',
'server_state.table.list.pwd': '密码',
'server_state.table.list.defaultPort': '默认端口',
'server_state.table.list.parameter': '服务器参数',
'server_state.table.list.publicKeyString': '公钥字符串',
'server_state.table.list.connectivityTesting': '连通性测试',
'server_state.table.list.isEnable': '是否启用',
'server_state.table.list.remark': '备注',
'server_state.table.list.createTime': '创建时间',
'server_state.table.list.updateTime': '更新时间',
'server_state.table.rule.required.modelFkId': '模型为必填项',
'server_state.table.rule.required.path': '模型地址为必填项',
'server_state.table.list.add': '新建服务器',
'server_state.table.list.editor': '编辑服务器',
'server_state.table.list.update': '更新模型版本',
};
// 未启用
@ -181,23 +195,3 @@ export const model_image: { [key: string]: string } = {
'resource.model_image.table.list.add': '新建模型镜像',
'resource.model_image.table.list.update': '更新模型镜像',
};
export const server_status: { [key: string]: string } = {
'resource.server_status.table.list.name': '服务器名称',
'resource.server_status.table.list.userName': '用户名',
'resource.server_status.table.list.ip': 'IP',
'resource.server_status.table.list.pwd': '密码',
'resource.server_status.table.list.defaultPort': '默认端口',
'resource.server_status.table.list.parameter': '服务器参数',
'resource.server_status.table.list.publicKeyString': '公钥字符串',
'resource.server_status.table.list.connectivityTesting': '连通性测试',
'resource.server_status.table.list.isEnable': '是否启用',
'resource.server_status.table.list.remark': '备注',
'resource.server_status.table.list.createTime': '创建时间',
'resource.server_status.table.list.updateTime': '更新时间',
'resource.server_status.table.rule.required.modelFkId': '模型为必填项',
'resource.server_status.table.rule.required.path': '模型地址为必填项',
'resource.server_status.table.list.add': '新建服务器',
'resource.server_status.table.list.editor': '编辑服务器',
'resource.server_status.table.list.update': '更新模型版本',
};

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-07 13:42:27
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-18 10:59:08
* @LastEditTime: 2024-05-10 16:06:57
* @FilePath: \general-ai-manage\src\locales\zh-CN\pages.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
@ -80,6 +80,10 @@ export default {
'pages.searchTable.batchApproval': '批量审批',
'pages.searchTable.stop': '停止',
'pages.searchTable.edit': '编辑',
'pages.searchTable.search': '查询',
'pages.searchTable.reset': '重置',
'pages.searchTable.updateDetail': '查看',
'pages.searchTable.setDefault': '设为默认',
'pages.modelForm.okText': '确认',
'pages.modelForm.cancelText': '取消',
};

@ -0,0 +1,30 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-09 15:21:03
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 14:51:36
* @FilePath: \general-ai-platform-web\src\locales\zh-CN\server.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
// 服务器状态
export const server_state: { [key: string]: string } = {
'server_state.create.form.add': '新建服务器',
'server_state.table.list.add': '新建服务器',
'server_state.table.form.name': '服务器名称',
'server_state.table.form.rule.required.name': '请填写服务器名称',
'server_state.table.form.ip': 'IP',
'server_state.table.form.userName': '用户名',
'server_state.table.form.pwd': '密码',
'server_state.table.form.defaultPort': '默认端口',
'server_state.table.stateLog.list.ip': 'IP',
'server_state.table.stateLog.list.defaultPort': '默认端口',
'server_state.table.stateLog.list.createTime': '创建时间',
'server_state.table.detail.echarts.used': '已占用',
'server_state.table.detail.echarts.free': '未占用',
'server_state.table.detail.echarts.kindName': '名称',
'server_state.table.detail.title.params': '服务器参数',
'server_state.table.detail.title.info': '硬件信息',
'server_state.table.detail.title.task': '当前任务',
};

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-22 15:23:36
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-25 16:11:40
* @LastEditTime: 2024-05-07 13:26:50
* @FilePath: \general-ai-platform-web\src\pages\Node\BusinessModel\index.tsx
* @Description:
* @
@ -25,7 +25,7 @@ import { ProCard, ProTable } from '@ant-design/pro-components';
import { FormattedMessage } from '@umijs/max';
import { Button } from 'antd';
import { useRef, useState } from 'react';
import { proTableCommonOptions, proTablePaginationOptions } from '../../../../config/defaultTable';
import { proTablePaginationOptions } from '../../../../config/defaultTable';
import CreateForm from './components/createForm';
const BusinessModel: React.FC = () => {
@ -67,6 +67,7 @@ const BusinessModel: React.FC = () => {
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
width: '40%',
},
{
@ -124,11 +125,11 @@ const BusinessModel: React.FC = () => {
},
];
return (
<div className="modelIndex_page gn_head_card">
<div className="businessModel_page gn_head_card">
<ProCard
className="gn_card pb-[16px]"
title={
<span className="head5">
<span className="head3">
<FormattedMessage id="business_model.table.title" defaultMessage="标题" />
</span>
}
@ -159,10 +160,9 @@ const BusinessModel: React.FC = () => {
}}
// 标题栏
search={false}
scroll={{ y: proTableCommonOptions.commscrollY }}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
actionRef={actionRef}
rowKey="key"
rowKey="id"
onDataSourceChange={(data) => {
console.log(data, 'onDataSourceChange_data');
// let CategoryFkIdIds: any = data.map((v) => {
@ -188,9 +188,7 @@ const BusinessModel: React.FC = () => {
let resp = await getBusinessModelList({ ...reqParams });
console.log(resp, 'getModelVersionList_resp');
return {
data: resp.data?.results.map((v: Record<string, any>) => {
return { ...v, key: v.id };
}),
data: resp.data?.results,
success: resp.success,
total: resp.data.count,
current: current,

@ -0,0 +1,123 @@
import { ModalForm, ProForm, ProFormText } 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';
export type CreateDeviceFormProps = {
createModalOpen: boolean;
handleModal: () => void;
reload: any;
};
const CreateServerForm: React.FC<CreateDeviceFormProps> = (props) => {
const intl = useIntl();
const [form] = Form.useForm<API.ModelCategory>();
return (
<ModalForm<API.ModelCategory>
className="gn_modal_form gn_form"
width={proFormSmallModelWidth}
title={intl.formatMessage({
id: 'server_state.create.form.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 对接新增接口
props.handleModal();
return true;
}}
>
<ProForm.Group>
<ProFormText
width={proFormSmallItemStyleProps.column2Width}
name="name"
label={<FormattedMessage id="server_state.table.form.name" defaultMessage="名称" />}
placeholder={`${intl.formatMessage({
id: 'common.please_input',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'server_state.table.form.name',
defaultMessage: '$$$',
})}`}
required={true}
rules={[
{
required: true,
message: (
<FormattedMessage
id="server_state.table.form.rule.required.name"
defaultMessage="名称必填"
/>
),
},
]}
/>
<ProFormText
width={proFormSmallItemStyleProps.column2Width}
name="ip"
label={<FormattedMessage id="server_state.table.form.ip" defaultMessage="IP" />}
placeholder={`${intl.formatMessage({
id: 'common.please_input',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'server_state.table.form.ip',
defaultMessage: '$$$',
})}`}
/>
<ProFormText
width={proFormSmallItemStyleProps.column2Width}
name="userName"
label={<FormattedMessage id="server_state.table.form.userName" defaultMessage="用户名" />}
placeholder={`${intl.formatMessage({
id: 'common.please_input',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'server_state.table.form.userName',
defaultMessage: '$$$',
})}`}
/>
<ProFormText.Password
width={proFormSmallItemStyleProps.column2Width}
label={<FormattedMessage id="server_state.table.form.pwd" defaultMessage="密码" />}
name="pwd"
placeholder={`${intl.formatMessage({
id: 'common.please_input',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'server_state.table.form.pwd',
defaultMessage: '$$$',
})}`}
/>
<ProFormText
width={proFormSmallItemStyleProps.width}
name="defaultPort"
label={
<FormattedMessage id="server_state.table.form.defaultPort" defaultMessage="默认端口" />
}
placeholder={`${intl.formatMessage({
id: 'common.please_input',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'server_state.table.form.defaultPort',
defaultMessage: '$$$',
})}`}
/>
</ProForm.Group>
</ModalForm>
);
};
export default CreateServerForm;

@ -0,0 +1,358 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:12:44
* @FilePath: \general-ai-manage\src\pages\Project\BusinessProject\components\detailDeviceState.tsx
* @Description:
* @
*
*/
import { bsDeviceDetailEnums } from '@/enums/device';
import { getModelGroupBaseModelList } from '@/services/testApi/model';
import { isSuccessApi } from '@/utils/forApi';
import { ProCard, ProDescriptions, ProList, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Modal, Tabs } from 'antd';
import * as echarts from 'echarts';
import ReactEcharts from 'echarts-for-react';
import { useEffect, useState } from 'react';
import { proFormMaxModelWidth } from '../../../../../config/defaultForm';
import DetailDeviceStateLog from './detailDeviceStateLog';
type DetailDeviceStateProps = {
info: Record<string, any>;
detailOpen: boolean;
closeModal: () => void;
};
const DetailDeviceState: React.FC<DetailDeviceStateProps> = ({ info, detailOpen, closeModal }) => {
/**state */
const intl = useIntl();
const [tabKey, setTabKey] = useState<string>(bsDeviceDetailEnums[0].key);
const [tabs] = useState<DICTENUM.DICT_TAB_ITEM[]>([...bsDeviceDetailEnums]);
const [modelData, setModelData] = useState<Record<string, any>[]>([]); // 列表数据
const [forceRender, setForceRender] = useState<boolean>(false);
// 基础模型信息
const ModelDetailColumns = [
{
title: <FormattedMessage id="device_state.table.form.groupName" defaultMessage="设备组" />,
dataIndex: 'groupName',
},
{
title: <FormattedMessage id="device_state.table.form.deviceType" defaultMessage="设备分类" />,
dataIndex: 'deviceType',
},
{
title: <FormattedMessage id="device_state.table.form.name" defaultMessage="设备名称" />,
dataIndex: 'name',
},
{
title: <FormattedMessage id="device_state.table.form.remark" defaultMessage="备注" />,
dataIndex: 'remark',
},
];
// 硬件信息环形图
const fetchOptionByData = (record) => {
const totalCount = 100 * Math.floor(Math.random() * 15);
const currData = [
{
value: record?.percent * totalCount,
name: `${intl.formatMessage({
id: 'device_state.table.detail.echarts.used',
defaultMessage: '已占用',
})}`,
},
{
value: totalCount - record?.percent * totalCount,
name: `${intl.formatMessage({
id: 'device_state.table.detail.echarts.free',
defaultMessage: '未占用',
})}`,
},
];
let currNames = [];
currData.forEach((item) => {
currNames.push(item.name);
});
console.log(record, 'fetchOptionByData_record');
return {
title: {
text: record.label,
x: 'center',
y: '16.2%',
textStyle: {
fontSize: 16, // 标题文字大小
},
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)',
},
legend: {
orient: 'horizontal',
top: '37%',
data: currNames,
},
series: [
{
name: '名称',
type: 'pie',
center: ['50%', '20%'], // 调整 center 属性使饼图偏上
radius: ['28%', '45%'], // 控制环形图大小
color: [
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: record.usedColors[0],
},
{
offset: 1,
color: record.usedColors[1],
},
]),
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: record.freeColors[0],
},
{
offset: 1,
color: record.freeColors[1],
},
]),
],
avoidLabelOverlap: false,
label: {
show: false,
},
emphasis: {
label: {
show: false,
fontSize: '20',
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
data: currData,
},
],
};
};
// 模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
title: <FormattedMessage id="base_model.table.list.name" defaultMessage="基础模型名称" />,
dataIndex: 'name',
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
width: '45%',
},
{
title: <FormattedMessage id="base_model.table.list.version" defaultMessage="版本" />,
dataIndex: 'version',
hideInSearch: true,
width: '20%',
},
{
title: (
<FormattedMessage id="base_model.table.list.runtimeLibFile" defaultMessage="运行库镜像" />
),
dataIndex: 'runtimeLibFile',
hideInSearch: true,
render: (dom, record) => {
return (
<div>
{record.runtimeLibFile ? (
dom
) : (
<div className={`gn_list_type_tag flex items-center justify-center active2`}>
<span className="dot"></span>
<span>
<FormattedMessage
id="base_model.table.list.undeployed.runtimeLibFile"
defaultMessage="未部署"
/>
</span>
</div>
)}
</div>
);
},
},
];
// 将数据组装成reactDom
function toListDomByData(record) {
let startList = [...record];
let finalList = startList.map((item) => ({
content: (
<div>
<div className="gn_list_card_title pb-[12px]">
<span></span>
<span>{item.name}</span>
</div>
<ProTable
className="gn_pro_table mb-[16px]"
cardProps={{
bodyStyle: { padding: 0, margin: 0 },
}}
// 标题栏
search={false}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
rowKey="id"
onDataSourceChange={(data) => {
console.log(data, 'onDataSourceChange_data');
}}
pagination={false}
dataSource={item.list}
columns={columns}
/>
</div>
),
}));
setModelData(finalList);
console.log(finalList, 'toListDomByData_finalList');
}
// 基础模型列表数据api
async function fetchData() {
const resp = await getModelGroupBaseModelList();
if (isSuccessApi(resp)) {
toListDomByData(resp.data.results);
}
}
useEffect(() => {
setForceRender(detailOpen);
}, [detailOpen]);
// 初始化加载
useEffect(() => {
fetchData();
}, []);
return (
<Modal
width={proFormMaxModelWidth}
title={info?.deviceSort}
open={detailOpen}
onCancel={closeModal}
footer={null}
afterVisibleChange={(isVisible) => {
if (!isVisible) {
setForceRender(false); // Modal 关闭时重置状态
}
}}
>
<ProCard className="gn_card" bodyStyle={{ padding: 0 }}>
<Tabs
className="gn_tabs"
activeKey={tabKey}
items={tabs}
onChange={(key) => {
setTabKey(key);
}}
></Tabs>
{tabKey === '0' && (
<div>
<ProCard className="gn_card bs_server_info_wrap" bodyStyle={{ padding: 0 }}>
<ul>
<li className="pb-[8px]">
<p className="head4">
<FormattedMessage
id="device_state.table.detail.title.params"
defaultMessage="设备参数"
/>
</p>
<div className="my-[8px] gn_active_descriptions bg_active_4">
<ProDescriptions
column={4}
columns={ModelDetailColumns}
dataSource={info}
></ProDescriptions>
</div>
</li>
<li className="pb-[16px]">
<p className="head4">
<FormattedMessage
id="device_state.table.detail.title.info"
defaultMessage="硬件信息"
/>
</p>
<ul className="mt-[8px] flex items-center ">
{detailOpen &&
info?.progressData?.map((item, index) => {
return (
<li
key={index}
className={`w-[25%] bg_active_4 rounded ${
index !== 0 ? 'ml-[10px]' : ''
}`}
>
<div style={{ height: '140px' }}>
{forceRender && (
<ReactEcharts echarts={echarts} option={fetchOptionByData(item)} />
)}
</div>
</li>
);
})}
</ul>
</li>
<li className="pb-[8px] bs_server_task_wrap">
<p className="head4">
<FormattedMessage
id="device_state.table.detail.title.task"
defaultMessage="当前任务"
/>
</p>
<div className="pt-[8px]">
<ProList<{ title: string }>
itemLayout="vertical"
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
style: {
width: '100%',
border: 0,
},
}}
cardProps={{
style: { padding: 0, margin: 0 }, // 设置卡片的内外边距为 0
bodyStyle: {
padding: 0,
margin: 0,
height: 'calc(300px)',
overflow: 'scroll',
},
}}
rowKey="id"
dataSource={modelData}
pagination={false}
rowSelection={false}
metas={{
content: {
style: { margin: 0, padding: 0 },
},
}}
/>
</div>
</li>
</ul>
</ProCard>
</div>
)}
{tabKey === '1' && <DetailDeviceStateLog />}
</ProCard>
</Modal>
);
};
export default DetailDeviceState;

@ -0,0 +1,98 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-22 15:23:36
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 17:07:15
* @FilePath: \general-ai-platform-web\src\pages\Business\BusinessState\components\detailDeviceStateLog.tsx
* @Description:
* @
* 1
*/
import { getDeviceStateLogList } from '@/services/testApi/businessState';
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProCard, ProTable } from '@ant-design/pro-components';
import { FormattedMessage } from '@umijs/max';
import { useRef, useState } from 'react';
import { proTablePaginationOptions } from '../../../../../config/defaultTable';
const DetailDeviceStateLog: React.FC = () => {
const actionRef = useRef<ActionType>();
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
// 业务模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
title: <FormattedMessage id="device_state.table.stateLog.list.ip" defaultMessage="名称" />,
dataIndex: 'IP',
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
width: '40%',
},
{
title: (
<FormattedMessage id="device_state.table.stateLog.list.runTime" defaultMessage="运行时长" />
),
dataIndex: 'runTime',
hideInSearch: true,
width: '20%',
},
{
title: (
<FormattedMessage
id="device_state.table.stateLog.list.updateTime"
defaultMessage="更新时间"
/>
),
dataIndex: 'updateTime',
hideInSearch: true,
valueType: 'dateTime',
},
];
return (
<div className="detailDeviceStateLog_wrap">
<ProCard className="gn_card" bodyStyle={{ padding: 0 }}>
<ProTable
className="gn_pro_table"
cardProps={{
bodyStyle: { padding: 0 },
}}
// 标题栏
search={false}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
actionRef={actionRef}
rowKey="id"
pagination={{
...proTablePaginationOptions,
pageSize: currentPageSize,
onChange: (page, pageSize) => setCurrentPageSize(pageSize),
}}
columnsState={{
persistenceKey: 'bs_server_log_list',
persistenceType: 'localStorage',
}}
request={async (params = {}) => {
const { current, ...rest } = params;
const reqParams = {
page: current,
...rest,
};
let resp = await getDeviceStateLogList({ ...reqParams });
console.log(resp, 'getDeviceStateLogList_resp');
return {
data: resp.data?.results,
success: resp.success,
total: resp.data.count,
current: current,
pageSize: currentPageSize,
};
}}
columns={columns}
/>
</ProCard>
</div>
);
};
export default DetailDeviceStateLog;

@ -0,0 +1,367 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:05:25
* @FilePath: \general-ai-manage\src\pages\Project\BusinessProject\components\detailServerState.tsx
* @Description:
* @
*
*/
import { bsServerDetailEnums } from '@/enums/server';
import { getModelGroupBaseModelList } from '@/services/testApi/model';
import { isSuccessApi } from '@/utils/forApi';
import { ProCard, ProDescriptions, ProList, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Modal, Tabs } from 'antd';
import * as echarts from 'echarts';
import ReactEcharts from 'echarts-for-react';
import { useEffect, useState } from 'react';
import { proFormMaxModelWidth } from '../../../../../config/defaultForm';
import DetailServerStateLog from './detailServerStateLog';
type DetailServerStateProps = {
info: Record<string, any>;
detailOpen: boolean;
closeModal: () => void;
};
const DetailServerState: React.FC<DetailServerStateProps> = ({ info, detailOpen, closeModal }) => {
/**state */
const intl = useIntl();
const [tabKey, setTabKey] = useState<string>(bsServerDetailEnums[0].key);
const [tabs] = useState<DICTENUM.DICT_TAB_ITEM[]>([...bsServerDetailEnums]);
const [modelData, setModelData] = useState<Record<string, any>[]>([]); // 列表数据
const [forceRender, setForceRender] = useState<boolean>(false);
// 基础模型信息
const ModelDetailColumns = [
{
title: <FormattedMessage id="server_state.table.form.name" defaultMessage="服务器名称" />,
dataIndex: 'deviceSort',
},
{
title: <FormattedMessage id="server_state.table.form.ip" defaultMessage="IP" />,
dataIndex: 'IP',
},
{
title: (
<FormattedMessage id="server_state.table.form.defaultPort" defaultMessage="默认端口" />
),
dataIndex: 'port',
},
{
title: <FormattedMessage id="server_state.table.form.userName" defaultMessage="用户名" />,
dataIndex: 'userName',
},
{
title: <FormattedMessage id="server_state.table.form.pwd" defaultMessage="密码" />,
dataIndex: 'pwd',
render: () => {
return '*********';
},
},
];
// 硬件信息环形图
const fetchOptionByData = (record) => {
const totalCount = 100 * Math.floor(Math.random() * 15);
const currData = [
{
value: record?.percent * totalCount,
name: `${intl.formatMessage({
id: 'server_state.table.detail.echarts.used',
defaultMessage: '已占用',
})}`,
},
{
value: totalCount - record?.percent * totalCount,
name: `${intl.formatMessage({
id: 'server_state.table.detail.echarts.free',
defaultMessage: '未占用',
})}`,
},
];
let currNames = [];
currData.forEach((item) => {
currNames.push(item.name);
});
console.log(record, 'fetchOptionByData_record');
return {
title: {
text: record.label,
x: 'center',
y: '16.2%',
textStyle: {
fontSize: 16, // 标题文字大小
},
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)',
},
legend: {
orient: 'horizontal',
top: '37%',
data: currNames,
},
series: [
{
name: '名称',
type: 'pie',
center: ['50%', '20%'], // 调整 center 属性使饼图偏上
radius: ['28%', '45%'], // 控制环形图大小
color: [
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: record.usedColors[0],
},
{
offset: 1,
color: record.usedColors[1],
},
]),
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: record.freeColors[0],
},
{
offset: 1,
color: record.freeColors[1],
},
]),
],
avoidLabelOverlap: false,
label: {
show: false,
},
emphasis: {
label: {
show: false,
fontSize: '20',
fontWeight: 'bold',
},
},
labelLine: {
show: false,
},
data: currData,
},
],
};
};
// 模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
title: <FormattedMessage id="base_model.table.list.name" defaultMessage="基础模型名称" />,
dataIndex: 'name',
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
width: '45%',
},
{
title: <FormattedMessage id="base_model.table.list.version" defaultMessage="版本" />,
dataIndex: 'version',
hideInSearch: true,
width: '20%',
},
{
title: (
<FormattedMessage id="base_model.table.list.runtimeLibFile" defaultMessage="运行库镜像" />
),
dataIndex: 'runtimeLibFile',
hideInSearch: true,
render: (dom, record) => {
return (
<div>
{record.runtimeLibFile ? (
dom
) : (
<div className={`gn_list_type_tag flex items-center justify-center active2`}>
<span className="dot"></span>
<span>
<FormattedMessage
id="base_model.table.list.undeployed.runtimeLibFile"
defaultMessage="未部署"
/>
</span>
</div>
)}
</div>
);
},
},
];
// 将数据组装成reactDom
function toListDomByData(record) {
let startList = [...record];
let finalList = startList.map((item) => ({
content: (
<div>
<div className="gn_list_card_title pb-[12px]">
<span></span>
<span>{item.name}</span>
</div>
<ProTable
className="gn_pro_table mb-[16px]"
cardProps={{
bodyStyle: { padding: 0, margin: 0 },
}}
// 标题栏
search={false}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
rowKey="id"
onDataSourceChange={(data) => {
console.log(data, 'onDataSourceChange_data');
}}
pagination={false}
dataSource={item.list}
columns={columns}
/>
</div>
),
}));
setModelData(finalList);
console.log(finalList, 'toListDomByData_finalList');
}
// 基础模型列表数据api
async function fetchData() {
const resp = await getModelGroupBaseModelList();
if (isSuccessApi(resp)) {
toListDomByData(resp.data.results);
}
}
useEffect(() => {
setForceRender(detailOpen);
}, [detailOpen]);
// 初始化加载
useEffect(() => {
fetchData();
}, []);
return (
<Modal
width={proFormMaxModelWidth}
title={info?.deviceSort}
open={detailOpen}
onCancel={closeModal}
footer={null}
afterVisibleChange={(isVisible) => {
if (!isVisible) {
setForceRender(false); // Modal 关闭时重置状态
}
}}
>
<ProCard className="gn_card" bodyStyle={{ padding: 0 }}>
<Tabs
className="gn_tabs"
activeKey={tabKey}
items={tabs}
onChange={(key) => {
setTabKey(key);
}}
></Tabs>
{tabKey === '0' && (
<div>
<ProCard className="gn_card bs_server_info_wrap" bodyStyle={{ padding: 0 }}>
<ul>
<li className="pb-[8px]">
<p className="head4">
<FormattedMessage
id="server_state.table.detail.title.params"
defaultMessage="服务器参数"
/>
</p>
<div className="my-[8px] gn_active_descriptions bg_active_4">
<ProDescriptions
column={5}
columns={ModelDetailColumns}
dataSource={info}
></ProDescriptions>
</div>
</li>
<li className="pb-[16px]">
<p className="head4">
<FormattedMessage
id="server_state.table.detail.title.info"
defaultMessage="硬件信息"
/>
</p>
<ul className="mt-[8px] flex items-center ">
{detailOpen &&
info?.progressData?.map((item, index) => {
return (
<li
key={index}
className={`w-[25%] bg_active_4 rounded ${
index !== 0 ? 'ml-[10px]' : ''
}`}
>
<div style={{ height: '140px' }}>
{forceRender && (
<ReactEcharts echarts={echarts} option={fetchOptionByData(item)} />
)}
</div>
</li>
);
})}
</ul>
</li>
<li className="pb-[8px] bs_server_task_wrap">
<p className="head4">
<FormattedMessage
id="server_state.table.detail.title.task"
defaultMessage="当前任务"
/>
</p>
<div className="pt-[8px]">
<ProList<{ title: string }>
itemLayout="vertical"
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
style: {
width: '100%',
border: 0,
},
}}
cardProps={{
style: { padding: 0, margin: 0 }, // 设置卡片的内外边距为 0
bodyStyle: {
padding: 0,
margin: 0,
height: 'calc(300px)',
overflow: 'scroll',
},
}}
rowKey="id"
dataSource={modelData}
pagination={false}
rowSelection={false}
metas={{
content: {
style: { margin: 0, padding: 0 },
},
}}
/>
</div>
</li>
</ul>
</ProCard>
</div>
)}
{tabKey === '1' && <DetailServerStateLog />}
</ProCard>
</Modal>
);
};
export default DetailServerState;

@ -0,0 +1,99 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-22 15:23:36
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 14:44:54
* @FilePath: \general-ai-platform-web\src\pages\Business\BusinessState\components\detailServerStateLog.tsx
* @Description:
* @
* 1
*/
import { getServerStateLogList } from '@/services/testApi/businessState';
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProCard, ProTable } from '@ant-design/pro-components';
import { FormattedMessage } from '@umijs/max';
import { useRef, useState } from 'react';
import { proTablePaginationOptions } from '../../../../../config/defaultTable';
const DetailServerStateLog: React.FC = () => {
const actionRef = useRef<ActionType>();
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
// 业务模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
title: <FormattedMessage id="server_state.table.stateLog.list.ip" defaultMessage="名称" />,
dataIndex: 'IP',
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
},
{
title: (
<FormattedMessage id="server_state.table.stateLog.list.defaultPort" defaultMessage="端口" />
),
dataIndex: 'port',
hideInSearch: true,
},
{
title: (
<FormattedMessage
id="server_state.table.stateLog.list.createTime"
defaultMessage="创建时间"
/>
),
dataIndex: 'createTime',
hideInSearch: true,
valueType: 'dateTime',
},
];
return (
<div className="detailServerStateLog_wrap">
<ProCard className="gn_card" bodyStyle={{ padding: 0 }}>
<ProTable
className="gn_pro_table"
cardProps={{
bodyStyle: { padding: 0 },
}}
// 标题栏
search={false}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
actionRef={actionRef}
rowKey="key"
pagination={{
...proTablePaginationOptions,
pageSize: currentPageSize,
onChange: (page, pageSize) => setCurrentPageSize(pageSize),
}}
columnsState={{
persistenceKey: 'bs_server_log_list',
persistenceType: 'localStorage',
}}
request={async (params = {}) => {
const { current, ...rest } = params;
const reqParams = {
page: current,
...rest,
};
let resp = await getServerStateLogList({ ...reqParams });
console.log(resp, 'getServerStateLogList_resp');
return {
data: resp.data?.results.map((v: Record<string, any>) => {
return { ...v, key: v.id };
}),
success: resp.success,
total: resp.data.count,
current: current,
pageSize: currentPageSize,
};
}}
columns={columns}
/>
</ProCard>
</div>
);
};
export default DetailServerStateLog;

@ -0,0 +1,83 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 14:26:02
* @FilePath: \general-ai-manage\src\pages\Business\BusinessState\components\deviceStateCard.tsx
* @Description:
*/
import { AnimatePic } from '@/components/Animate';
import TableActionCard, { actionsProps } from '@/components/TableActionCard';
import { deviceStateEnums } from '@/enums/device';
import { Progress } from 'antd';
import json01 from '../../../../../public/animate/device/01.json'; //引入下载的动效json
type DeviceStateCardProps = {
info: Record<string, any>;
renderActions: actionsProps[];
fetchDetail: () => void;
};
const DeviceStateCard: React.FC<DeviceStateCardProps> = ({ info, renderActions, fetchDetail }) => {
const formatStateByVal = (record: string): DICTENUM.DICT_TAB_ITEM => {
return deviceStateEnums.find((item: DICTENUM.DICT_TAB_ITEM) => item.key === record);
};
return (
<div
onClick={() => {
console.log('服务器详情展示');
fetchDetail();
}}
className={`bs_card_box ${formatStateByVal(info?.state)?.className}`}
>
<div className="flex justify-between w-full p-[12px] bs_card_header">
<div className="flex items-center title_box">
<div className="bs_card_name single_line head4">{info?.deviceSort}</div>
<div
className={`gn_card_tag ml-[8px] text-white ${
info?.state === '1' ? 'bg_active_1' : ''
} ${info?.state === '2' ? 'bg_gray_color_1' : ''} ${
info?.state === '3' ? 'bg_active_3' : ''
} ${info?.state === '4' ? 'bg_active_2' : ''}`}
>
{formatStateByVal(info?.state)?.label}
</div>
</div>
<span>
<TableActionCard renderActions={renderActions} maxActionCount={3}></TableActionCard>
</span>
</div>
<div className="flex bs_card_content px-[12px] py-[6px] items-center">
<div className="device-content-left w-[100px] mr-[10px]">
<AnimatePic value={json01} />
</div>
<div className="flex-1">
<ul className="w-full">
{info?.progressData?.map((v, k) => {
return (
<li key={k}>
<div className="flex rectProgress_box my-[6px]">
<div className="pr-[4px] text3 pt-[5px]">{v.label}</div>
<div className="flex items-center flex-1">
<Progress
style={{ padding: 0, margin: 0, borderRadius: 0 }}
size={['100%', 10]}
height={46}
percent={v.percent * 100}
strokeColor={v.strokeColor}
showInfo={false}
/>
</div>
</div>
</li>
);
})}
</ul>
</div>
</div>
</div>
);
};
export default DeviceStateCard;

@ -0,0 +1,81 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 14:25:55
* @FilePath: \general-ai-manage\src\pages\Business\BusinessState\components\serverStateCard.tsx
* @Description:
*/
import { AnimatePic } from '@/components/Animate';
import TableActionCard, { actionsProps } from '@/components/TableActionCard';
import { serverStateEnums } from '@/enums/server';
import { Progress } from 'antd';
import json01 from '../../../../../public/animate/device/01.json'; //引入下载的动效json
type ServerStateCardProps = {
info: Record<string, any>;
renderActions: actionsProps[];
fetchDetail: () => void;
};
const ServerStateCard: React.FC<ServerStateCardProps> = ({ info, renderActions, fetchDetail }) => {
const formatStateByVal = (record: string): DICTENUM.DICT_TAB_ITEM => {
return serverStateEnums.find((item: DICTENUM.DICT_TAB_ITEM) => item.key === record);
};
return (
<div
onClick={() => {
console.log('服务器详情展示');
fetchDetail();
}}
className={`bs_card_box ${formatStateByVal(info?.state)?.className}`}
>
<div className="flex justify-between w-full p-[12px] bs_card_header">
<div className="flex items-center title_box">
<div className="bs_card_name single_line head4">{info?.deviceSort}</div>
<div
className={`gn_card_tag ml-[8px] text-white ${
info?.state === '1' ? 'bg_active_1' : 'bg_gray_color_1'
}`}
>
{formatStateByVal(info?.state).label}
</div>
</div>
<span>
<TableActionCard renderActions={renderActions} maxActionCount={3}></TableActionCard>
</span>
</div>
<div className="flex bs_card_content px-[12px] py-[6px] items-center">
<div className="server-content-left w-[100px] mr-[10px]">
<AnimatePic value={json01} />
</div>
<div className="flex-1">
<ul className="w-full">
{info?.progressData?.map((v, k) => {
return (
<li key={k}>
<div className="flex rectProgress_box my-[6px]">
<div className="pr-[4px] text3 pt-[5px]">{v.label}</div>
<div className="flex items-center flex-1">
<Progress
style={{ padding: 0, margin: 0, borderRadius: 0 }}
size={['100%', 10]}
height={46}
percent={v.percent * 100}
strokeColor={v.strokeColor}
showInfo={false}
/>
</div>
</div>
</li>
);
})}
</ul>
</div>
</div>
</div>
);
};
export default ServerStateCard;

@ -0,0 +1,297 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-10 10:47:45
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 14:57:18
* @FilePath: \general-ai-platform-web\src\pages\Business\BusinessState\deviceSate.tsx
* @Description:
* @
* 1
* 2
*/
import { CommButton, TextButton } from '@/components/Button';
import IsConfirmAction from '@/components/TableActionCard/isConfirmAction';
import { deviceStateEnums } from '@/enums/device';
import { getDeviceStateList } from '@/services/testApi/businessState';
import { getDictDeviceType } from '@/services/testApi/dict';
import { isSuccessApi } from '@/utils/forApi';
import { ProCard, ProForm, ProFormSelect, ProList } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Tabs } from 'antd';
import { useEffect, useState } from 'react';
import { proTablePaginationOptions } from '../../../../config/defaultTable';
import DetailDeviceState from './components/detailDeviceState';
import DeviceStateCard from './components/deviceStateCard';
import './index.less';
import { ReactComponent as ResetIcon } from '/public/home/reset_icon.svg';
import { ReactComponent as SearchIcon } from '/public/home/search_icon.svg';
const DeviceSate: React.FC = () => {
/**state */
const intl = useIntl();
// 列表
const [serverList, setServerList] = useState<Record<string, any>[]>([]); // 列表数据
const [currentRow, setCurrentRow] = useState<Record<string, any>>();
const [currentPageSize, setCurrentPageSize] = useState<number>(8);
const [currentPage, setCurrentPage] = useState<number>(1);
const [total, setTotal] = useState<number>(1);
// 详情展示
const [detailOpen, setDetailOpen] = useState<boolean>(false);
// 切换筛选
const [form] = ProForm.useForm(); // form 对象
const [querysData, setQuerysData] = useState<Record<string, any>>({}); // 列表查询参数
const [tabKey, setTabKey] = useState<string>(deviceStateEnums[0].key);
const [tabs, setTabs] = useState<DICTENUM.DICT_TAB_ITEM[]>([]);
// 将数据组装成reactDom
function toListDomByData(record) {
let startList = [...record];
let finalList = startList.map((item) => ({
content: (
<DeviceStateCard
info={item}
fetchDetail={() => {
setCurrentRow(item);
setDetailOpen(true);
}}
renderActions={[
{
key: 'detail',
renderDom: (
<span>
<TextButton
className="text-[12px]"
buttonLabel={
<FormattedMessage id="pages.searchTable.detail" defaultMessage="详情" />
}
buttonType="primary"
></TextButton>
</span>
),
},
{
key: 'destroy',
renderDom: (
<span>
<IsConfirmAction
title={`${intl.formatMessage({
id: 'pages.searchTable.reOpen',
defaultMessage: '重启',
})}`}
buttonRender={
<TextButton
fontSize={12}
buttonLabel={
<FormattedMessage id="pages.searchTable.reOpen" defaultMessage="重启" />
}
buttonType="danger"
></TextButton>
}
confirmAction={() => {
// TODO 调用重启接口
}}
/>
</span>
),
},
]}
></DeviceStateCard>
),
}));
setServerList(finalList);
console.log(finalList, 'toListDomByData_finalList');
}
// 企业列表数据api
async function fetchData() {
const resp = await getDeviceStateList({
page: currentPage,
pageSize: currentPageSize,
status: tabKey,
...querysData,
});
if (isSuccessApi(resp)) {
toListDomByData(resp.data.results);
setTabs(() => {
const finalArr = [];
JSON.parse(JSON.stringify(deviceStateEnums)).forEach((item) => {
switch (item.key) {
case '1':
item.label = `${deviceStateEnums[1].label}${resp.data.onlineCount}`;
break;
case '2':
item.label = `${deviceStateEnums[2].label}${resp.data.outlineCount}`;
break;
case '3':
item.label = `${deviceStateEnums[3].label}${resp.data.processCount}`;
break;
case '4':
item.label = `${deviceStateEnums[4].label}${resp.data.errorCount}`;
break;
case '0':
default:
item.label = `${deviceStateEnums[0].label}${resp.data.count}`;
break;
}
finalArr.push(item);
});
return finalArr;
});
setTotal(() => {
switch (tabKey) {
case '1':
return resp.data.onlineCount;
case '2':
return resp.data.outlineCount;
case '3':
return resp.data.processCount;
case '4':
return resp.data.errorCount;
default:
return resp.data.count;
}
});
}
}
// TODO 切换时页码没有显示第一页
const changeTabMode = (key: string) => {
setTabKey(key);
setCurrentPage(1);
console.log(key);
};
// function reloadList() {
// setTabKey('0');
// setCurrentPage(1);
// }
// 初始化加载 & 筛选查询
useEffect(() => {
fetchData();
}, [tabKey, currentPageSize, currentPage, querysData]);
return (
<div className="flex-1 bs_server_state_page bs_state_page gn_head_card">
<div className="gn_table_query_filter">
<ProForm
form={form}
layout="horizontal"
submitter={{
render: () => (
<div style={{ textAlign: 'center', marginLeft: 12 }}>
<CommButton
type="primary"
htmlType="submit"
prevIcon={<SearchIcon />}
buttonLabel={
<FormattedMessage id="pages.searchTable.search" defaultMessage="查询" />
}
></CommButton>
<CommButton
style={{ marginLeft: 12 }}
htmlType="button"
prevIcon={<ResetIcon />}
buttonLabel={
<FormattedMessage id="pages.searchTable.reset" defaultMessage="重置" />
}
onClick={() => {
form.resetFields(); // 点击重置按钮时重置表单数据
setQuerysData(() => {}); // 清空筛选项
}}
></CommButton>
</div>
),
}}
onFinish={async (values) => {
console.log(values, 'filter_finish_values');
setQuerysData(() => values);
return true;
}}
>
{/* //TODO 缺失筛选条件设备组 树形选择*/}
<ProFormSelect
width={300}
name="deviceType"
label={
<FormattedMessage
id="device_group_list.table.list.deviceType"
defaultMessage="设备分类"
/>
}
placeholder={`${intl.formatMessage({
id: 'common.please_select',
defaultMessage: '$$$',
})}${intl.formatMessage({
id: 'device_group_list.table.list.deviceType',
defaultMessage: '设备分类',
})}`}
showSearch
debounceTime={500}
request={async () => {
const { data } = await getDictDeviceType();
return data?.results?.map((v: Record<string, any>) => {
return { ...v, label: v.name, value: v.id };
});
}}
/>
</ProForm>
</div>
<ProCard className="gn_card pb-[16px]">
<div className="bs_server_state_box">
<Tabs
className="gn_tabs"
activeKey={tabKey}
items={tabs}
onChange={(key) => {
changeTabMode(key);
}}
></Tabs>
<ProList<any>
className="gn"
ghost={true}
rowKey={'id'}
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
}}
cardProps={{
bodyStyle: {
background: 'transparent',
margin: '-4px 0',
},
}}
pagination={{
...proTablePaginationOptions,
page: currentPage,
pageSize: currentPageSize,
total: total || 0, // 指定总条目数
onChange: (page, pageSize) => {
setCurrentPageSize(pageSize);
setCurrentPage(page);
},
}}
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 3, xl: 4, xxl: 5 }}
metas={{
content: {},
}}
dataSource={serverList}
/>
</div>
</ProCard>
<DetailDeviceState
detailOpen={detailOpen}
info={currentRow}
closeModal={() => {
setDetailOpen(false);
}}
/>
</div>
);
};
export default DeviceSate;

@ -0,0 +1,26 @@
/* 服务器 设备 共用 */
.bs_state_page .bs_card_box {
width: 100%;
background: #f4f8fe;
}
.bs_state_page .bs_card_box .bs_card_header {
background: linear-gradient(90deg, #d5e6fe 0%, rgba(213, 230, 254, 0) 100%);
}
.bs_state_page .bs_card_box .bs_card_header .bs_card_name {
max-width: 100px;
}
.bs_state_page .bs_card_box.outline_info {
background: #f5f5f5;
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
-webkit-filter: gray;
-webkit-filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
filter: grayscale(100%);
filter: gray;
filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
}
.bs_state_page .bs_card_box.outline_info .bs_card_header {
background: linear-gradient(90deg, #dcdcdc 0%, rgba(245, 245, 245, 0) 100%);
}

@ -0,0 +1,40 @@
/* 服务器 设备 共用 */
@import url('@/base.less');
.bs_state_page {
.bs_card_box {
width: 100%;
background: #f4f8fe;
.bs_card_header {
background: linear-gradient(90deg, #d5e6fe 0%, rgba(213, 230, 254, 0) 100%);
.bs_card_name {
max-width: 100px;
}
}
// 离线
&.outline_info {
.gray_info_all();
background: #f5f5f5;
// .bs_card_header {
// background: linear-gradient(90deg, #dcdcdc 0%, rgba(245, 245, 245, 0) 100%);
// }
}
// 在线
// &.online_info {
// }
}
}
// 基础模型设置
.bs_server_task_wrap {
.ant-list-items {
.ant-list-item {
margin: 0;
padding: 0;
border: none;
.ant-pro-list-row-content {
margin: 0;
padding: 0;
}
}
}
}

@ -0,0 +1,238 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-07 13:38:03
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 13:39:39
* @FilePath: \general-ai-platform-web\src\pages\Business\BusinessState\index.tsx
* @Description: businessStatebs
* @
* 1
* 2
*/
import { CommButton, TextButton } from '@/components/Button';
import IsDelete from '@/components/TableActionCard/isDelete';
import { serverStateEnums } from '@/enums/server';
import { getServerStateList } from '@/services/testApi/businessState';
import { isSuccessApi } from '@/utils/forApi';
import { ProCard, ProList } from '@ant-design/pro-components';
import { FormattedMessage } from '@umijs/max';
import { Tabs } from 'antd';
import { useEffect, useState } from 'react';
import { proTablePaginationOptions } from '../../../../config/defaultTable';
import CreateServerForm from './components/createServerForm';
import DetailServerState from './components/detailServerState';
import ServerStateCard from './components/serverStateCard';
import './index.less';
const BusinessState: React.FC = () => {
/**state */
// 列表
const [serverList, setServerList] = useState<Record<string, any>[]>([]); // 列表数据
const [currentRow, setCurrentRow] = useState<Record<string, any>>();
const [currentPageSize, setCurrentPageSize] = useState<number>(8);
const [currentPage, setCurrentPage] = useState<number>(1);
const [total, setTotal] = useState<number>(1);
const [createModalOpen, setCreateModalOpen] = useState<boolean>(false);
// 详情展示
const [detailOpen, setDetailOpen] = useState<boolean>(false);
// 切换筛选
const [tabKey, setTabKey] = useState<string>(serverStateEnums[0].key);
const [tabs, setTabs] = useState<DICTENUM.DICT_TAB_ITEM[]>([]);
// 新增
const handleCreateModal = () => {
setCreateModalOpen(!createModalOpen);
};
// 将数据组装成reactDom
function toListDomByData(record) {
let startList = [...record];
let finalList = startList.map((item) => ({
content: (
<ServerStateCard
info={item}
fetchDetail={() => {
setCurrentRow(item);
setDetailOpen(true);
}}
renderActions={[
{
key: 'update',
renderDom: (
<span
onClick={(e) => {
e.stopPropagation();
setCurrentRow(item);
console.log('编辑');
}}
>
<TextButton
className="text-[12px]"
buttonLabel={
<FormattedMessage id="pages.searchTable.update" defaultMessage="编辑" />
}
buttonType="primary"
></TextButton>
</span>
),
},
{
key: 'destroy',
renderDom: (
<span>
<IsDelete
deleteNextText={
<FormattedMessage id="pages.searchTable.destroy" defaultMessage="删除" />
}
buttonRender={
<TextButton
fontSize={12}
buttonLabel={
<FormattedMessage id="pages.searchTable.destroy" defaultMessage="删除" />
}
buttonType="danger"
></TextButton>
}
deleteApi={() => {
// TODO 调用删除接口
// handleDestroy(record).then(() => {});
}}
/>
</span>
),
},
]}
></ServerStateCard>
),
}));
setServerList(finalList);
console.log(finalList, 'toListDomByData_finalList');
}
// 企业列表数据api
async function fetchData() {
const resp = await getServerStateList({
page: currentPage,
pageSize: currentPageSize,
status: tabKey,
});
if (isSuccessApi(resp)) {
toListDomByData(resp.data.results);
setTabs(() => {
const finalArr = [];
JSON.parse(JSON.stringify(serverStateEnums)).forEach((item) => {
switch (item.key) {
case '0':
item.label = `${serverStateEnums[0].label}${resp.data.count}`;
break;
case '1':
item.label = `${serverStateEnums[1].label}${resp.data.onlineCount}`;
break;
case '2':
item.label = `${serverStateEnums[2].label}${resp.data.outlineCount}`;
break;
}
finalArr.push(item);
});
return finalArr;
});
setTotal(() => {
switch (tabKey) {
case '1':
return resp.data.onlineCount;
case '2':
return resp.data.outlineCount;
default:
return resp.data.count;
}
});
}
}
// TODO 切换时页码没有显示第一页
const changeTabMode = (key: string) => {
setTabKey(key);
setCurrentPage(1);
console.log(key);
};
function reloadList() {
setTabKey('0');
setCurrentPage(1);
}
// 初始化加载 & 筛选查询
useEffect(() => {
fetchData();
}, [tabKey, currentPageSize, currentPage]);
return (
<div className="flex-1 bs_server_state_page bs_state_page gn_head_card">
<ProCard className="gn_card pb-[16px]">
<div className="bs_server_state_box">
<Tabs
className="gn_tabs"
activeKey={tabKey}
items={tabs}
onChange={(key) => {
changeTabMode(key);
}}
></Tabs>
<div className="flex justify-end pb-[12px]">
<CommButton
type="primary"
onClick={() => {
setCreateModalOpen(true);
}}
buttonLabel={
<FormattedMessage id="server_state.table.list.add" defaultMessage="新建" />
}
></CommButton>
</div>
<ProList<any>
className="gn"
ghost={true}
rowKey={'id'}
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
}}
cardProps={{
bodyStyle: {
background: 'transparent',
margin: '-4px 0',
},
}}
pagination={{
...proTablePaginationOptions,
page: currentPage,
pageSize: currentPageSize,
total: total || 0, // 指定总条目数
onChange: (page, pageSize) => {
setCurrentPageSize(pageSize);
setCurrentPage(page);
},
}}
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 3, xl: 4, xxl: 5 }}
metas={{
content: {},
}}
dataSource={serverList}
/>
</div>
</ProCard>
<CreateServerForm
createModalOpen={createModalOpen}
handleModal={handleCreateModal}
reload={reloadList}
/>
<DetailServerState
detailOpen={detailOpen}
info={currentRow}
closeModal={() => {
setDetailOpen(false);
}}
/>
</div>
);
};
export default BusinessState;

@ -53,7 +53,7 @@ const BaseInfo: React.FC<BaseInfoProps> = ({ info }) => {
},
];
return (
<div className="gn_table_descriptions bg_active_1">
<div className="gn_active_descriptions bg_active_4">
<ProDescriptions column={3} columns={DeviceDetailColumns} dataSource={info}></ProDescriptions>
</div>
);

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-22 15:23:36
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 17:00:52
* @LastEditTime: 2024-05-10 15:34:31
* @FilePath: \general-ai-platform-web\src\pages\Business\DeviceGroup\components\deviceList.tsx
* @Description: deviceGroupdg
* @
@ -91,7 +91,7 @@ const DeviceList: React.FC<DeviceListProps> = () => {
render: (dom, record) => {
return (
<div
className={`model_index_type_tag flex items-center justify-center ${
className={`gn_list_type_tag flex items-center justify-center ${
record.isEnable ? 'active1' : 'active2'
}`}
>
@ -134,7 +134,6 @@ const DeviceList: React.FC<DeviceListProps> = () => {
size="small"
onClick={() => {
setCurrentRow(record);
setIsSettingOpen(true);
// history.push('/home/model-detail');
// doToDetail(record);
@ -232,7 +231,7 @@ const DeviceList: React.FC<DeviceListProps> = () => {
// scroll={{ y: proTableCommonOptions.commscrollY, x: proTableCommonOptions.commscrollX }}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
actionRef={actionRef}
rowKey="key"
rowKey="id"
onDataSourceChange={(data) => {
console.log(data, 'onDataSourceChange_data');
// let CategoryFkIdIds: any = data.map((v) => {
@ -258,9 +257,7 @@ const DeviceList: React.FC<DeviceListProps> = () => {
let resp = await getDeviceListByGroup({ ...reqParams });
console.log(resp, 'getDeviceListByGroup_resp');
return {
data: resp.data?.results.map((v: Record<string, any>) => {
return { ...v, key: v.id };
}),
data: resp.data?.results,
success: resp.success,
total: resp.data.count,
current: current,

@ -2,25 +2,26 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-30 10:02:29
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 16:58:57
* @LastEditTime: 2024-05-10 16:41:37
* @FilePath: \general-ai-platform-web\src\pages\Business\DeviceGroup\components\modelDeploy.tsx
* @Description:
* @
* 1
* 2
*/
import { TextButton } from '@/components/Button';
import TableActionCard from '@/components/TableActionCard';
import { getBusinessModelList } from '@/services/testApi/businessModel';
import { ExclamationCircleFilled } from '@ant-design/icons';
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { ProTable } from '@ant-design/pro-components';
import { FormattedMessage } from '@umijs/max';
import { Button } from 'antd';
import { useRef, useState } from 'react';
import {
proTableCommonOptions,
proTablePaginationOptions,
} from '../../../../../config/defaultTable';
import ModelDeployConfig from './modelDeployConfig';
// import CreateForm from './components/createForm';
const ModelDeploy: React.FC = () => {
@ -31,14 +32,13 @@ const ModelDeploy: React.FC = () => {
// const [categoryFkIdIds, setCategoryFkIdIds] = useState([]);
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
// const [currentRow, setCurrentRow] = useState<Record<string, any>>({});
const [currentRow, setCurrentRow] = useState<Record<string, any>>({});
// 部署参数配置展示
const [detailOpen, setDetailOpen] = useState<boolean>(false);
/**配置参数 */
// function reloadList() {
// actionRef.current?.reload();
// }
// 业务模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
@ -52,11 +52,10 @@ const ModelDeploy: React.FC = () => {
title: <FormattedMessage id="business_model.table.list.isEnable" defaultMessage="部署状态" />,
dataIndex: 'isEnable',
hideInSearch: true,
// width: 80,
render: (dom, record) => {
return (
<div
className={`model_index_type_tag flex items-center justify-center ${
className={`gn_list_type_tag flex items-center justify-center ${
record.isEnable ? 'active1' : 'active2'
}`}
>
@ -94,24 +93,30 @@ const ModelDeploy: React.FC = () => {
valueType: 'option',
fixed: 'right',
key: 'option',
render: () => [
render: (_, record) => [
<TableActionCard
key="TableActionCardRef"
renderActions={[
{
key: 'updateDetail',
key: 'config',
renderDom: (
<Button
key="updateDetail"
type="link"
size="small"
<span
onClick={() => {
// TODO 编辑在新增联调后实现
// setCurrentRow(record);
setCurrentRow(record);
setDetailOpen(true);
}}
>
<FormattedMessage id="pages.searchTable.updateDetail" defaultMessage="配置参数" />
</Button>
<TextButton
className="text-[12px]"
buttonLabel={
<FormattedMessage
id="business_model.table.list.action.config"
defaultMessage="配置参数"
/>
}
buttonType="primary"
></TextButton>
</span>
),
},
]}
@ -177,6 +182,14 @@ const ModelDeploy: React.FC = () => {
}}
columns={columns}
/>
<ModelDeployConfig
detailOpen={detailOpen}
info={currentRow}
closeModal={() => {
setDetailOpen(false);
}}
/>
</div>
);
};

@ -0,0 +1,178 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 17:28:39
* @FilePath: \general-ai-manage\src\pages\Project\BusinessProject\components\detailServerState.tsx
* @Description:
* @
*
*/
import { getAllDeviceList } from '@/services/testApi/device';
import { ProCard, ProColumns, ProDescriptions, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Modal } from 'antd';
import { useEffect, useRef, useState } from 'react';
import { proFormMaxModelWidth } from '../../../../../config/defaultForm';
type ModelDeployConfigProps = {
info: Record<string, any>;
detailOpen: boolean;
closeModal: () => void;
};
const ModelDeployConfig: React.FC<ModelDeployConfigProps> = ({ info, detailOpen, closeModal }) => {
/**state */
const intl = useIntl();
const [selectedRows, setSelectedRows] = useState<Record<string, any>[]>([]);
const actionRef = useRef();
// 基础配置信息
const detailColumns = [
{
title: (
<FormattedMessage
id="business_model.deploy.config.bussnessName"
defaultMessage="业务名称"
/>
),
dataIndex: 'bussnessName',
},
{
title: <FormattedMessage id="business_model.deploy.config.remark" defaultMessage="简介" />,
dataIndex: 'remark',
},
{
title: (
<FormattedMessage
id="business_model.deploy.config.linkModels"
defaultMessage="关联基础模型"
/>
),
dataIndex: 'linkModels',
render: (_, record) => {
return (
<ul className="flex flex-wrap">
{record?.linkModels?.map((item, index) => {
return (
<li
className={`text_primary primary_border rounded-[2px] px-[8px] mb-[8px] ${
index !== 0 ? 'ml-[8px]' : ''
}`}
key={item.id}
>
{item.name}
</li>
);
})}
</ul>
);
},
},
];
// 模型列表信息
const columns: ProColumns<Record<string, any>>[] = [
{
title: (
<FormattedMessage id="business_model.deploy.config.table.name" defaultMessage="设备名称" />
),
dataIndex: 'name',
hideInSearch: true,
key: 'fixedName',
fixed: 'left',
width: '55%',
},
{
title: (
<FormattedMessage
id="business_model.deploy.config.table.deviceType"
defaultMessage="设备类型"
/>
),
dataIndex: 'deviceType',
hideInSearch: true,
},
];
// 基础模型列表数据api
function loadData() {}
// 初始化加载
useEffect(() => {
console.log('modelDeployConfig_detailOpen', detailOpen);
if (detailOpen) {
loadData();
} else {
actionRef?.current?.clearSelected();
setSelectedRows([]);
}
}, [detailOpen]);
return (
<Modal
width={proFormMaxModelWidth}
title={`${intl.formatMessage({
id: 'business_model.table.list.action.config',
defaultMessage: '配置参数',
})}`}
open={detailOpen}
onCancel={() => {
closeModal();
}}
onOk={() => {
console.log('onOk_selectedRows', selectedRows);
// TODO 选择完成后再关闭弹框
closeModal();
}}
okText={<FormattedMessage id="pages.modelForm.okText" defaultMessage="确认" />}
cancelText={<FormattedMessage id="pages.modelForm.cancelText" defaultMessage="取消" />}
>
<ProCard className="gn_card" bodyStyle={{ padding: 0 }}>
<div className="my-[8px] gn_active_descriptions bg_active_4">
<ProDescriptions column={1} columns={detailColumns} dataSource={info}></ProDescriptions>
</div>
<div className="head4 py-[8px]">
<FormattedMessage
id="business_model.deploy.config.table.title.name"
defaultMessage="请选择"
/>
</div>
<ProTable
style={{
height: '300px',
overflowY: 'scroll',
}}
className="gn_pro_table"
cardProps={{
bodyStyle: { padding: 0 },
}}
actionRef={actionRef}
// 标题栏
search={false}
options={{ fullScreen: false, setting: false, density: false, reload: false }}
rowKey="id"
pagination={false}
rowSelection={{
onChange: (_, selectedRowsData) => {
setSelectedRows(selectedRowsData);
},
}}
tableAlertOptionRender={() => {
return <>{selectedRows?.length > 0 && <></>}</>;
}}
request={async () => {
let resp = await getAllDeviceList();
console.log(resp, 'getAllDeviceList_resp');
return {
data: resp.data?.results,
success: resp.success,
};
}}
columns={columns}
/>
</ProCard>
</Modal>
);
};
export default ModelDeployConfig;

@ -67,7 +67,7 @@ const ModelSetting: React.FC<ModelSettingProps> = () => {
{record.runtimeLibFile ? (
dom
) : (
<div className={`model_index_type_tag flex items-center justify-center active2`}>
<div className={`gn_list_type_tag flex items-center justify-center active2`}>
<span className="dot"></span>
<span>
<FormattedMessage

@ -12,29 +12,6 @@
.deviceGroup_page .node_info {
padding-left: 0;
}
.model_index_type_tag {
width: 82px;
height: 24px;
color: #52c41a;
background: #e8f7e6;
border: 1px solid #baeea1;
border-radius: 12px;
}
.model_index_type_tag .dot {
width: 6px;
height: 6px;
margin-right: 4px;
background: #52c41a;
border-radius: 50%;
}
.model_index_type_tag.active2 {
color: #e80d0d;
background: #feefee;
border: 1px solid #f9b2ae;
}
.model_index_type_tag.active2 .dot {
background: #e80d0d;
}
.dg_modelSetting_page .ant-list-items .ant-list-item {
margin: 0;
padding: 0;

@ -17,31 +17,6 @@
}
}
.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;
}
}
}
// 基础模型设置
.dg_modelSetting_page {

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-22 15:23:36
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 10:27:14
* @LastEditTime: 2024-05-10 17:29:38
* @FilePath: \general-ai-platform-web\src\pages\Business\DeviceGroup\index.tsx
* @Description: deviceGroupdg
* @
@ -13,7 +13,7 @@
* 5
*/
import { DeviceGroupTree } from '@/components/Tree';
import { deviceGroupEnums } from '@/enums/deviceGroup';
import { deviceGroupEnums } from '@/enums/device';
import { getDeviceGroupList } from '@/services/testApi/deviceGroup';
import { ProCard } from '@ant-design/pro-components';
import { Button, Tabs } from 'antd';
@ -34,7 +34,7 @@ const DeviceGroup: React.FC = () => {
const [createModalOpen, setCreateModalOpen] = useState<boolean>(false); // 创建新增窗口是否打开
// 切换模块
const [tabKey, setTabKey] = useState<string>(deviceGroupEnums[0].key);
const [tabKey, setTabKey] = useState<string>(deviceGroupEnums[1].key);
const [tabs] = useState<any>([...deviceGroupEnums]);
const changeTabMode = (key: string) => {
setTabKey(key);
@ -69,7 +69,7 @@ const DeviceGroup: React.FC = () => {
<div className="flex deviceGroup_page">
{/* 节点列表 */}
<div className="dg_content gn_head_card w-[300px] node_list">
<ProCard className="gn_card pb-[16px]" title={<span className="head5"></span>}>
<ProCard className="gn_card pb-[16px]" title={<span className="head3"></span>}>
<div className="dg_tree_box">
<DeviceGroupTree
dataSource={deviceTreeList}
@ -96,7 +96,7 @@ const DeviceGroup: React.FC = () => {
<div className="flex-1 dg_content gn_head_card node_info">
<ProCard
className="gn_card pb-[16px]"
title={<span className="head5"></span>}
title={<span className="head3"></span>}
extra={
<Button
type="primary"
@ -112,6 +112,7 @@ const DeviceGroup: React.FC = () => {
<div className="dg_content_box">
<BaseInfo info={nodeInfo} />
<Tabs
className="gn_tabs"
activeKey={tabKey}
items={tabs}
onChange={(key) => {

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 10:36:06
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-06 10:30:32
* @LastEditTime: 2024-05-07 13:28:53
* @FilePath: \general-ai-manage\src\pages\Model\ModelDetail\index.tsx
* @Description:
* @
@ -202,13 +202,13 @@ const ModelDetail: React.FC = () => {
},
];
return (
<div className="modelIndex_page home_container">
<div className="modelDetail_page home_container">
<ProCard
style={{ padding: 0, margin: 0, backgroundColor: 'transparent' }}
bodyStyle={{ padding: 0, margin: 0, backgroundColor: 'transparent' }}
>
<InnerPageBack title=""></InnerPageBack>
<div className="gn_table_descriptions mb-[20px]">
<div className="gn_active_descriptions mb-[20px]">
<ProDescriptions
column={3}
columns={ModelDetailColumns}

@ -1,23 +0,0 @@
.modelIndex_page .model_index_type_tag {
width: 82px;
height: 24px;
background: rgba(21, 77, 221, 0.1);
border: 1px solid rgba(21, 77, 221, 0.4);
border-radius: 12px;
color: #154DDD;
}
.modelIndex_page .model_index_type_tag .dot {
width: 6px;
height: 6px;
background: #154ddd;
border-radius: 50%;
margin-right: 4px;
}
.modelIndex_page .model_index_type_tag.active2 {
color: #FF8413;
background: #FFF3E8;
border: 1px solid #FFBF84;
}
.modelIndex_page .model_index_type_tag.active2 .dot {
background: #ff8413;
}

@ -1,25 +1,3 @@
.modelIndex_page {
.model_index_type_tag {
width: 82px;
height: 24px;
color: #154ddd;
background: rgba(21, 77, 221, 0.1);
border: 1px solid rgba(21, 77, 221, 0.4);
border-radius: 12px;
.dot {
width: 6px;
height: 6px;
margin-right: 4px;
background: #154ddd;
border-radius: 50%;
}
&.active2 {
color: #ff8413;
background: #fff3e8;
border: 1px solid #ffbf84;
.dot {
background: #ff8413;
}
}
}
// 业务层样式
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-07 14:02:00
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-30 15:01:14
* @LastEditTime: 2024-05-09 10:25:13
* @FilePath: \general-ai-manage\src\pages\ModelIndex\ModelIndex.tsx
* @Description:
* @
@ -49,11 +49,7 @@ const ModelIndex: React.FC = () => {
/**新增 设置行业分类 删除 */
// 新增
const handleCreateModal = () => {
if (createModalOpen) {
setCreateModalOpen(false);
} else {
setCreateModalOpen(true);
}
setCreateModalOpen(!createModalOpen);
};
// 设置行业分类
const handleSetIndustry = () => {
@ -78,17 +74,17 @@ const ModelIndex: React.FC = () => {
dataIndex: 'type',
hideInSearch: true,
render: (dom, record) => {
let activeName = 'active1';
let activeName = 'active_primary';
switch (record.type) {
case '深度学习':
activeName = 'active2';
activeName = 'active3';
break;
default:
activeName = 'active1';
activeName = 'active_primary';
break;
}
return (
<div className={`model_index_type_tag flex items-center justify-center ${activeName}`}>
<div className={`gn_list_type_tag flex items-center justify-center ${activeName}`}>
<span className="dot"></span>
<span>{dom}</span>
</div>

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 10:36:06
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-18 10:10:40
* @LastEditTime: 2024-05-07 13:29:08
* @FilePath: \general-ai-manage\src\pages\Model\ModelRuntimeLib\index.tsx
* @Description:
* @
@ -152,7 +152,7 @@ const ModelRuntimeLib: React.FC = () => {
},
];
return (
<div className="modelIndex_page home_container">
<div className="modelRuntimeLib_page home_container">
<ProCard
style={{ padding: 0, margin: 0, backgroundColor: 'transparent' }}
bodyStyle={{ padding: 0, margin: 0, backgroundColor: 'transparent' }}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-08 16:57:30
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-24 16:58:44
* @LastEditTime: 2024-05-09 09:54:36
* @FilePath: \general-ai-manage\src\pages\Project\BusinessProject\components\businessCard.tsx
* @Description:
*/
@ -29,7 +29,6 @@ const AlgorithmCard: React.FC<AlgorithmCardProps> = ({ info }) => {
padding: 0,
borderRadius: 4,
boxShadow: 'inset 2px 2px 4px 0px #D8E8FF, inset -2px -2px 4px 0px #D8E8FF',
border: '1px solid #FFFFFF',
}}
bodyStyle={{ margin: 0, padding: 0 }}
@ -38,7 +37,7 @@ const AlgorithmCard: React.FC<AlgorithmCardProps> = ({ info }) => {
<div>
<div className="flex items-center mb-[12px] ">
<span
className="pr-[16px] head5 "
className="pr-[16px] head3 single_line w-[150px]"
style={{
color: token.colorPrimary,
}}
@ -61,12 +60,12 @@ const AlgorithmCard: React.FC<AlgorithmCardProps> = ({ info }) => {
<li className="flex items-center mb-[8px]">
<Image width={16} className="flex items-center" preview={false} src={icon1} />
<span className="pl-[8px]"> </span>
<span className="color_1">{info.version}</span>
<span className="text_color_1">{info.version}</span>
</li>
<li className="flex items-center">
<Image width={16} className="flex items-center" preview={false} src={icon2} />
<span className="pl-[8px]"> </span>
<span className="color_1">{info.industryName}</span>
<span className="text_color_1">{info.industryName}</span>
</li>
</ul>
</div>

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-23 17:00:00
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-28 09:33:34
* @LastEditTime: 2024-05-09 16:52:13
* @FilePath: \general-ai-platform-web\src\pages\Project\BusinessInfo\components\baseInfo.tsx
* @Description:
*
@ -45,7 +45,7 @@ const BaseInfo: React.FC<BaseInfoProps> = ({ info }) => {
},
];
return (
<div className="= gn_table_descriptions bg_active_1">
<div className="gn_active_descriptions bg_active_4">
<ProDescriptions column={4} columns={ModelDetailColumns} dataSource={info}></ProDescriptions>
</div>
);

@ -108,7 +108,7 @@ const BusinessInfo: React.FC = () => {
<div className="gn_head_card mb-[20px]">
<ProCard
className="gn_card pb-[16px]"
title={<span className="head5"></span>}
title={<span className="head3"></span>}
extra={
<Button
type="primary"
@ -125,8 +125,8 @@ const BusinessInfo: React.FC = () => {
{/* // TODO 替换使用公司的logo字段 */}
<YaxinshijueIcon></YaxinshijueIcon>
<div>
<span className="head5 ">{detailInfo?.name}</span>
<div className="color_2 py-[12px]">
<span className="head3 ">{detailInfo?.name}</span>
<div className="text_color_2 py-[12px]">
: {formatTimeByDateType(detailInfo?.create_time)}
</div>
</div>
@ -137,7 +137,7 @@ const BusinessInfo: React.FC = () => {
</div>
<div className="gn_head_card mb-[20px]">
<ProCard className="gn_card" title={<span className="head5"></span>}>
<ProCard className="gn_card" title={<span className="head3"></span>}>
<AccountPsw></AccountPsw>
</ProCard>
</div>
@ -145,7 +145,7 @@ const BusinessInfo: React.FC = () => {
<div className="gn_head_card mb-[20px]">
<ProCard
className="gn_card pb-[16px]"
title={<span className="head5">({total})</span>}
title={<span className="head3">({total})</span>}
>
<ProList<any>
className="gn"
@ -177,7 +177,7 @@ const BusinessInfo: React.FC = () => {
}}
showActions="hover"
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 2, xl: 3, xxl: 3 }}
grid={{ gutter: 16, xs: 1, md: 1, lg: 2, xl: 3, xxl: 4 }}
metas={{
type: {
// 不展示在筛选项

@ -0,0 +1,92 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-05-08 14:37:04
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-05-10 15:16:41
* @FilePath: \general-ai-platform-web\src\services\testApi\businessState.ts
* @Description: mock
*/
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 服务器状态分页列表 */
export async function getServerStateList(
body: Record<string, any>, //
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/business/serverState/list`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...body,
},
...(options || {}),
},
);
}
/** 服务器日志分页列表 */
export async function getServerStateLogList(
body: Record<string, any>, //
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/business/serverState/logList`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...body,
},
...(options || {}),
},
);
}
/** 设备状态分页列表 */
export async function getDeviceStateList(
body: Record<string, any>, //
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/business/deviceState/list`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...body,
},
...(options || {}),
},
);
}
/** 设备日志分页列表 */
export async function getDeviceStateLogList(
body: Record<string, any>, //
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/business/deviceState/logList`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...body,
},
...(options || {}),
},
);
}

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-04-25 15:39:42
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-04-28 17:14:06
* @LastEditTime: 2024-05-10 17:11:56
* @FilePath: \general-ai-platform-web\src\services\testApi\device.ts
* @Description: api
*/
@ -29,3 +29,20 @@ export async function getDeviceListByGroup(
},
);
}
/** 节点下设备分页列表 */
export async function getAllDeviceList(
body: Record<string, any>, //
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(`/api/device/allDevice`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...body,
},
...(options || {}),
});
}

8
types/index.d.ts vendored

@ -125,3 +125,11 @@ export namespace API {
currentAuthority: string;
};
}
export namespace DICTENUM {
export type DICT_TAB_ITEM = {
label: string;
key: number | string;
className?: string;
};
}

Loading…
Cancel
Save