feat: 算力分配模块调整完成

develop
donghao 11 months ago
parent 70dab765df
commit d6950afaea

@ -0,0 +1,34 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-01-25 13:34:56
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-03-11 13:55:06
* @FilePath: \general-ai-platform-web\mock\modelCategory.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
/**模型类别模块 mock */
import {
powerPoolsListData,
powerGroupListData,
} from './pools/computePowerData';
import { successMockApiProps } from './typing';
import { fetchMockSuccessFullByOther } from './utils/apiMock';
export default {
// 算力分配类别
'POST /api/v1/compute_power/getPowerGroupList': async (req: Request, res: Response) => {
const resData: successMockApiProps = {
...fetchMockSuccessFullByOther(powerGroupListData),
};
res.send(resData);
},
// 算力分配池
'POST /api/v1/compute_power/getPowerPoolsList': async (req: Request, res: Response) => {
const resData: successMockApiProps = {
...fetchMockSuccessFullByOther(powerPoolsListData),
};
res.send(resData);
},
};

@ -0,0 +1,122 @@
export type ComputePowerPoolItem = {
name: string;
type: number; // 类别
color?: string; //
proportion: number;
pretreatmentEfficiency?: number;
bgColor?: string;
};
const groupList: Record<string, any>[] = [
{
label: "NVIDIA GeForce 4090",
type: 1
},
{
label: "瑞芯微 RK3566",
type: 0
},
{
label: "瑞芯微 RK3566",
type: 0
},
{
label: "NVIDIA GeForce 4090",
type: 1
},
{
label: "NVIDIA GeForce 4090",
type: 1
}
];
const poolsData: ComputePowerPoolItem[] = [
{
name: "焊线颜色检测",
type: 9,
proportion: 7,
pretreatmentEfficiency: 20,
color: "#014BE6",
bgColor: "linear-gradient(180deg, #015DE6 0%, #4881F6 100%)"
},
{
name: "螺纹缺陷检测",
type: 8,
proportion: 8,
pretreatmentEfficiency: 20,
color: "#FAA90B",
bgColor: "linear-gradient(180deg, #E64601 0%, #F6A648 100%)"
},
{
name: "PIN间距测量",
type: 7,
proportion: 4,
pretreatmentEfficiency: 15,
color: "#EA1281",
bgColor: "linear-gradient(180deg, #E60161 0%, #F648E5 100%)"
},
{
name: "螺纹无牙缺陷检测",
type: 6,
proportion: 7,
pretreatmentEfficiency: 20,
color: "#FA8616",
bgColor: "linear-gradient(180deg, #FA8316 0%, #FAAD16 100%)"
},
{
name: "压板缺陷检测",
type: 5,
proportion: 32,
pretreatmentEfficiency: 38,
color: "#F9DB18",
bgColor: "linear-gradient(180deg, #FFC56F 0%, #F9E006 100%)"
},
{
name: "划伤缺陷检测",
type: 4,
proportion: 8,
pretreatmentEfficiency: 38,
color: "#1CCCFA",
bgColor: "linear-gradient(180deg, #6FFFFF 0%, #06BEF9 100%)"
},
{
name: "披锋(毛刺)缺陷检测",
type: 3,
proportion: 12,
pretreatmentEfficiency: 38,
color: "#9E26EE",
bgColor: "linear-gradient(180deg, #FF2494 0%, #8D27FF 100%)"
},
{
name: "工件尺寸测量",
type: 2,
proportion: 7,
pretreatmentEfficiency: 38,
color: "#6F50F6",
bgColor: "linear-gradient(180deg, #6B55F6 0%, #8C38F8 100%)"
},
{
name: "打孔不良检测",
type: 1,
proportion: 5,
pretreatmentEfficiency: 38,
color: "#24ED75",
bgColor: "linear-gradient(180deg, #43EA80 0%, #38F8D4 100%)"
},
{
name: "空闲算力",
type: 0,
proportion: 10,
pretreatmentEfficiency: 0,
color: "#DCDCDC",
bgColor: "linear-gradient(90deg, #7B7979 0%, #C1C1C1 100%)"
}
];
export const powerGroupListData = {
data: groupList
};
export const powerPoolsListData = {
data: poolsData
};

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.1 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,27 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 22C14.7614 22 17.2614 20.8807 19.0711 19.0711C20.8807 17.2614 22 14.7614 22 12C22 9.2386 20.8807 6.7386 19.0711 4.92893C17.2614 3.11929 14.7614 2 12 2C9.2386 2 6.7386 3.11929 4.92893 4.92893C3.11929 6.7386 2 9.2386 2 12C2 14.7614 3.11929 17.2614 4.92893 19.0711C6.7386 20.8807 9.2386 22 12 22Z"
stroke="#FAAD14"
stroke-width="2"
stroke-linejoin="round"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M12 18.5C12.6904 18.5 13.25 17.9404 13.25 17.25C13.25 16.5597 12.6904 16 12 16C11.3097 16 10.75 16.5597 10.75 17.25C10.75 17.9404 11.3097 18.5 12 18.5Z"
fill="#FAAD14"
/>
<path
d="M12 6V14"
stroke="#FAAD14"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>

After

Width:  |  Height:  |  Size: 869 B

@ -0,0 +1,24 @@
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M8.948 8.7975V7.3675C9.08911 7.35702 9.23051 7.35102 9.372 7.3495C13.294 7.2255 15.865 10.7235
15.865 10.7235C15.865 10.7235 13.091 14.5745 10.115 14.5745C9.72158 14.5753 9.33059 14.5128 8.957
14.3895V10.0435C10.485 10.2285 10.794 10.9005 11.704 12.4285L13.744 10.7145C13.744 10.7145 12.252
8.7625 9.744 8.7625C9.47818 8.75656 9.21227 8.76826 8.948 8.7975ZM8.948 4.0625V6.2005L9.372
6.1735C14.822 5.9885 18.382 10.6435 18.382 10.6435C18.382 10.6435 14.302 15.6075 10.052
15.6075C9.68491 15.6063 9.31858 15.5739 8.957 15.5105V16.8355C9.257 16.8705 9.567 16.8975 9.867
16.8975C13.824 16.8975 16.687 14.8745 19.46 12.4895C19.919 12.8605 21.8 13.7525 22.19 14.1415C19.557
16.3495 13.418 18.1255 9.937 18.1255C9.602 18.1255 9.284 18.1075 8.966
18.0725V19.9365H24V4.0625H8.948ZM8.948 14.3885V15.5195C5.291 14.8655 4.275 11.0595 4.275
11.0595C4.275 11.0595 6.033 9.1155 8.948 8.7975V10.0345H8.94C7.412 9.8485 6.21 11.2795 6.21
11.2795C6.21 11.2795 6.89 13.6915 8.949 14.3895M2.456 10.8995C2.456 10.8995 4.62 7.7025 8.956
7.3665V6.2005C4.153 6.5895 0 10.6525 0 10.6525C0 10.6525 2.35 17.4545 8.948 18.0725V16.8355C4.108
16.2355 2.456 10.8995 2.456 10.8995Z"
fill="#76B900"
/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1,168 @@
.pf-1 {
color: #333;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
/* 157.143% */
}
.pf-2 {
color: #666;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
}
.flex {
display: flex;
}
.justify-between {
justify-content: space-between;
}
.items-center {
align-items: center;
}
.flex-wrap {
flex-wrap: wrap;
}
.mr16px {
margin-right: 16px;
}
.mt16px {
margin-top: 16px;
}
.mb16px {
margin-bottom: 16px;
}
.px16px {
padding: 0 16px;
}
.pl8px {
padding-left: 8px;
}
.font-bold {
font-weight: 700;
}
.computePowerAllocation_body {
/* header */
/* banner */
/* footer */
}
.computePowerAllocation_body h3 {
font-weight: bold;
font-size: 16px;
color: #333333;
line-height: 19px;
}
.computePowerAllocation_body .head_info .bg_header_logo {
width: 80px;
height: 80px;
}
.computePowerAllocation_body .head_info .head_info_item {
margin-left: 12px;
}
.computePowerAllocation_body .banner_group {
padding-top: 24px;
}
.computePowerAllocation_body .banner_group > li {
width: 24%;
height: 88px;
background-color: rgba(255, 255, 255, 0.1);
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.1);
border-radius: 8px 8px 8px 8px;
position: relative;
overflow: hidden;
}
.computePowerAllocation_body .banner_group > li .cp_label {
width: 100%;
padding-left: 12px;
}
.computePowerAllocation_body .banner_group > li .cp_bg_logo_icon {
min-width: 24px;
height: 26px;
background: url('/images/computePowerAllocation/type1.svg') no-repeat 0 0;
}
.computePowerAllocation_body .banner_group > li .cp_bg_logo_icon_0 {
width: 44px;
height: 16px;
background: url('/images/computePowerAllocation/ruiyinweilogo1.svg') no-repeat 0 0;
}
.computePowerAllocation_body .banner_group > li .bg_banner_group_logo {
width: 100%;
height: 88px;
position: absolute;
background: url('/images/computePowerAllocation/guoqi.svg') no-repeat 100% 0%;
background-size: cover;
opacity: 0.1;
}
.computePowerAllocation_body .banner_group > li .bg_banner_group_logo_1 {
background: url('/images/computePowerAllocation/NVIDIA.svg') no-repeat 100% 0%;
}
.computePowerAllocation_body .computePower_footer li {
margin-right: 16px;
margin-bottom: 8px;
}
.computePowerCube_wrap {
position: relative;
overflow: hidden;
}
.computePowerCube_wrap .tip_icon {
width: 20px;
height: 20px;
background-size: cover;
}
.computePowerCube_wrap .bg_body_logo {
/* width: 358.886px;
height: 343.026px;
bottom: 0;
position: absolute;
left: -48px;
background: url("@/assets/computePower/bgLogo.svg") no-repeat 50% 50%;
opacity: 0.02; */
}
.computePowerCube_wrap .cube_info {
position: relative;
margin: 0 auto;
width: 100%;
border-radius: 2px;
/* background-color: red; */
border: 2px solid rgba(21, 77, 221, 0.4);
}
.computePowerCube_wrap .cube_info > li .bg_cube {
height: 100%;
position: relative;
}
.computePowerCube_wrap .cube_info_line {
position: absolute;
left: 18px;
bottom: 14px;
height: 4px;
width: calc(100% - 36px);
/* height: 401px; */
background: #ffffff;
filter: blur(4px);
}
.computePowerCube_wrap .cube_body {
/* margin-left: 30px; */
width: 100%;
border: 2px solid #b8b8b8;
border-radius: 6px;
}
.computePowerCube_wrap .bg_line {
height: 56px;
width: 2px;
background-color: black;
}
.computePowerType_wrap {
position: relative;
}
.computePowerType_wrap .bg_square_box {
padding-top: 6px;
padding-right: 8px;
}
.computePowerType_wrap .bg_square {
width: 12px;
height: 12px;
}

@ -0,0 +1,197 @@
@web_font1: #333;
@web_font2: #666;
.pf-1 {
color: @web_font1;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
/* 157.143% */
}
.pf-2 {
color: @web_font2;
font-family: "PingFang SC";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
}
.flex {
display: flex;
}
.justify-between{
justify-content: space-between;
}
.items-center{
align-items: center;
}
.flex-wrap{
flex-wrap: wrap
}
.mr16px{
margin-right: 16px
}
.mt16px{
margin-top: 16px
}
.mb16px{
margin-bottom: 16px
}
.px16px{
padding: 0 16px;
}
.pl8px{
padding-left: 8px;
}
.font-bold{
font-weight: 700;
}
.computePowerAllocation_body {
h3 {
font-weight: bold;
font-size: 16px;
color: #333333;
line-height: 19px;
}
/* header */
.head_info {
// font-size: 28px;
.bg_header_logo {
width: 80px;
height: 80px;
}
.head_info_item{
margin-left: 12px;
}
}
/* banner */
.banner_group {
padding-top: 24px;
& > li {
width: 24%;
height: 88px;
background-color: rgba(256, 256, 256, 0.1);
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.1);
border-radius: 8px 8px 8px 8px;
position: relative;
overflow: hidden;
.cp_label{
width: 100%;
padding-left: 12px;
}
.cp_bg_logo_icon {
min-width: 24px;
height: 26px;
background: url('/images/computePowerAllocation/type1.svg') no-repeat 0 0;
}
.cp_bg_logo_icon_0 {
width: 44px;
height: 16px;
background: url('/images/computePowerAllocation/ruiyinweilogo1.svg') no-repeat 0 0;
}
.bg_banner_group_logo {
width: 100%;
height: 88px;
position: absolute;
background: url('/images/computePowerAllocation/guoqi.svg') no-repeat 100% 0%;
background-size: cover;
opacity: 0.1;
}
.bg_banner_group_logo_1 {
background: url('/images/computePowerAllocation/NVIDIA.svg') no-repeat 100% 0%;
}
}
}
/* footer */
.computePower_footer{
li {
margin-right: 16px;
margin-bottom: 8px;
}
}
}
.computePowerCube_wrap {
position: relative;
overflow: hidden;
.tip_icon {
width: 20px;
height: 20px;
// background: url("@/assets/computePower/tipIcon.svg") no-repeat;
background-size: cover;
// tipIcon.svg
}
.bg_body_logo {
/* width: 358.886px;
height: 343.026px;
bottom: 0;
position: absolute;
left: -48px;
background: url("@/assets/computePower/bgLogo.svg") no-repeat 50% 50%;
opacity: 0.02; */
}
.cube_info {
position: relative;
margin: 0 auto;
width: 100%;
border-radius: 2px;
/* background-color: red; */
border: 2px solid rgba(21, 77, 221, 0.4);
& > li {
.bg_cube {
height: 100%;
position: relative;
}
}
}
.cube_info_line {
position: absolute;
left: 18px;
bottom: 14px;
height: 4px;
width: calc(100% - 36px);
/* height: 401px; */
background: rgba(255, 255, 255, 1);
filter: blur(4px);
}
.cube_body {
/* margin-left: 30px; */
width: 100%;
border: 2px solid #b8b8b8;
border-radius: 6px;
}
.bg_line{
height: 56px;
width: 2px;
background-color: black;
}
}
.computePowerType_wrap {
position: relative;
.bg_square_box{
padding-top: 6px;
padding-right: 8px;
}
.bg_square {
width: 12px;
height: 12px;
}
// .type_info{
// line-height: 1
// }
}

@ -1,361 +1,47 @@
/* eslint-disable eqeqeq */
/* eslint-disable react/no-unknown-property */
import { PageContainer, ProCard } from '@ant-design/pro-components';
import { Image } from 'antd';
import { fabric } from 'fabric';
import React, { useEffect, useRef, useState } from 'react';
import { Image, Button } from 'antd';
import React, { useEffect, useState } from 'react';
// type
import { ComputePowerPoolItem } from './typing';
import { postPowerGroup, postPowerPoolsList } from '@/services/system/ComputePower';
import './ComputePowerAllocation.less';
import ComputePowerType from "./components/computePowerType"
import ComputePowerCube from "./components/computePowerCube"
import UpdatePowerForm from "./components/updatePowerForm"
// TODO bug左侧
/**
* @
* @returns
*/
const ComputePowerAllocation: React.FC = () => {
const [poolsData, setPoolsData] = useState([]);
const [groupList, setGroupList] = useState([]);
const [showEdit, setShowEdit] = useState(false);
// state
const poolsData: ComputePowerPoolItem[] = [
{
name: '玩手机监控',
type: 0,
proportion: 39,
PretreatmentEfficiency: 15,
color: '#FAA90B',
},
{
name: '离岗监控',
type: 1,
proportion: 30,
PretreatmentEfficiency: 20,
color: '#3879FE',
},
{
name: '空闲算力',
type: 2,
proportion: 1,
PretreatmentEfficiency: 0,
},
];
async function fetchPowerData() {
const res = await postPowerPoolsList();
console.log('fetchPowerData_res', res);
setPoolsData(res.data);
}
/**子组件 */
// 参数信息项
const InfoPreview: React.FC<{
name: string;
des: string;
}> = ({ name, des }) => {
return (
<div
style={{
padding: 0,
margin: 0,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
minWidth: '13vw',
}}
>
<h6 style={{ color: '#333333', fontSize: 14, fontWeight: 700 }}>{name}</h6>
<div style={{ color: '#666666', fontSize: 14 }}>{des}</div>
</div>
);
};
async function fetchGroupData() {
const res = await postPowerGroup();
console.log('fetchGroupData_res', res);
setGroupList(res.data.splice(0, 4));
}
// 占比信息
const OccupyProportion: React.FC<{
pools: ComputePowerPoolItem[];
}> = ({ pools }) => {
const poolDefault = {
processBarOptions: {
top: 3, // 矩形左上角在y轴的位置
left: 0, // 矩形左上角在x轴的位置
height: 32, // 矩形的高
stroke: 'transparent', // 边框颜色
strokeWidth: 2, // 边框宽度
rx: 15, // 圆角的横向半径
ry: 15, // 圆角的纵向半径
selectable: false,
},
buttonBgOptions: {
width: 20,
height: 40,
fill: 'white', // 填充颜色
strokeWidth: 2, // 边框宽度
left: 0,
top: 0,
selectable: false,
hasControls: false,
},
buttonImageOptions: {
selectable: false,
hasControls: false,
},
buttonGroupOptions: {
width: 20,
height: 40,
top: 0,
lockMovementY: true,
hasControls: false,
// selectable: false,
},
};
const [clipPathData, setClipPathData] = useState({
width: 1000, // 宽
height: 80, // 高
});
const canvasRef = useRef(null);
const [cvs, setCanvas] = useState(null);
const [rect1Witdh, setRect1Witdh] = useState((pools[0].proportion / 100) * clipPathData.width);
const [rect2Witdh, setRect2Witdh] = useState((pools[1].proportion / 100) * clipPathData.width);
// 算力配置
function editComputePower() {
setShowEdit(true)
console.log(111, 'editComputePower')
}
useEffect(() => {
const canvasObject = new fabric.Canvas(canvasRef.current);
// 整个进度条 底色块
const rect0 = new fabric.Rect({
...poolDefault.processBarOptions,
width: clipPathData.width, // 矩形的宽
fill: '#E5E5E5', // 填充色
});
// 玩手机监控
const rect1 = new fabric.Rect({
...poolDefault.processBarOptions,
width: rect1Witdh, // 矩形的宽
fill: '#FAA90B', // 填充色
});
// 离岗监控
const rect2 = new fabric.Rect({
...poolDefault.processBarOptions,
left: rect1Witdh,
width: rect2Witdh, // 矩形的宽
fill: '#3879FE', // 填充色
});
// 创建矩形对象
const bgRect1 = new fabric.Rect(poolDefault.buttonBgOptions);
const bgRect2 = new fabric.Rect(poolDefault.buttonBgOptions);
// 添加背景图片到矩形
fabric.Image.fromURL('/images/computePowerAllocation/slideBtn1.png', function (img) {
// 设置图片的宽度和高度为矩形的宽度和高度
img.set({ width: bgRect1.width, height: bgRect1.height, ...poolDefault.buttonImageOptions });
// 将图片置于矩形的底部
// bgRect1.set({ originX: 'center', originY: 'center' });
canvasObject.add(
new fabric.Group([bgRect1, img], {
...poolDefault.buttonGroupOptions,
buttonId: '1',
left: rect1Witdh - 10,
}),
);
// 更新Canvas以应用更改
canvasObject.renderAll();
});
fabric.Image.fromURL('/images/computePowerAllocation/slideBtn2.png', function (img) {
// 设置图片的宽度和高度为矩形的宽度和高度
img.set({ width: bgRect2.width, height: bgRect2.height, ...poolDefault.buttonImageOptions });
// 将图片置于矩形的底部
// bgRect1.set({ originX: 'center', originY: 'center' });
canvasObject.add(
new fabric.Group([bgRect2, img], {
...poolDefault.buttonGroupOptions,
buttonId: '2',
left: rect1Witdh + rect2Witdh - 10,
}),
);
// 更新Canvas以应用更改
canvasObject.renderAll();
});
canvasObject.add(rect0);
canvasObject.add(rect1);
canvasObject.add(rect2);
canvasObject.on('object:moving', (event) => {
// 获取事件的目标对象
const targetObject = event.target;
console.log(targetObject.buttonId, 'targetObject', canvasObject.item(3));
// 算力按钮
switch (targetObject.buttonId) {
case '1':
// 算力按钮1
if (targetObject?.left >= clipPathData.width - 20) {
targetObject?.set({
left: clipPathData.width - 20,
});
}
if (targetObject?.left <= 0) {
targetObject?.set({
left: 0,
});
}
const currObject1Width = targetObject?.left + 10;
canvasObject.item(1).set({
width: currObject1Width,
});
canvasObject.item(2).set({
left: targetObject?.left + 10,
});
canvasObject.item(4).set({
left: canvasObject.item(2).left - 10 + canvasObject.item(2).width,
});
if (currObject1Width + canvasObject.item(2).width >= clipPathData.width) {
canvasObject.item(2).set({
width: clipPathData.width - currObject1Width,
});
canvasObject.item(4).set({
left: clipPathData.width - 20,
});
}
break;
case '2':
// 算力按钮2
if (targetObject?.left >= clipPathData.width - 20) {
targetObject?.set({
left: clipPathData.width - 20,
});
}
const currObject11Width = canvasObject.item(1).width;
const currObject22Width = canvasObject.item(2).width;
if(targetObject?.left <= currObject11Width+ 10){
targetObject?.set({
left: currObject11Width + 10,
});
}
// if (targetObject?.left <= rect1Witdh) {
// targetObject?.set({
// left: currObject11Width + currObject22Width,
// });
// }
console.log(currObject11Width, 'button2', currObject22Width)
canvasObject.item(2).set({
width: targetObject?.left - currObject11Width + 10,
});
// canvasObject.item(2).set({
// left: targetObject?.left + 10,
// });
// canvasObject.item(2).set({
// width: targetObject?.left -rect1Witdh + 10,
// });
break;
}
// set_category_fk_id_open(false);
// 检查目标对象是否为组合对象
setRect1Witdh(targetObject?.left);
canvasObject.renderAll();
});
canvasObject.renderAll();
setCanvas(canvasObject);
return () => {
canvasObject.dispose();
};
fetchGroupData();
fetchPowerData();
}, []);
return (
<div className="occupyProportion_box">
<div
className="occupy_up"
style={{ marginTop: 24, marginBottom: 20, padding: 0, position: 'relative', width: '100%' }}
>
<canvas ref={canvasRef} {...clipPathData} ></canvas>
{/* <ul
className="occupy_progress"
style={{
width: '100%',
height: 32,
backgroundColor: '#E5E5E5',
borderRadius: 16,
padding: 0,
overflow: 'hidden',
display: 'flex',
}}
>
{pools.map((item, index) => {
return (
<li
key={index}
style={{
height: 32,
width: `${item.proportion}%`,
padding: 0,
backgroundColor: item?.color || '#E5E5E5',
}}
></li>
);
})}
</ul>
<ul>
<li
style={{
position: 'absolute',
left: `calc(${pools[0].proportion - 0.8}% )`,
top: -4,
padding: 0,
width: 20,
}}
>
<Image
width={20}
src={'/images/computePowerAllocation/slideBtn1.png'}
preview={false}
></Image>
</li>
<li
style={{
position: 'absolute',
left: `${pools[0].proportion + pools[1].proportion - 0.8}%`,
top: -4,
width: 20,
}}
>
<Image
width={20}
src={'/images/computePowerAllocation/slideBtn2.png'}
preview={false}
></Image>
</li>
</ul> */}
</div>
<div className="occupy_des">
<ul
style={{
display: 'flex',
paddingLeft: 0,
paddingBottom: 24,
margin: 0,
}}
>
{pools.map((item, index) => {
return (
<li key={index} style={{ marginRight: 35 }}>
<span
style={{
width: 12,
height: 12,
display: 'inline-block',
background: item?.color || '#E5E5E5',
}}
></span>
<span style={{ paddingLeft: 8 }}>
{item.name}{item.proportion}%
</span>
{item.type != 2 ? (
<span style={{ paddingLeft: 8 }}>
<span style={{ fontWeight: 700 }}>{item.PretreatmentEfficiency} /</span>
</span>
) : (
<></>
)}
</li>
);
})}
</ul>
</div>
</div>
);
};
/**
* @
* @returns
*/
const ComputePowerAllocation: React.FC = () => {
return (
<PageContainer>
<ProCard
@ -363,8 +49,8 @@ const ComputePowerAllocation: React.FC = () => {
style={{ background: 'white' }}
headStyle={{ padding: 20, borderBottom: '1px solid #E0E0E0' }}
bodyStyle={{
paddingLeft: 9,
paddingRight: 9,
paddingLeft: 20,
paddingRight: 20,
paddingTop: 0,
paddingBottom: 0,
margin: 0,
@ -373,56 +59,70 @@ const ComputePowerAllocation: React.FC = () => {
wrap
ghost
>
{/* 参数信息 */}
<ProCard
gutter={24}
style={{ padding: 0, margin: 0 }}
bodyStyle={{
paddingTop: 24,
paddingBottom: 24,
paddingLeft: 0,
paddingRight: 0,
margin: 0,
display: 'flex',
alignItems: 'center',
borderBottom: '1px solid #E0E0E0',
}}
>
<Image
width={62}
src={'/images/computePowerAllocation/icon1.png'}
placeholder={
<Image preview={false} src={'/images/computePowerAllocation/icon1.png'} width={62} />
}
/>
<div
style={{
paddingLeft: 17,
paddingRight: 17,
margin: 0,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
}}
>
<InfoPreview name="苏胜天算力资源池" des="算力资源999Tops"></InfoPreview>
</div>
<InfoPreview
name="硬件组成"
des="NVIDIA GeForce 4090 | NVIDIA GeForce 4090 | NVIDIA GeForce 4090 |"
></InfoPreview>
</ProCard>
{/* 占比信息 */}
<ProCard
gutter={24}
style={{ padding: 0, margin: 0 }}
bodyStyle={{ padding: 0, margin: 0 }}
>
<OccupyProportion pools={poolsData as ComputePowerPoolItem[]} />
</ProCard>
<ul className="computePowerAllocation_body">
<li>
<div className="flex items-center head_info mt16px">
<div className="bg_header_logo">
<Image
width={80}
src={'/images/computePowerAllocation/banner.png'}
placeholder={
<Image
preview={false}
src={'/images/computePowerAllocation/banner.png'}
width={80}
/>
}
/>
</div>
<div className="head_info_item">
<h6 className="font-bold pf-1"></h6>
<p className="pf-2">999Tops</p>
</div>
</div>
</li>
<li className="mt16px">
<h3></h3>
{/* // TODO 重新设计*/}
<ul className="flex justify-between banner_group">
{groupList.map((v, k) => {
return (
<li key={k} className="flex items-center mb16px">
<div className="flex items-center px16px">
<div className={`cp_bg_logo_icon cp_bg_logo_icon_${v.type}`} />
<span className="cp_label pf-2 two-line">{v.label}</span>
</div>
<div className={`bg_banner_group_logo bg_banner_group_logo_${v.type}`} />
</li>
);
})}
</ul>
</li>
<li className="mt16px">
<h3></h3>
<div className="mt16px">
<ComputePowerCube list={poolsData} />
<ul className="flex flex-wrap items-center computePower_footer mt16px">
{poolsData.map((v, k) => {
return (
<li key={k} className="flex items-center justify-center">
<ComputePowerType info={v} />
</li>
);
})}
</ul>
</div>
<div>
<Button type="primary" onClick={editComputePower}></Button>
</div>
</li>
</ul>
</ProCard>
<UpdatePowerForm modalOpen={showEdit} poolsData={poolsData}></UpdatePowerForm>
</PageContainer>
);
};
export default ComputePowerAllocation;
export default ComputePowerAllocation;

@ -0,0 +1,428 @@
/* eslint-disable eqeqeq */
/* eslint-disable react/no-unknown-property */
import { PageContainer, ProCard } from '@ant-design/pro-components';
import { Image } from 'antd';
import { fabric } from 'fabric';
import React, { useEffect, useRef, useState } from 'react';
// type
import { ComputePowerPoolItem } from './typing';
// TODO bug左侧
// state
const poolsData: ComputePowerPoolItem[] = [
{
name: '玩手机监控',
type: 0,
proportion: 39,
PretreatmentEfficiency: 15,
color: '#FAA90B',
},
{
name: '离岗监控',
type: 1,
proportion: 30,
PretreatmentEfficiency: 20,
color: '#3879FE',
},
{
name: '空闲算力',
type: 2,
proportion: 1,
PretreatmentEfficiency: 0,
},
];
/**子组件 */
// 参数信息项
const InfoPreview: React.FC<{
name: string;
des: string;
}> = ({ name, des }) => {
return (
<div
style={{
padding: 0,
margin: 0,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
minWidth: '13vw',
}}
>
<h6 style={{ color: '#333333', fontSize: 14, fontWeight: 700 }}>{name}</h6>
<div style={{ color: '#666666', fontSize: 14 }}>{des}</div>
</div>
);
};
// 占比信息
const OccupyProportion: React.FC<{
pools: ComputePowerPoolItem[];
}> = ({ pools }) => {
const poolDefault = {
processBarOptions: {
top: 3, // 矩形左上角在y轴的位置
left: 0, // 矩形左上角在x轴的位置
height: 32, // 矩形的高
stroke: 'transparent', // 边框颜色
strokeWidth: 2, // 边框宽度
rx: 15, // 圆角的横向半径
ry: 15, // 圆角的纵向半径
selectable: false,
},
buttonBgOptions: {
width: 20,
height: 40,
fill: 'white', // 填充颜色
strokeWidth: 2, // 边框宽度
left: 0,
top: 0,
selectable: false,
hasControls: false,
},
buttonImageOptions: {
selectable: false,
hasControls: false,
},
buttonGroupOptions: {
width: 20,
height: 40,
top: 0,
lockMovementY: true,
hasControls: false,
// selectable: false,
},
};
const [clipPathData, setClipPathData] = useState({
width: 1000, // 宽
height: 80, // 高
});
const canvasRef = useRef(null);
const [cvs, setCanvas] = useState(null);
const [rect1Witdh, setRect1Witdh] = useState((pools[0].proportion / 100) * clipPathData.width);
const [rect2Witdh, setRect2Witdh] = useState((pools[1].proportion / 100) * clipPathData.width);
useEffect(() => {
const canvasObject = new fabric.Canvas(canvasRef.current);
// 整个进度条 底色块
const rect0 = new fabric.Rect({
...poolDefault.processBarOptions,
width: clipPathData.width, // 矩形的宽
fill: '#E5E5E5', // 填充色
});
// 玩手机监控
const rect1 = new fabric.Rect({
...poolDefault.processBarOptions,
width: rect1Witdh, // 矩形的宽
fill: '#FAA90B', // 填充色
});
// 离岗监控
const rect2 = new fabric.Rect({
...poolDefault.processBarOptions,
left: rect1Witdh,
width: rect2Witdh, // 矩形的宽
fill: '#3879FE', // 填充色
});
// 创建矩形对象
const bgRect1 = new fabric.Rect(poolDefault.buttonBgOptions);
const bgRect2 = new fabric.Rect(poolDefault.buttonBgOptions);
// 添加背景图片到矩形
fabric.Image.fromURL('/images/computePowerAllocation/slideBtn1.png', function (img) {
// 设置图片的宽度和高度为矩形的宽度和高度
img.set({ width: bgRect1.width, height: bgRect1.height, ...poolDefault.buttonImageOptions });
// 将图片置于矩形的底部
// bgRect1.set({ originX: 'center', originY: 'center' });
canvasObject.add(
new fabric.Group([bgRect1, img], {
...poolDefault.buttonGroupOptions,
buttonId: '1',
left: rect1Witdh - 10,
}),
);
// 更新Canvas以应用更改
canvasObject.renderAll();
});
fabric.Image.fromURL('/images/computePowerAllocation/slideBtn2.png', function (img) {
// 设置图片的宽度和高度为矩形的宽度和高度
img.set({ width: bgRect2.width, height: bgRect2.height, ...poolDefault.buttonImageOptions });
// 将图片置于矩形的底部
// bgRect1.set({ originX: 'center', originY: 'center' });
canvasObject.add(
new fabric.Group([bgRect2, img], {
...poolDefault.buttonGroupOptions,
buttonId: '2',
left: rect1Witdh + rect2Witdh - 10,
}),
);
// 更新Canvas以应用更改
canvasObject.renderAll();
});
canvasObject.add(rect0);
canvasObject.add(rect1);
canvasObject.add(rect2);
canvasObject.on('object:moving', (event) => {
// 获取事件的目标对象
const targetObject = event.target;
console.log(targetObject.buttonId, 'targetObject', canvasObject.item(3));
// 算力按钮
switch (targetObject.buttonId) {
case '1':
// 算力按钮1
if (targetObject?.left >= clipPathData.width - 20) {
targetObject?.set({
left: clipPathData.width - 20,
});
}
if (targetObject?.left <= 0) {
targetObject?.set({
left: 0,
});
}
const currObject1Width = targetObject?.left + 10;
canvasObject.item(1).set({
width: currObject1Width,
});
canvasObject.item(2).set({
left: targetObject?.left + 10,
});
canvasObject.item(4).set({
left: canvasObject.item(2).left - 10 + canvasObject.item(2).width,
});
if (currObject1Width + canvasObject.item(2).width >= clipPathData.width) {
canvasObject.item(2).set({
width: clipPathData.width - currObject1Width,
});
canvasObject.item(4).set({
left: clipPathData.width - 20,
});
}
break;
case '2':
// 算力按钮2
if (targetObject?.left >= clipPathData.width - 20) {
targetObject?.set({
left: clipPathData.width - 20,
});
}
const currObject11Width = canvasObject.item(1).width;
const currObject22Width = canvasObject.item(2).width;
if(targetObject?.left <= currObject11Width+ 10){
targetObject?.set({
left: currObject11Width + 10,
});
}
// if (targetObject?.left <= rect1Witdh) {
// targetObject?.set({
// left: currObject11Width + currObject22Width,
// });
// }
console.log(currObject11Width, 'button2', currObject22Width)
canvasObject.item(2).set({
width: targetObject?.left - currObject11Width + 10,
});
// canvasObject.item(2).set({
// left: targetObject?.left + 10,
// });
// canvasObject.item(2).set({
// width: targetObject?.left -rect1Witdh + 10,
// });
break;
}
// set_category_fk_id_open(false);
// 检查目标对象是否为组合对象
setRect1Witdh(targetObject?.left);
canvasObject.renderAll();
});
canvasObject.renderAll();
setCanvas(canvasObject);
return () => {
canvasObject.dispose();
};
}, []);
return (
<div className="occupyProportion_box">
<div
className="occupy_up"
style={{ marginTop: 24, marginBottom: 20, padding: 0, position: 'relative', width: '100%' }}
>
<canvas ref={canvasRef} {...clipPathData} ></canvas>
{/* <ul
className="occupy_progress"
style={{
width: '100%',
height: 32,
backgroundColor: '#E5E5E5',
borderRadius: 16,
padding: 0,
overflow: 'hidden',
display: 'flex',
}}
>
{pools.map((item, index) => {
return (
<li
key={index}
style={{
height: 32,
width: `${item.proportion}%`,
padding: 0,
backgroundColor: item?.color || '#E5E5E5',
}}
></li>
);
})}
</ul>
<ul>
<li
style={{
position: 'absolute',
left: `calc(${pools[0].proportion - 0.8}% )`,
top: -4,
padding: 0,
width: 20,
}}
>
<Image
width={20}
src={'/images/computePowerAllocation/slideBtn1.png'}
preview={false}
></Image>
</li>
<li
style={{
position: 'absolute',
left: `${pools[0].proportion + pools[1].proportion - 0.8}%`,
top: -4,
width: 20,
}}
>
<Image
width={20}
src={'/images/computePowerAllocation/slideBtn2.png'}
preview={false}
></Image>
</li>
</ul> */}
</div>
<div className="occupy_des">
<ul
style={{
display: 'flex',
paddingLeft: 0,
paddingBottom: 24,
margin: 0,
}}
>
{pools.map((item, index) => {
return (
<li key={index} style={{ marginRight: 35 }}>
<span
style={{
width: 12,
height: 12,
display: 'inline-block',
background: item?.color || '#E5E5E5',
}}
></span>
<span style={{ paddingLeft: 8 }}>
{item.name}{item.proportion}%
</span>
{item.type != 2 ? (
<span style={{ paddingLeft: 8 }}>
<span style={{ fontWeight: 700 }}>{item.PretreatmentEfficiency} /</span>
</span>
) : (
<></>
)}
</li>
);
})}
</ul>
</div>
</div>
);
};
/**
* @
* @returns
*/
const ComputePowerAllocation: React.FC = () => {
return (
<PageContainer>
<ProCard
title="算力资源池"
style={{ background: 'white' }}
headStyle={{ padding: 20, borderBottom: '1px solid #E0E0E0' }}
bodyStyle={{
paddingLeft: 9,
paddingRight: 9,
paddingTop: 0,
paddingBottom: 0,
margin: 0,
}}
gutter={24}
wrap
ghost
>
{/* 参数信息 */}
<ProCard
gutter={24}
style={{ padding: 0, margin: 0 }}
bodyStyle={{
paddingTop: 24,
paddingBottom: 24,
paddingLeft: 0,
paddingRight: 0,
margin: 0,
display: 'flex',
alignItems: 'center',
borderBottom: '1px solid #E0E0E0',
}}
>
<Image
width={62}
src={'/images/computePowerAllocation/icon1.png'}
placeholder={
<Image preview={false} src={'/images/computePowerAllocation/icon1.png'} width={62} />
}
/>
<div
style={{
paddingLeft: 17,
paddingRight: 17,
margin: 0,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
}}
>
<InfoPreview name="苏胜天算力资源池" des="算力资源999Tops"></InfoPreview>
</div>
<InfoPreview
name="硬件组成"
des="NVIDIA GeForce 4090 | NVIDIA GeForce 4090 | NVIDIA GeForce 4090 |"
></InfoPreview>
</ProCard>
{/* 占比信息 */}
<ProCard
gutter={24}
style={{ padding: 0, margin: 0 }}
bodyStyle={{ padding: 0, margin: 0 }}
>
<OccupyProportion pools={poolsData as ComputePowerPoolItem[]} />
</ProCard>
</ProCard>
</PageContainer>
);
};
export default ComputePowerAllocation;

@ -0,0 +1,62 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-11 16:48:04
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-03-12 11:00:14
* @FilePath: \general-ai-platform-web\src\pages\ComputePowerAllocation\components\computePowerCube.tsx
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import React, { useEffect, useRef, useState } from 'react';
import '../ComputePowerAllocation.less';
import { ComputePowerPoolItem } from '../typing';
export type ComputePowerCubeProps = {
// alarmStatusModalOpen: boolean;
// handleModal: () => void;
// values: Partial<API.DeviceCategory>;
list: ComputePowerPoolItem[];
};
const ComputePowerCube: React.FC<ComputePowerCubeProps> = (props) => {
const cubeBoxRefs = useRef(null);
const [listData, setListData] = useState([]);
useEffect(() => {
console.log(cubeBoxRefs.current.clientWidth, 'cubeBoxRefs');
let finalList = [];
const totalWidth = cubeBoxRefs.current?.clientWidth + 6 || 1062;
finalList = props.list.map((item) => {
item.value = Math.floor((item.proportion / 100) * totalWidth);
return item;
});
setListData(() => finalList.reverse());
}, [cubeBoxRefs, props.list]);
return (
<div className="computePowerCube_wrap">
<div className="flex justify-start des_wrap pb-[16px]">
<div className="tip_icon"></div>
<p className="tip_text">
</p>
</div>
<div className="cube_body">
<ul className="flex cube_info" ref={cubeBoxRefs}>
{listData.map((v, k) => {
return (
<li key={k} className="flex items-center justify-center">
<div className="bg_cube" style={{ width: v.value + 'px', background: v.bgColor }}>
{k !== 0 && <div className="bg_line"></div>}
</div>
</li>
);
})}
<li>
<div className="cube_info_line" />
</li>
</ul>
</div>
<div className="bg_body_logo"></div>
</div>
);
};
export default ComputePowerCube;

@ -0,0 +1,27 @@
import '../ComputePowerAllocation.less';
import { ComputePowerPoolItem } from '../typing';
export type ComputePowerTypeProps = {
// alarmStatusModalOpen: boolean;
// handleModal: () => void;
// values: Partial<API.DeviceCategory>;
info: ComputePowerPoolItem;
};
const ComputePowerType: React.FC<ComputePowerTypeProps> = (props) => {
return (
<div className="flex computePowerType_wrap">
<div className='bg_square_box'>
<div className="bg_square" style={{ background: props.info.bgColor }} />
</div>
<div className="flex type_info items-center">
<p className="pf-1">{props.info.name}</p>
<p className="pf-1">{props.info.proportion}%</p>
{!!props.info.pretreatmentEfficiency && (
<p className="pl8px pf-2">: {props.info.pretreatmentEfficiency}/</p>
)}
</div>
</div>
);
};
export default ComputePowerType;

@ -0,0 +1,77 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-07 14:01:13
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-03-12 16:29:48
* @FilePath: \general-ai-platform-web\src\pages\ComputePowerAllocation\components\updatePowerForm.tsx
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import type { ProDescriptionsActionType } from '@ant-design/pro-components';
import '../ComputePowerAllocation.less';
import { ProDescriptions } from '@ant-design/pro-components';
import { Modal } from 'antd';
import { useEffect, useRef, useState } from 'react';
export type UpdatePowerFormProps = {
modalOpen: boolean;
poolsData: Record<string, any>[];
};
const UpdatePowerForm: React.FC<UpdatePowerFormProps> = (props) => {
const actionRef = useRef<ProDescriptionsActionType>();
// const [state, setState] = useState<PicSearcherState>({
// loading: false,
// modalOpen: false,
// popoverVisible: false,
// icons: [],
// fileList: [],
// error: false,
// modelLoaded: false,
// });
const [formList, setFormList] = useState([]);
useEffect(() => {
setFormList(() => props.poolsData);
}, [props.poolsData]);
return (
<Modal width={761} title={'编辑算力配置'} open={props.modalOpen}>
<ProDescriptions
actionRef={actionRef}
editable={{
onSave: async (keypath, newInfo, oriInfo) => {
console.log(keypath, newInfo, oriInfo);
return true;
},
}}
>
{formList.map((item, index) => {
return (
<ProDescriptions.Item
key={index}
label={
<div className="flex items-center">
<span style={{ width: 12, height: 12, marginRight: 8, background: item.bgColor }}></span>
<span>{item.name}</span>
</div>
}
formItemProps={{
fieldId: index,
initialValue: item.proportion,
rules: [
{
required: true,
message: '此项为必填项',
},
],
}}
>
{item.proportion}
</ProDescriptions.Item>
);
})}
</ProDescriptions>
</Modal>
);
};
export default UpdatePowerForm;

@ -0,0 +1,41 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-03-11 14:06:18
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2024-03-11 14:15:11
* @FilePath: \general-ai-platform-web\src\services\system\ComputePower.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 算力分配类别 */
export async function postPowerGroup(
body: any,
options?: { [key: string]: any },
) {
return request<API.Response & { msg?: string }>(`/api/v1/compute_power/getPowerGroupList`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 算力分配类别 */
export async function postPowerPoolsList(
body: any,
options?: { [key: string]: any },
) {
return request<API.Response & { msg?: string }>(`/api/v1/compute_power/getPowerPoolsList`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
Loading…
Cancel
Save