feat: 页面更新

develop
JINGYJ 2 years ago
parent 4587d9bdda
commit 3347a16caa

@ -25,7 +25,8 @@ const include = [
const exclude = [
"@iconify-icons/ep",
"@iconify-icons/ri",
"@pureadmin/theme/dist/browser-utils"
"@pureadmin/theme/dist/browser-utils",
"@iconify-icons/ant-design"
];
export { include, exclude };

@ -35,51 +35,51 @@ import { MockMethod } from "vite-plugin-mock";
// ]
// };
const projectRouter = {
path: "/project",
meta: {
title: "项目管理",
icon: "lollipop",
rank: 11
},
children: [
{
path: "/project/list/index",
name: "ProjectList",
meta: {
title: "项目列表",
roles: ["admin", "common"]
}
},
{
path: "/project/details/index",
name: "ProjectDetails",
meta: {
title: "项目详情",
roles: ["admin", "common"]
}
}
]
};
// const projectRouter = {
// path: "/project",
// meta: {
// title: "项目管理",
// icon: "lollipop",
// rank: 11
// },
// children: [
// {
// path: "/project/list/index",
// name: "ProjectList",
// meta: {
// title: "项目列表",
// roles: ["admin", "common"]
// }
// },
// {
// path: "/project/details/index",
// name: "ProjectDetails",
// meta: {
// title: "项目详情",
// roles: ["admin", "common"]
// }
// }
// ]
// };
const modelRouter = {
path: "/aiModel",
meta: {
title: "模型管理",
icon: "lollipop",
rank: 12
},
children: [
{
path: "/aiModel",
name: "AiModelPage",
meta: {
title: "模型管理",
roles: ["admin", "common"]
}
}
]
};
// const modelRouter = {
// path: "/aiModel",
// meta: {
// title: "模型管理",
// icon: "lollipop",
// rank: 12
// },
// children: [
// {
// path: "/aiModel",
// name: "AiModelPage",
// meta: {
// title: "模型管理",
// roles: ["admin", "common"]
// }
// }
// ]
// };
// const deviceRouter = {
// path: "/device",
@ -100,38 +100,76 @@ const modelRouter = {
// ]
// };
const warningRouter = {
path: "/warning",
// const warningRouter = {
// path: "/warning",
// meta: {
// title: "告警管理",
// icon: "Alarm",
// rank: 14
// },
// children: [
// {
// path: "/warning/list/index",
// name: "WarningList",
// meta: {
// title: "告警列表",
// roles: ["admin", "common"]
// }
// }
// ]
// };
const enterpriseRouter = {
path: "/enterprise",
meta: {
title: "企业管理",
icon: "lollipop",
rank: 15
},
children: [
{
path: "/enterprise/index",
name: "EnterpriseList",
meta: {
title: "企业管理",
roles: ["admin", "common"]
}
}
]
};
const myAlgorithmRouter = {
path: "/myAlgorithm",
meta: {
title: "告警管理",
title: "我的算法库",
icon: "lollipop",
rank: 14
rank: 16
},
children: [
{
path: "/warning/list/index",
name: "WarningList",
path: "/myAlgorithm/index",
name: "myAlgorithm",
meta: {
title: "告警列表",
title: "我的算法库",
roles: ["admin", "common"]
}
}
]
};
const enterpriseRouter = {
path: "/enterprise",
const algorithmTestingRouter = {
path: "/algorithmTesting",
meta: {
title: "企业管理",
title: "算法实测",
icon: "lollipop",
rank: 15
rank: 16
},
children: [
{
path: "/enterprise/index",
name: "EnterpriseList",
path: "/algorithmTesting/index",
name: "algorithmTesting",
meta: {
title: "企业列表",
title: "算法实测",
roles: ["admin", "common"]
}
}
@ -145,7 +183,7 @@ export default [
response: () => {
return {
success: true,
data: [projectRouter, modelRouter, warningRouter, enterpriseRouter]
data: [enterpriseRouter, myAlgorithmRouter, algorithmTestingRouter]
};
}
}

@ -9,444 +9,443 @@ export default [
success: true,
data: {
list: [
{
index: 1,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "SSL证书",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 2,
isSetup: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "人脸识别",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 3,
isSetup: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 4,
isSetup: false,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "SSL证书",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 5,
isSetup: true,
type: 3,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "SSL证书",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 6,
isSetup: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "T-Sec 云防火墙",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 7,
isSetup: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "CVM",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 8,
isSetup: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "SSL证书",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 9,
isSetup: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "SSL证书",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 10,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 11,
isSetup: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "云数据库",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 12,
isSetup: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "SSL证书",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 13,
isSetup: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
name: "云数据库",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 14,
isSetup: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "SSL证书",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 15,
isSetup: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "云数据库",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 16,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "CVM",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 17,
isSetup: false,
type: 5,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "云数据库",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 18,
isSetup: false,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "云数据库",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 19,
isSetup: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 20,
isSetup: true,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "SSL证书",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 21,
isSetup: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "云数据库",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 22,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
name: "CVM",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 23,
isSetup: true,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "人脸识别",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 24,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "人脸识别",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 25,
isSetup: false,
type: 5,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "CVM",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 26,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "SSL证书",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 27,
isSetup: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 28,
isSetup: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "云数据库",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 29,
isSetup: false,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
name: "CVM",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 30,
isSetup: true,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 31,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "CVM",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 32,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "T-Sec 云防火墙",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 33,
isSetup: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "CVM",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 34,
isSetup: false,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "SSL证书",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 35,
isSetup: false,
type: 1,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "云数据库",
description:
"基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
},
{
index: 36,
isSetup: false,
type: 4,
banner:
"https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
name: "SSL证书",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 37,
isSetup: true,
type: 5,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "CVM",
description:
"云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
},
{
index: 38,
isSetup: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "云数据库",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 39,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "人脸识别",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 40,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "CVM",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 41,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "T-Sec 云防火墙",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 42,
isSetup: true,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "T-Sec 云防火墙",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 43,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
name: "SSL证书",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 44,
isSetup: true,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
name: "SSL证书",
description:
"云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
},
{
index: 45,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "T-Sec 云防火墙",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 46,
isSetup: true,
type: 2,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "SSL证书",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
},
{
index: 47,
isSetup: false,
type: 4,
banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
name: "SSL证书",
description:
"腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
},
{
index: 48,
isSetup: false,
type: 3,
banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
name: "T-Sec 云防火墙",
description:
"SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
}
// {
// index: 1,
// isSetup: true,
// type: 4,
// name: "项目一",
// leader: "张三",
// phone: 13888888888
// }
// {
// index: 2,
// isSetup: false,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "人脸识别",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 3,
// isSetup: false,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 4,
// isSetup: false,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "SSL证书",
// description:
// "云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
// },
// {
// index: 5,
// isSetup: true,
// type: 3,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "SSL证书",
// description:
// "云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
// },
// {
// index: 6,
// isSetup: true,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "T-Sec 云防火墙",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 7,
// isSetup: false,
// type: 1,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "CVM",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 8,
// isSetup: true,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "SSL证书",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 9,
// isSetup: false,
// type: 1,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "SSL证书",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 10,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
// },
// {
// index: 11,
// isSetup: true,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "云数据库",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 12,
// isSetup: true,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "SSL证书",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 13,
// isSetup: true,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
// name: "云数据库",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 14,
// isSetup: false,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "SSL证书",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 15,
// isSetup: true,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "云数据库",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 16,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "CVM",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 17,
// isSetup: false,
// type: 5,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "云数据库",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 18,
// isSetup: false,
// type: 4,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "云数据库",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 19,
// isSetup: true,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 20,
// isSetup: true,
// type: 4,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "SSL证书",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 21,
// isSetup: false,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "云数据库",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 22,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
// name: "CVM",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 23,
// isSetup: true,
// type: 1,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "人脸识别",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 24,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "人脸识别",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 25,
// isSetup: false,
// type: 5,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "CVM",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 26,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "SSL证书",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 27,
// isSetup: true,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 28,
// isSetup: false,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "云数据库",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 29,
// isSetup: false,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
// name: "CVM",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 30,
// isSetup: true,
// type: 1,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 31,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "CVM",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 32,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "T-Sec 云防火墙",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 33,
// isSetup: true,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "CVM",
// description:
// "云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
// },
// {
// index: 34,
// isSetup: false,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "SSL证书",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 35,
// isSetup: false,
// type: 1,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "云数据库",
// description:
// "基于腾讯优图强大的面部分析技术,提供包括人脸检测与分析、五官定位、人脸搜索、人脸比对、人脸"
// },
// {
// index: 36,
// isSetup: false,
// type: 4,
// banner:
// "https://tdesign.gtimg.com/tdesign-pro/face-recognition.jpg",
// name: "SSL证书",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 37,
// isSetup: true,
// type: 5,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "CVM",
// description:
// "云数据库MySQL为用户提供安全可靠性能卓越、易于维护的企业级云数据库服务。"
// },
// {
// index: 38,
// isSetup: false,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "云数据库",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 39,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "人脸识别",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 40,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "CVM",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 41,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "T-Sec 云防火墙",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 42,
// isSetup: true,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "T-Sec 云防火墙",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 43,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-db.jpg",
// name: "SSL证书",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 44,
// isSetup: true,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/t-sec.jpg",
// name: "SSL证书",
// description:
// "云硬盘为您提供用于CVM的持久性数据块级存储服务。云硬盘中的数据自动地可用区内以多副本冗"
// },
// {
// index: 45,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "T-Sec 云防火墙",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 46,
// isSetup: true,
// type: 2,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "SSL证书",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// },
// {
// index: 47,
// isSetup: false,
// type: 4,
// banner: "https://tdesign.gtimg.com/tdesign-pro/cloud-server.jpg",
// name: "SSL证书",
// description:
// "腾讯安全云防火墙产品是腾讯云安全团队结合云原生的优势自主研发的SaaS化防火墙产品无需客无需客无需客无需客无需客无需客无需客"
// },
// {
// index: 48,
// isSetup: false,
// type: 3,
// banner: "https://tdesign.gtimg.com/tdesign-pro/ssl.jpg",
// name: "T-Sec 云防火墙",
// description:
// "SSL证书又叫服务器证书腾讯云为您提供证书的一站式服务包括免费、付费证书的申请、管理及部"
// }
]
}
};

@ -56,6 +56,7 @@
"devDependencies": {
"@commitlint/cli": "^17.6.6",
"@commitlint/config-conventional": "^17.6.6",
"@iconify-icons/ant-design": "^1.2.7",
"@iconify-icons/ep": "^1.2.12",
"@iconify-icons/ri": "^1.2.9",
"@iconify/vue": "^4.1.1",

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 533 KiB

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.66675 8.33333C4.66675 6.4924 6.15915 5 8.00008 5C9.84101 5 11.3334 6.4924 11.3334 8.33333V13.6667H4.66675V8.33333Z" stroke="#333333" stroke-linejoin="round"/>
<path d="M8 1.66667V2.66667" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.9638 3.10941L11.321 3.87546" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14.073 6.76244L13.0881 6.9361" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.927 6.76247L2.91181 6.9361" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.03613 3.10934L4.67893 3.8754" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 13.6667H14.3333" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 893 B

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="2.5" width="11" height="9.28572" rx="1.5" stroke="#333333"/>
<path d="M4.57153 14H11.4287" stroke="#333333" stroke-linecap="round"/>
<path d="M7.07728 4.90192L8.92258 4.90192C9.10121 4.90192 9.26628 4.99722 9.35559 5.15192L10.2782 6.74999C10.3676 6.90469 10.3676 7.09529 10.2782 7.24999L9.35559 8.84807C9.26628 9.00277 9.10121 9.09807 8.92258 9.09807L7.07728 9.09807C6.89865 9.09807 6.73359 9.00277 6.64427 8.84807L5.72162 7.24999C5.6323 7.09529 5.6323 6.90469 5.72162 6.74999L6.64427 5.15192C6.73359 4.99722 6.89865 4.90192 7.07728 4.90192Z" stroke="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 682 B

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.66675 13.3333C2.66675 12 2.66675 4.33333 2.66675 4.33333C2.66675 3.22876 3.62188 2.33333 4.80008 2.33333H13.3334V12C13.3334 12 6.66058 12 4.80008 12C3.12083 12 2.66675 12.2281 2.66675 13.3333Z" stroke="#333333" stroke-linejoin="round"/>
<path d="M5 9L7.66667 6.33333L9 8.66667L11.6667 6" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.00008 14.6667H13.3334V12H4.00008C3.2637 12 2.66675 12.597 2.66675 13.3333C2.66675 14.0697 3.2637 14.6667 4.00008 14.6667Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 710 B

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.26175 2.65666L3.11758 5.10666C2.59258 5.51499 2.16675 6.38416 2.16675 7.04333V11.3658C2.16675 12.7192 3.26925 13.8275 4.62258 13.8275H11.3776C12.7309 13.8275 13.8334 12.7192 13.8334 11.3717V7.12499C13.8334 6.41916 13.3609 5.51499 12.7834 5.11249L9.17842 2.58666C8.36175 2.01499 7.04925 2.04416 6.26175 2.65666Z" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 11.4942V9.74417" stroke="#333333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 588 B

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 10.9382V5.6618C3 5.58747 3.07823 5.53912 3.14472 5.57236L6.94472 7.47236C6.9786 7.4893 7 7.52393 7 7.5618V12.8382C7 12.9125 6.92177 12.9609 6.85528 12.9276L3.05528 11.0276C3.0214 11.0107 3 10.9761 3 10.9382Z" stroke="#333333"/>
<path d="M13 10.9382V5.6618C13 5.58747 12.9218 5.53912 12.8553 5.57236L9.05528 7.47236C9.0214 7.4893 9 7.52393 9 7.5618V12.8382C9 12.9125 9.07823 12.9609 9.14472 12.9276L12.9447 11.0276C12.9786 11.0107 13 10.9761 13 10.9382Z" stroke="#333333"/>
<path d="M7.95939 2.01805L3.70561 3.90862C3.62643 3.94381 3.62643 4.05619 3.70561 4.09138L7.95939 5.98195C7.98524 5.99344 8.01476 5.99344 8.04061 5.98195L12.2944 4.09138C12.3736 4.05619 12.3736 3.94381 12.2944 3.90862L8.04061 2.01805C8.01476 2.00656 7.98524 2.00656 7.95939 2.01805Z" stroke="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 891 B

@ -0,0 +1,8 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4333 3H3.23325C2.7362 3 2.33325 3.40294 2.33325 3.9V12.9C2.33325 13.3971 2.7362 13.8 3.23325 13.8H13.4333C13.9303 13.8 14.3333 13.3971 14.3333 12.9V3.9C14.3333 3.40294 13.9303 3 13.4333 3Z" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2.33325 5.39999H14.3333" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.1333 8.39999H11.9333" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.1333 10.8H11.9333" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.73315 8.39999H5.33315" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.73315 10.8H5.33315" stroke="#1C0D82" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 869 B

@ -1,7 +1,7 @@
import type { App } from "vue";
import * as echarts from "echarts/core";
import { CanvasRenderer } from "echarts/renderers";
import { PieChart, BarChart, LineChart } from "echarts/charts";
import { PieChart, BarChart, LineChart, RadarChart } from "echarts/charts";
import {
GridComponent,
TitleComponent,
@ -19,6 +19,7 @@ use([
PieChart,
BarChart,
LineChart,
RadarChart,
CanvasRenderer,
GridComponent,
TitleComponent,

@ -0,0 +1,20 @@
import Alarm from "@/assets/svg/alarm.svg?component";
export default {
path: "/warning",
meta: {
title: "告警管理",
icon: Alarm,
rank: 14
},
children: [
{
path: "/warning/list/index",
name: "WarningList",
component: () => import("@/views/warning/list/index.vue"),
meta: {
title: "告警列表",
roles: ["admin", "common"]
}
}
]
} as RouteConfigsTable;

@ -1,13 +1,13 @@
const { VITE_HIDE_HOME } = import.meta.env;
const Layout = () => import("@/layout/index.vue");
import HomeFill from "@/assets/svg/home.svg?component";
export default {
path: "/",
name: "Home",
component: Layout,
redirect: "/welcome",
meta: {
icon: "homeFilled",
icon: HomeFill,
title: "首页",
rank: 0
},
@ -15,7 +15,7 @@ export default {
{
path: "/welcome",
name: "Welcome",
component: () => import("@/views/project/list/index.vue"),
component: () => import("@/views/welcome/index.vue"),
meta: {
title: "首页",
showLink: VITE_HIDE_HOME === "true" ? false : true

@ -0,0 +1,29 @@
import Project from "@/assets/svg/project.svg?component";
export default {
path: "/project",
meta: {
title: "项目管理",
icon: Project,
rank: 11
},
children: [
{
path: "/project/list/index",
name: "ProjectList",
component: () => import("@/views/project/list/index.vue"),
meta: {
title: "项目列表",
roles: ["admin", "common"]
}
},
{
path: "/project/details/index",
name: "ProjectDetails",
component: () => import("@/views/project/details/index.vue"),
meta: {
title: "项目详情",
roles: ["admin", "common"]
}
}
]
} as RouteConfigsTable;

@ -40,7 +40,7 @@ export default [
{
path: "/screen",
name: "Sereen",
component: () => import("@/views/error/404.vue"),
component: () => import("@/views/screen/index.vue"),
meta: {
title: "数据大屏",
roles: ["admin", "common"]

@ -38,4 +38,5 @@ export type setType = {
export type userType = {
username?: string;
roles?: Array<string>;
currentPage?: number;
};

@ -16,7 +16,9 @@ export const useUserStore = defineStore({
username:
storageSession().getItem<DataInfo<number>>(sessionKey)?.username ?? "",
// 页面级别权限
roles: storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? []
roles: storageSession().getItem<DataInfo<number>>(sessionKey)?.roles ?? [],
// 判断登录页面显示哪个组件0登录默认、1手机登录、2二维码登录、3注册、4忘记密码
currentPage: 0
}),
actions: {
/** 存储用户名 */
@ -27,6 +29,10 @@ export const useUserStore = defineStore({
SET_ROLES(roles: Array<string>) {
this.roles = roles;
},
/** 存储登录页面显示哪个组件 */
SET_CURRENTPAGE(value: number) {
this.currentPage = value;
},
/** 登入 */
async loginByUsername(data) {
return new Promise<UserResult>((resolve, reject) => {

@ -1,41 +1,89 @@
.wave {
position: fixed;
width: 100%;
height: 100%;
left: 0;
bottom: 0;
z-index: -1;
}
.logo-small {
position: fixed;
/* width: 100%;
height: 100%; */
left: 10%;
top: 5%;
}
.login-container {
width: 100vw;
height: 100vh;
display: grid;
/* display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 18rem;
padding: 0 2rem;
align-items: start; */
display: flex;
justify-content: center;
align-items: center;
/* padding: 0 2rem; */
/* justify-content: end; */
}
.img {
padding: 40px 0 33px;
width: 35%;
height: 60vh;
display: flex;
justify-content: flex-end;
/* justify-content: flex-end; */
flex-direction: column;
justify-content: space-between;
align-items: center;
width: 500px;
height: 380px;
background-image: url("../assets/login/login-bg.png");
background-repeat: no-repeat;
background-size: cover;
background-position: left center;
/* width: 500px; */
/* height: 380px; */
}
.img img {
width: 500px;
.describe {
/* margin: 32px 0 64px; */
/* width: 480px; */
/* font-family: PingFang SC; */
/* font-size: 48px; */
/* font-weight: 400; */
height: 54px;
/* letter-spacing: 0em; */
text-align: left;
font-family: Open Sans;
font-size: 40px;
font-weight: 700;
line-height: 54px;
color: #fff;
}
.platform-logo {
width: 464px;
height: 68px;
/* text-align: left; */
}
/* .img img {
width: 500px;
} */
.login-box {
padding: 25px 0 24px;
width: 45%;
height: 60vh;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
text-align: center;
background: rgb(255, 255, 255);
}
.login-form {
width: 360px;
margin-bottom: 130px;
width: 80%;
}
.avatar {
@ -46,8 +94,31 @@
.login-form h2 {
text-transform: uppercase;
margin: 15px 0;
/* color: #999;
font: bold 200% Consolas, Monaco, monospace; */
/* font-family: "PingFang SC";
font-size: 32px;
font-weight: 400;
line-height: 45px;
letter-spacing: 0em;
text-align: left; */
height: 45px;
font-family: PingFang SC;
font-size: 32px;
font-weight: bold;
line-height: 45px;
text-align: left;
color: #333;
}
.login-form-footer {
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0em;
color: #999;
font: bold 200% Consolas, Monaco, monospace;
text-align: left;
}
@media screen and (max-width: 1180px) {

@ -0,0 +1,11 @@
<script setup lang="ts">
defineOptions({
name: "AlgorithmTesting"
});
</script>
<template>
<div class="container">
<h1>算法实测</h1>
</div>
</template>

@ -43,7 +43,7 @@ const add = () => {
/>
</div>
</template>
<el-scrollbar max-height="400px">
<el-scrollbar max-height="1000px">
<p v-for="item in count" :key="item" class="scrollbar-demo-item">
{{ "电子有限公司" }}
</p>

@ -3,18 +3,19 @@ import Motion from "./utils/motion";
import { useRouter } from "vue-router";
import { message } from "@/utils/message";
import { loginRules } from "./utils/rule";
import { useNav } from "@/layout/hooks/useNav";
// import { useNav } from "@/layout/hooks/useNav";
import type { FormInstance } from "element-plus";
import { useLayout } from "@/layout/hooks/useLayout";
import { useUserStoreHook } from "@/store/modules/user";
import { initRouter, getTopMenu } from "@/router/utils";
import { bg, avatar, illustration } from "./utils/static";
import { bg, leftLogo, sst } from "./utils/static";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { ref, reactive, toRaw, onMounted, onBeforeUnmount } from "vue";
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
// import update from "./components/update.vue";
import { ref, reactive, onMounted, onBeforeUnmount } from "vue";
// import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import dayIcon from "@/assets/svg/day.svg?component";
import darkIcon from "@/assets/svg/dark.svg?component";
// import dayIcon from "@/assets/svg/day.svg?component";
// import darkIcon from "@/assets/svg/dark.svg?component";
import Lock from "@iconify-icons/ri/lock-fill";
import User from "@iconify-icons/ri/user-3-fill";
@ -24,13 +25,17 @@ defineOptions({
const router = useRouter();
const loading = ref(false);
const ruleFormRef = ref<FormInstance>();
const checked = ref(false);
// const currentPage = computed(() => {
// return useUserStoreHook().currentPage;
// });
const { initStorage } = useLayout();
initStorage();
const { dataTheme, dataThemeChange } = useDataThemeChange();
dataThemeChange();
const { title } = useNav();
// const { dataTheme, dataThemeChange } = useDataThemeChange();
// dataThemeChange();
// const { title } = useNav();
const ruleForm = reactive({
username: "admin",
@ -79,25 +84,31 @@ onBeforeUnmount(() => {
<template>
<div class="select-none">
<img :src="bg" class="wave" />
<div class="flex-c absolute right-5 top-3">
<!-- 主题 -->
<el-switch
<img :src="sst" class="logo-small" />
<!-- <div class="flex-c absolute right-5 top-3"> -->
<!-- 主题 -->
<!-- <el-switch
v-model="dataTheme"
inline-prompt
:active-icon="dayIcon"
:inactive-icon="darkIcon"
@change="dataThemeChange"
/>
</div>
/> -->
<!-- </div> -->
<div class="login-container">
<div class="img">
<!-- <div class="platform-logo">
<img :src="sst" />
</div> -->
<p class="describe">智能制造公共服务平台</p>
<img :src="leftLogo" />
<!-- <component :is="toRaw(illustration)" /> -->
</div>
<div class="login-box">
<div class="login-form">
<avatar class="avatar" />
<!-- <avatar class="avatar" /> -->
<Motion>
<h2 class="outline-none">{{ title }}</h2>
<h2 class="outline-none">{{ "欢迎登录" }}</h2>
</Motion>
<el-form
@ -137,19 +148,42 @@ onBeforeUnmount(() => {
/>
</el-form-item>
</Motion>
<Motion :delay="250">
<div class="w-full h-[20px] flex justify-between items-center">
<el-checkbox v-model="checked">
{{ "记住密码" }}
</el-checkbox>
<el-button
link
class="btn-color"
type="primary"
@click="useUserStoreHook().SET_CURRENTPAGE(4)"
>
{{ "忘记密码?" }}
</el-button>
</div>
<el-button
class="w-full mt-4"
class="w-full mt-7 login-btn"
size="default"
type="primary"
color="#1C0D82"
:loading="loading"
@click="onLogin(ruleFormRef)"
>
登录
</el-button>
<div class="w-full h-[60px] flex justify-center items-center">
<el-button link type="primary" text class="btn-color">
{{ "企业用户注册" }}
</el-button>
</div>
</Motion>
</el-form>
<!-- 忘记密码 -->
<!-- <update v-if="currentPage === 4" /> -->
</div>
<div class="login-form-footer">
{{ "Copyright2021-2022 xxxxxx All Rights Reserved" }}
</div>
</div>
</div>
@ -164,4 +198,24 @@ onBeforeUnmount(() => {
:deep(.el-input-group__append, .el-input-group__prepend) {
padding: 0;
}
.login-btn {
font-weight: 600;
// font-family: "PingFang SC";
color: #fff;
}
.btn-color {
color: #1c0d82;
}
.btn-color:hover {
color: #1c0d82;
opacity: 0.5;
}
// :deep(.el-button) {
// font-weight: bold;
// color: #fff;
// }
</style>

@ -1,5 +1,7 @@
import bg from "@/assets/login/bg.png";
import leftLogo from "@/assets/login/leftLogo.png";
import sst from "@/assets/login/sst.png";
import avatar from "@/assets/login/avatar.svg?component";
import illustration from "@/assets/login/illustration.svg?component";
export { bg, avatar, illustration };
export { bg, avatar, illustration, leftLogo, sst };

@ -0,0 +1,218 @@
<script setup lang="ts">
import { computed, PropType } from "vue";
import shopIcon from "@/assets/svg/shop.svg?component";
import laptopIcon from "@/assets/svg/laptop.svg?component";
import serviceIcon from "@/assets/svg/service.svg?component";
import calendarIcon from "@/assets/svg/calendar.svg?component";
import userAvatarIcon from "@/assets/svg/user_avatar.svg?component";
import More2Fill from "@iconify-icons/ri/more-2-fill";
defineOptions({
name: "ReCard"
});
interface CardProductType {
type: number;
isSetup: boolean;
description: string;
name: string;
}
const props = defineProps({
product: {
type: Object as PropType<CardProductType>
}
});
const emit = defineEmits(["manage-product", "delete-item", "product-detail"]);
const handleClickManage = (product: CardProductType) => {
emit("manage-product", product);
};
const handleClickDelete = (product: CardProductType) => {
emit("delete-item", product);
};
const handleClickDetail = (product: CardProductType) => {
emit("product-detail", product);
};
const cardClass = computed(() => [
"list-card-item",
{ "list-card-item__disabled": !props.product.isSetup }
]);
const cardLogoClass = computed(() => [
"list-card-item_detail--logo",
{ "list-card-item_detail--logo__disabled": !props.product.isSetup }
]);
const cardInfoClass = computed(() => [
"list-card-item_detail--info",
{ "list-card-item_detail--info__disabled": !props.product.isSetup }
]);
</script>
<template>
<div :class="cardClass">
<div
class="list-card-item_detail bg-bg_color"
@click="handleClickDetail(product)"
>
<el-row justify="space-between">
<el-col :span="8">
<div :class="cardLogoClass">
<shopIcon v-if="product.type === 1" />
<calendarIcon v-if="product.type === 2" />
<serviceIcon v-if="product.type === 3" />
<userAvatarIcon v-if="product.type === 4" />
<laptopIcon v-if="product.type === 5" />
</div>
</el-col>
<el-col :span="8">
<div :class="cardInfoClass">
<p class="list-card-item_detail--title text-text_color_primary">
{{ product.name }}
</p>
<div class="list-card-item_detail--content text-text_color_regular">
<!-- {{ product.description }} -->
<p>项目负责</p>
<p>联系方式</p>
<p>模型应用数</p>
<p>算力消耗</p>
</div>
</div>
</el-col>
<!-- <div :class="cardLogoClass">
<shopIcon v-if="product.type === 1" />
<calendarIcon v-if="product.type === 2" />
<serviceIcon v-if="product.type === 3" />
<userAvatarIcon v-if="product.type === 4" />
<laptopIcon v-if="product.type === 5" />
</div> -->
<div class="list-card-item_detail--operation" @click.stop>
<!-- <el-tag
:color="product.isSetup ? '#00a870' : '#eee'"
effect="dark"
class="mx-1 list-card-item_detail--operation--tag"
>
{{ product.isSetup ? "已启用" : "已停用" }}
</el-tag> -->
<el-dropdown trigger="click" :disabled="!product.isSetup">
<IconifyIconOffline :icon="More2Fill" class="text-[24px]" />
<template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup">
<el-dropdown-item @click="handleClickManage(product)">
修改
</el-dropdown-item>
<el-dropdown-item @click="handleClickDelete(product)">
删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-row>
<!-- <p class="list-card-item_detail--name text-text_color_primary">
{{ product.name }}
</p>
<p class="list-card-item_detail--desc text-text_color_regular">
{{ product.description }}
</p> -->
</div>
</div>
</template>
<style scoped lang="scss">
.list-card-item {
display: flex;
flex-direction: column;
margin-bottom: 12px;
overflow: hidden;
cursor: pointer;
border-radius: 3px;
&_detail {
flex: 1;
min-height: 140px;
padding: 24px 32px;
&--logo {
display: flex;
align-items: center;
justify-content: center;
width: 250px;
height: 150px;
font-size: 32px;
color: #0052d9;
background: #e0ebff;
// border-radius: 50%;
&__disabled {
color: #a1c4ff;
}
}
&--info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-evenly;
width: 200px;
height: 100%;
}
&--operation {
display: flex;
height: 100%;
&--tag {
border: 0;
}
}
&--name {
margin: 24px 0 8px;
font-size: 16px;
font-weight: 400;
}
&--title {
font-size: 24px;
font-weight: 400;
color: #a1c4ff;
}
&--content {
font-size: 16px;
font-weight: 400;
color: #000;
}
&--desc {
display: -webkit-box;
height: 40px;
margin-bottom: 24px;
overflow: hidden;
font-size: 12px;
line-height: 20px;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
&__disabled {
.list-card-item_detail--name,
.list-card-item_detail--title,
.list-card-item_detail--desc {
color: var(--el-text-color-disabled);
}
.list-card-item_detail--operation--tag {
color: #bababa;
}
}
}
</style>

@ -0,0 +1,163 @@
<script setup lang="ts">
import { ref, watch } from "vue";
import { message } from "@/utils/message";
import { FormInstance } from "element-plus";
// const SELECT_OPTIONS = [
// { label: "", value: 1 },
// { label: "", value: 2 },
// { label: "CVM", value: 3 },
// { label: "", value: 4 },
// { label: "", value: 5 }
// ];
const props = defineProps({
visible: {
type: Boolean,
default: false
},
data: {
type: Object,
default: () => {
return {};
}
}
});
const ruleFormRef = ref<FormInstance>();
const formVisible = ref(false);
const formData = ref(props.data);
// const textareaValue = ref("");
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate(valid => {
if (valid) {
message("提交成功", { type: "success" });
formVisible.value = false;
resetForm(formEl);
}
});
};
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
const closeDialog = () => {
formVisible.value = false;
resetForm(ruleFormRef.value);
};
const emit = defineEmits(["update:visible"]);
watch(
() => formVisible.value,
val => {
emit("update:visible", val);
}
);
watch(
() => props.visible,
val => {
formVisible.value = val;
}
);
watch(
() => props.data,
val => {
formData.value = val;
}
);
const rules = {
name: [{ required: true, message: "请输入产品名称", trigger: "blur" }]
};
</script>
<template>
<el-dialog
v-model="formVisible"
title="新建项目"
:width="680"
draggable
:before-close="closeDialog"
>
<!-- 表单内容 -->
<el-form
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="100px"
>
<el-form-item label="项目名称" prop="name">
<el-input
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请输入项目名称"
/>
</el-form-item>
<el-form-item label="项目负责人" prop="leader">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请输入项目负责人"
/>
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input
v-model="formData.phone"
:style="{ width: '480px' }"
placeholder="请输入联系方式"
/>
</el-form-item>
<!-- <el-form-item label="产品状态" prop="status">
<el-radio-group v-model="formData.status">
<el-radio label="0">已停用</el-radio>
<el-radio label="1">已启用</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="项目简介" prop="description">
<el-input
v-model="formData.description"
type="textarea"
:style="{ width: '480px' }"
placeholder="请输入项目简介"
/>
</el-form-item>
<!-- <el-form-item label="产品类型" prop="type">
<el-select
v-model="formData.type"
clearable
:style="{ width: '480px' }"
>
<el-option
v-for="(item, index) in SELECT_OPTIONS"
:key="index"
:value="item.value"
:label="item.label"
>
{{ item.label }}
</el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="mark">
<el-input
v-model="textareaValue"
type="textarea"
:style="{ width: '480px' }"
placeholder="请输入内容"
/>
</el-form-item> -->
</el-form>
<template #footer>
<el-button @click="closeDialog"></el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">
确定
</el-button>
</template>
</el-dialog>
</template>

@ -0,0 +1,208 @@
<script setup lang="ts">
import Card from "./components/Card.vue";
import { getCardList } from "@/api/list";
import { message } from "@/utils/message";
import { ElMessageBox } from "element-plus";
import { ref, onMounted, nextTick } from "vue";
import dialogForm from "./components/DialogForm.vue";
import { useRouter } from "vue-router";
import { isString } from "@pureadmin/utils";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
// import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import Search from "@iconify-icons/ep/search";
// import AddFill from "@iconify-icons/ri/add-circle-line";
defineOptions({
name: "MyAlgorithm"
});
const svg = `
<path class="path" d="
M 30 15
L 28 17
M 25.61 25.61
A 15 15, 0, 0, 1, 15 30
A 15 15, 0, 1, 1, 27.99 7.5
L 15 15
" style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
`;
const INITIAL_DATA = {
name: "",
status: "",
description: "",
type: "",
mark: "",
leader: "",
phone: ""
};
const pagination = ref({ current: 1, pageSize: 12, total: 0 });
const productList = ref([]);
const dataLoading = ref(true);
const getCardListData = async () => {
try {
const { data } = await getCardList();
productList.value = data.list;
pagination.value = {
...pagination.value,
total: data.list.length
};
} catch (e) {
console.log(e);
} finally {
setTimeout(() => {
dataLoading.value = false;
}, 500);
}
};
onMounted(() => {
getCardListData();
});
const formDialogVisible = ref(false);
const formData = ref({ ...INITIAL_DATA });
const searchValue = ref("");
const onPageSizeChange = (size: number) => {
pagination.value.pageSize = size;
pagination.value.current = 1;
};
const onCurrentChange = (current: number) => {
pagination.value.current = current;
};
const handleDeleteItem = product => {
ElMessageBox.confirm(
product
? `确认删除后${product.name}的所有产品信息将被清空, 且无法恢复`
: "",
"提示",
{
type: "warning"
}
)
.then(() => {
message("删除成功", { type: "success" });
})
.catch(() => {});
};
const handleManageProduct = product => {
formDialogVisible.value = true;
nextTick(() => {
formData.value = { ...product, status: product?.isSetup ? "1" : "0" };
});
};
const router = useRouter();
const handleProductDetail = product => {
Object.keys(product).forEach(param => {
if (!isString(product[param])) {
product[param] = product[param].toString();
}
});
//
useMultiTagsStoreHook().handleTags("push", {
path: `/project/details`,
name: "ProjectDetails",
query: product,
meta: {
title: `项目详情`,
showLink: false
}
});
router.push({ name: "ProjectDetails", query: product });
// formDialogVisible.value = true;
// nextTick(() => {
// formData.value = { ...product, status: product?.isSetup ? "1" : "0" };
// });
};
</script>
<template>
<div class="main">
<!-- <div class="w-full flex justify-between mb-4">
<el-button
:icon="useRenderIcon(AddFill)"
@click="formDialogVisible = true"
>
新建项目
</el-button>
<el-input
style="width: 300px"
v-model="searchValue"
placeholder="请输入项目名称"
clearable
v-if="false"
>
<template #suffix>
<el-icon class="el-input__icon">
<IconifyIconOffline
v-show="searchValue.length === 0"
:icon="Search"
/>
</el-icon>
</template>
</el-input>
</div> -->
<div
v-loading="dataLoading"
:element-loading-svg="svg"
element-loading-svg-view-box="-10, -10, 50, 50"
>
<el-empty
description="暂无数据"
v-show="
productList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.name.toLowerCase().includes(searchValue.toLowerCase())
).length === 0
"
/>
<template v-if="pagination.total > 0">
<el-row :gutter="16">
<el-col
v-for="(product, index) in productList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.name.toLowerCase().includes(searchValue.toLowerCase())
)"
:key="index"
:xs="48"
:sm="36"
:md="24"
:lg="12"
:xl="8"
>
<Card
:product="product"
@delete-item="handleDeleteItem"
@manage-product="handleManageProduct"
@product-detail="handleProductDetail"
/>
</el-col>
</el-row>
<el-pagination
class="float-right"
v-model:currentPage="pagination.current"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 24, 36]"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"
@current-change="onCurrentChange"
/>
</template>
</div>
<dialogForm v-model:visible="formDialogVisible" :data="formData" />
</div>
</template>

@ -22,6 +22,14 @@ const { setOptions, resize } = useECharts(barChartRef as Ref<HTMLDivElement>, {
setOptions(
{
title: {
text: "缺陷监测数据",
left: "left",
textStyle: {
fontSize: 14,
color: "#333"
}
},
tooltip: {
trigger: "axis",
axisPointer: {
@ -33,11 +41,12 @@ setOptions(
right: "30px",
left: "40px"
},
legend: {
//@ts-expect-error
right: true,
data: ["watchers", "fork", "star"]
},
// legend: {
// //@ts-expect-error
// right: true,
// // data: ["star"]
// // data: ["watchers", "fork", "star"]
// },
xAxis: [
{
type: "category",
@ -49,7 +58,7 @@ setOptions(
// width: "70",
// overflow: "truncate"
},
data: ["2021", "2022", "2023"],
data: ["10.15", "10.16", "10.17", "10.18", "10.19"],
triggerEvent: true
}
],
@ -108,30 +117,30 @@ setOptions(
{
name: "star",
type: "bar",
barWidth: "15%",
barWidth: "20%",
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#409EFF"
color: "#0F00B3"
},
{
offset: 1,
color: "#53a7ff"
color: "#0F00B3"
}
])
},
data: [1450, 3620, 7500]
data: [3620, 7500, 1450, 3620, 7500]
},
{
//线()
name: "总量",
type: "line",
yAxisIndex: 1,
data: [160, 246, 450],
data: [160, 246, 450, 160, 246],
itemStyle: {
//线
color: "#2A47F8"
color: "#FF7B01"
}
}
],

@ -0,0 +1,167 @@
<script setup lang="ts">
import { ref, computed, watch, type Ref } from "vue";
import { useAppStoreHook } from "@/store/modules/app";
import {
delay,
useDark,
useECharts,
type EchartOptions
} from "@pureadmin/utils";
import * as echarts from "echarts/core";
const { isDark } = useDark();
const theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const barChartRef = ref<HTMLDivElement | null>(null);
const { setOptions, resize } = useECharts(barChartRef as Ref<HTMLDivElement>, {
theme
});
setOptions(
{
title: {
text: "缺陷监测数据",
left: "left",
textStyle: {
fontSize: 14,
color: "#333"
}
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow"
}
},
grid: {
bottom: "20px",
right: "30px",
left: "40px"
},
// legend: {
// //@ts-expect-error
// right: true,
// // data: ["star"]
// // data: ["watchers", "fork", "star"]
// },
xAxis: [
{
type: "category",
axisTick: {
alignWithLabel: true
},
axisLabel: {
interval: 0
// width: "70",
// overflow: "truncate"
},
data: ["10.15", "10.16", "10.17", "10.18", "10.19"],
triggerEvent: true
}
],
yAxis: [
{
type: "value",
triggerEvent: true
},
{
type: "value",
splitLine: {
//线
show: false
},
triggerEvent: true
}
],
series: [
// {
// name: "watchers",
// type: "bar",
// barWidth: "10%",
// itemStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// {
// offset: 0,
// color: "#e6a23c"
// },
// {
// offset: 1,
// color: "#eebe77"
// }
// ])
// },
// data: [200, 320, 800]
// },
// {
// name: "fork",
// type: "bar",
// barWidth: "15%",
// itemStyle: {
// color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
// {
// offset: 0,
// color: "#f56c6c"
// },
// {
// offset: 1,
// color: "#f89898"
// }
// ])
// },
// data: [1600, 2460, 4500]
// },
{
name: "star",
type: "bar",
barWidth: "20%",
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "#F7B303"
},
{
offset: 1,
color: "#F7B303"
}
])
},
data: [3620, 7500, 1450, 3620, 7500]
},
{
//线()
name: "总量",
type: "line",
yAxisIndex: 1,
data: [160, 246, 450, 160, 246],
itemStyle: {
//线
color: "#0246F6"
}
}
],
addTooltip: true
},
{
name: "click",
callback: params => {
console.log("click", params);
}
}
);
watch(
() => useAppStoreHook().getSidebarStatus,
() => {
delay(600).then(() => resize());
}
);
</script>
<template>
<div ref="barChartRef" style="width: 100%; height: 35vh" />
</template>

@ -3,6 +3,7 @@ import { ref, watch } from "vue";
import { message } from "@/utils/message";
import { FormInstance } from "element-plus";
import ReCol from "@/components/ReCol";
import logon from "@/assets/static/logo_icon.png";
// const SELECT_OPTIONS = [
// { label: "", value: 1 },
@ -33,64 +34,64 @@ const title = ref("添加检查项模型");
const activeStep = ref(0);
// const textareaValue = ref("");
const tableData = [
{
date: "2016-05-03",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-02",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-04",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-01",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-08",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-06",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
},
{
date: "2016-05-07",
name: "Tom",
state: "California",
city: "Los Angeles",
address: "No. 189, Grove St, Los Angeles",
zip: "CA 90036"
}
];
// const tableData = [
// {
// date: "2016-05-03",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-02",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-04",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-01",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-08",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-06",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// },
// {
// date: "2016-05-07",
// name: "Tom",
// state: "California",
// city: "Los Angeles",
// address: "No. 189, Grove St, Los Angeles",
// zip: "CA 90036"
// }
// ];
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
@ -118,6 +119,8 @@ const nextStep = () => {
if (activeStep.value++ > 2) activeStep.value = 0;
};
const checked = ref(false);
const emit = defineEmits(["update:visible"]);
watch(
() => formVisible.value,
@ -149,11 +152,12 @@ const rules = {
<el-dialog
v-model="formVisible"
:title="title"
:width="1080"
class="project-dialog"
:width="560"
draggable
:before-close="closeDialog"
>
<el-row :gutter="30" class="mb-12">
<el-row :gutter="30" class="mb-5">
<re-col :value="30" :xs="24" :sm="24">
<el-steps
:space="200"
@ -161,9 +165,8 @@ const rules = {
finish-status="success"
simple
>
<el-step title="选择模型" />
<el-step title="选择算力" />
<el-step title="支付" />
<el-step title="算法配置" />
<el-step title="告警配置" />
</el-steps>
</re-col>
</el-row>
@ -172,40 +175,63 @@ const rules = {
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="100px"
label-position="top"
label-width="160px"
v-if="activeStep == 0"
>
<el-row :gutter="30">
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="检测方向" prop="name">
<el-input
<re-col :value="18" :xs="24" :sm="24">
<el-form-item label="输入源" prop="name">
<el-select
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请选择检测方向"
/>
placeholder="请选择输入源"
:style="{ width: '100%' }"
>
<el-option label="Zone one" value="shanghai" />
<el-option label="Zone two" value="beijing" />
</el-select>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="检测类型" prop="leader">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请选择检测类型"
/>
</el-form-item>
<re-col :value="6" :xs="24" :sm="24">
<el-image
preview-teleported
loading="lazy"
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"
:preview-src-list="[
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
]"
:initial-index="1"
fit="cover"
/>
</re-col>
<re-col>
<el-table :data="tableData" style="width: 100%" height="300" border>
<el-table-column type="selection" width="55" />
<el-table-column prop="date" label="Date" width="150" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="state" label="State" />
<el-table-column prop="city" label="City" />
<el-table-column prop="address" label="Address" />
<el-table-column prop="zip" label="Zip" />
</el-table>
<re-col :value="24" :xs="24" :sm="24">
<el-form-item label="选择算法" class="flex flex-wrap">
<div class="algorithm-card">
<div class="algorithm-card-header">
<img :src="logon" />
<el-checkbox v-model="checked" fill="#1C0D82" size="large" />
</div>
<div class="algorithm-card-content">
<div class="algorithm-card-content-title">
<span class="algorithm-card-content-title-left">{{
"苏胜天文字OCR识别模型"
}}</span>
<span class="algorithm-card-content-title-right">{{
"经典算法"
}}</span>
</div>
<div class="algorithm-card-content-version">
{{ "v1.6.25" }}
</div>
<div class="algorithm-card-content-update">
更新时间<span>{{ "2023.09.10" }}</span>
</div>
<div class="algorithm-card-content-version">
提供方<span>{{ "v1.6.25" }}</span>
</div>
</div>
</div>
</el-form-item>
</re-col>
</el-row>
</el-form>
@ -213,82 +239,173 @@ const rules = {
ref="ruleFormRef"
:model="formData"
:rules="rules"
label-width="160px"
label-position="top"
v-if="activeStep == 1"
>
<el-row :gutter="30">
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择算力资源" prop="name">
<el-input
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请选择检测方向"
/>
<re-col :value="24" :xs="24" :sm="24">
<el-form-item label="平台警告" prop="name">
<el-input v-model="formData.name" placeholder="请选择检测方向" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择购买时间" prop="leader">
<re-col :value="24" :xs="24" :sm="24">
<el-form-item label="短信通知" prop="leader" class="flex">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请选择检测类型"
:style="{ width: '95%', 'margin-right': 'auto' }"
placeholder="请输入手机号"
/>
<el-checkbox v-model="checked" fill="#1C0D82" size="large" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择GPU数量" prop="name">
<re-col :value="24" :xs="24" :sm="24">
<el-form-item
label="设备警告"
prop="leader"
class="flex form-item-style"
>
<el-input
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请选择检测方向"
v-model="formData.leader"
:style="{ width: '95%', 'margin-right': 'auto' }"
placeholder="请输入HTTP调用地址"
/>
<el-checkbox v-model="checked" fill="#1C0D82" size="large" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择GPU数量" prop="leader">
<el-form-item prop="leader" class="flex form-item-style">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请选择检测类型"
:style="{ width: '95%', 'margin-right': 'auto' }"
placeholder="请输入HTTP调用地址"
/>
<el-checkbox v-model="checked" fill="#1C0D82" size="large" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择内存数量GB" prop="name">
<el-form-item prop="leader" class="flex form-item-style">
<el-input
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请选择检测方向"
v-model="formData.leader"
:style="{ width: '95%', 'margin-right': 'auto' }"
placeholder="请输入HTTP调用地址"
/>
<el-checkbox v-model="checked" fill="#1C0D82" size="large" />
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="选择节点数量" prop="leader">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请选择检测类型"
/>
</el-form-item>
<re-col>
<!-- <el-table :data="tableData" style="width: 100%" height="300" border>
<el-table-column type="selection" width="55" />
<el-table-column prop="date" label="Date" width="150" />
<el-table-column prop="name" label="Name" />
<el-table-column prop="state" label="State" />
<el-table-column prop="city" label="City" />
<el-table-column prop="address" label="Address" />
<el-table-column prop="zip" label="Zip" />
</el-table> -->
</re-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="closeDialog"></el-button>
<el-button @click="nextStep" v-if="activeStep < 2"></el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">
<el-button @click="closeDialog" class="btn-color" v-if="activeStep == 1"
>取消</el-button
>
<el-button @click="nextStep" class="btn-color" v-if="activeStep < 1"
>下一步</el-button
>
<el-button
type="primary"
color="#1C0D82"
@click="submitForm(ruleFormRef)"
>
确定
</el-button>
</div>
</template>
</el-dialog>
</template>
<style scoped lang="scss">
.dialog-footer {
text-align: center;
<style lang="scss">
.project-dialog {
border-radius: 8px;
.el-dialog__header {
margin-right: 0;
border-bottom: 1px solid #e0e0e0;
}
.form-item-style {
margin-bottom: 10px;
}
.btn-color:hover {
color: #fff;
background-color: #1c0d82;
opacity: 0.25;
}
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: #1c0d82 !important;
border-color: #1c0d82 !important;
}
.algorithm-card {
box-sizing: border-box;
width: 250px;
height: 160px;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
.algorithm-card-header {
display: flex;
align-items: center;
justify-content: space-between;
.el-checkbox__inner {
border-radius: 50%;
}
}
.algorithm-card-content {
.algorithm-card-content-title {
display: flex;
align-items: center;
height: 28px;
.algorithm-card-content-title-left {
margin-right: 8px;
// font-family: "PingFang SC";
font-size: 14px;
font-weight: 400;
color: #333;
}
.algorithm-card-content-title-right {
width: 56px;
height: 28px;
// font-family: "PingFang SC";
font-size: 12px;
font-weight: 400;
line-height: 28px;
color: #fff;
text-align: center;
background: #67c23a;
border-radius: 2px;
}
}
}
.algorithm-card-content-version {
// font-family: "PingFang SC";
font-size: 12px;
font-weight: 400;
color: #666;
}
&:nth-of-type(odd) {
margin-right: 10px;
}
}
</style>

@ -1,6 +1,8 @@
<script setup lang="ts">
import { ref } from "vue";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import BarDetail from "./BarDetail.vue";
import Radar from "./Radar.vue";
import AddFill from "@iconify-icons/ri/add-circle-line";
defineOptions({
@ -13,21 +15,29 @@ defineOptions({
// description: string;
// name: string;
// }
const modelStep = ref(1);
// const modelStep = ref(1);
const props = defineProps({
modelInfo: {
type: Object
}
});
console.log(props);
const loading = ref(true);
setTimeout(() => {
loading.value = !loading.value;
}, 800);
</script>
<template>
<div>
<div class="list-item">
<div class="list-item-header mb-[18px]">
<span class="font-bold">{{ "苏胜天OCR文字识别模型" }}</span>
<span>{{ "算力设备:" }}</span>
<span class="font-bold"
>{{ "苏胜天OCR文字识别模型" }}<i>v1.6.25</i>
</span>
<!-- <span>{{ "算力设备:" }}</span> -->
<span>
<el-button
type="primary"
@ -43,52 +53,89 @@ console.log(props);
text
>模型设置</el-button
>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
class="button"
text
>告警设置</el-button
>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
class="button"
text
>算法配置</el-button
>
</span>
</div>
<div class="list-item-content">
<div class="list-item-content-left">
<div class="list-item-content-left-progress">
<el-progress
type="circle"
stroke-linecap="butt"
:stroke-width="10"
:width="80"
:percentage="0"
<div class="list-item-content-box">
<el-skeleton animated :loading="loading">
<template #default>
<BarDetail style="width: 100%; height: 240px" />
</template>
</el-skeleton>
</div>
<div class="list-item-content-box">
<el-skeleton animated :loading="loading">
<template #default>
<Radar style="width: 100%; height: 240px" />
</template>
</el-skeleton>
</div>
<div class="list-item-content-box-pic">
<div class="list-item-content-box-top">
<el-image
preview-teleported
loading="lazy"
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"
:preview-src-list="[
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
]"
:initial-index="1"
fit="cover"
class="w-[100px] h-[100px]"
/>
<p>{{ "GPU占用" }}</p>
</div>
<div class="list-item-content-left-progress">
<el-progress
type="circle"
stroke-linecap="butt"
:stroke-width="10"
:width="80"
:percentage="30"
<el-image
preview-teleported
loading="lazy"
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"
:preview-src-list="[
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
]"
:initial-index="1"
fit="cover"
class="w-[100px] h-[100px]"
/>
<p>{{ "GPU占用" }}</p>
</div>
<div class="list-item-content-left-progress">
<el-progress
type="circle"
stroke-linecap="butt"
:stroke-width="10"
:width="80"
:percentage="60"
<el-image
preview-teleported
loading="lazy"
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"
:preview-src-list="[
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg'
]"
:initial-index="1"
fit="cover"
class="w-[100px] h-[100px]"
/>
<p>{{ "GPU占用" }}</p>
</div>
<div class="list-item-content-left-progress">
<el-progress
type="circle"
stroke-linecap="butt"
:stroke-width="10"
:width="80"
:percentage="80"
/>
<p>{{ "GPU占用" }}</p>
</div>
</div>
<div class="list-item-content-right">
<!-- <div class="list-item-content-left">
<div class="list-item-content-left-bottom">
<el-skeleton animated :loading="loading">
<template #default>
<Bar style="width: 240px; height: 240px" />
</template>
</el-skeleton>
<el-skeleton animated :loading="loading">
<template #default>
<Radar style="width: 240px; height: 240px" />
</template>
</el-skeleton>
</div>
</div> -->
<!-- <div class="list-item-content-right">
<div class="list-item-content-right-first" v-if="modelStep == 1">
<el-button
size="large"
@ -203,7 +250,7 @@ console.log(props);
/>
</div>
</div>
</div>
</div> -->
</div>
</div>
</div>
@ -213,10 +260,10 @@ console.log(props);
.list-item {
display: flex;
flex-direction: column;
height: 300px;
// height: 300px;
padding: 10px;
margin-bottom: 10px;
background: #fafafa;
// background: #fafafa;
}
// .list-item + .list-item {
// margin-top: 10px;
@ -234,8 +281,18 @@ console.log(props);
.list-item .list-item-content .list-item-content-left {
display: flex;
flex-wrap: wrap;
width: 500px;
flex-direction: column;
width: 60%;
}
.list-item
.list-item-content
.list-item-content-left
.list-item-content-left-top {
display: flex;
justify-content: center;
// flex-wrap: wrap;
width: 100%;
margin-right: 50px;
}
@ -246,6 +303,17 @@ console.log(props);
flex: 50%;
}
.list-item
.list-item-content
.list-item-content-left
.list-item-content-left-bottom {
display: flex;
justify-content: space-around;
// flex-wrap: wrap;
width: 100%;
margin-right: 50px;
}
.list-item .list-item-content .list-item-content-right {
display: flex;
flex: 1;
@ -302,4 +370,27 @@ console.log(props);
align-items: center;
justify-content: space-around;
}
.list-item .list-item-content .list-item-content-box,
.list-item .list-item-content .list-item-content-box-pic {
box-sizing: border-box;
flex: 1;
height: 260px;
padding: 16px;
background: #f2f6ff;
}
.list-item .list-item-content .list-item-content-box:nth-of-type(2) {
margin: 0 16px;
}
.list-item
.list-item-content
.list-item-content-box
.list-item-content-box-pic
.list-item-content-box-top {
display: flex;
align-items: center;
justify-content: space-between;
}
</style>

@ -0,0 +1,100 @@
<script setup lang="ts">
import { ref, computed, watch, type Ref } from "vue";
import { useAppStoreHook } from "@/store/modules/app";
import {
delay,
useDark,
useECharts,
type EchartOptions
} from "@pureadmin/utils";
const { isDark } = useDark();
const theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const pieChartRef = ref<HTMLDivElement | null>(null);
const { setOptions, resize } = useECharts(pieChartRef as Ref<HTMLDivElement>, {
theme
});
setOptions(
{
title: {
text: "算力占用",
left: "left",
textStyle: {
fontSize: 14,
color: "#333"
}
},
tooltip: {
trigger: "item"
},
legend: {
icon: "rect",
// orient: "vertical",
align: "auto",
bottom: "0",
// top: "40%",
// right: "15%",
// itemGap: 18,
textStyle: {
fontSize: 12,
color: "#333"
}
// right: true
},
series: [
{
name: "算力占用",
type: "pie",
center: ["50%", "50%"],
radius: ["30%", "55%"],
color: ["#6217DE", "#FF4444"],
itemStyle: {
borderColor: "#fff",
borderWidth: 1
},
data: [
{ value: 1600, name: "已占用" },
{ value: 400, name: "未占用" }
]
// emphasis: {
// itemStyle: {
// shadowBlur: 10,
// shadowOffsetX: 0,
// shadowColor: "rgba(0, 0, 0, 0.5)"
// }
// }
}
]
},
{
name: "click",
callback: params => {
console.log("click", params);
}
},
//
{
type: "zrender",
name: "click",
callback: params => {
console.log("点击空白处", params);
}
}
);
watch(
() => useAppStoreHook().getSidebarStatus,
() => {
delay(600).then(() => resize());
}
);
</script>
<template>
<div ref="pieChartRef" style="width: 100%; height: 35vh" />
</template>

@ -0,0 +1,109 @@
<script setup lang="ts">
import { ref, computed, watch, type Ref } from "vue";
import { useAppStoreHook } from "@/store/modules/app";
import {
delay,
useDark,
useECharts,
type EchartOptions
} from "@pureadmin/utils";
// import * as echarts from "echarts/core";
const { isDark } = useDark();
const theme: EchartOptions["theme"] = computed(() => {
return isDark.value ? "dark" : "light";
});
const radarChartRef = ref<HTMLDivElement | null>(null);
const { setOptions, resize } = useECharts(
radarChartRef as Ref<HTMLDivElement>,
{
theme
}
);
const dataMax = ref([
{ name: "类型A", max: 15 },
{ name: "类型B", max: 15 },
{ name: "类型C", max: 15 },
{ name: "类型D", max: 15 },
{ name: "类型E", max: 15 }
]);
setOptions(
{
title: {
text: "缺陷类型",
left: "left",
textStyle: {
fontSize: 14,
color: "#333"
}
},
tooltip: {
trigger: "item"
},
radar: {
center: ["50%", "50%"], //
radius: 70, //
//
indicator: dataMax.value,
shape: "polygon", //, circle:,polygon:()
splitArea: {
areaStyle: {
//
color: ["#f2f6ff"]
}
},
axisLine: {
show: false
}
},
series: [
{
type: "radar",
label: {
show: false //
},
// areaStyle: {}, //
itemStyle: {
//线
color: "#FF7B3D"
},
lineStyle: {
//线
color: "#FF7B3D"
},
symbolSize: 4, //
symbol: "circle", //
data: [
{
name: "类型A",
value: [5, 6, 7, 8, 9]
},
{
name: "类型B",
value: [9, 8, 7, 6, 5]
}
]
}
]
},
{
name: "click",
callback: params => {
console.log("click", params);
}
}
);
watch(
() => useAppStoreHook().getSidebarStatus,
() => {
delay(600).then(() => resize());
}
);
</script>
<template>
<div ref="radarChartRef" style="width: 100%; height: 35vh" />
</template>

@ -4,10 +4,13 @@ import { isEmpty } from "@pureadmin/utils";
import { ref, onMounted, computed } from "vue";
import { useWindowSize } from "@vueuse/core";
import { useRoute } from "vue-router";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import ModelCard from "./components/ModelCard.vue";
import Bar from "./components/Bar.vue";
import AddFill from "@iconify-icons/ri/add-circle-line";
import Pie from "./components/Pie.vue";
// import AddFill from "@iconify-icons/ri/add-circle-line";
import { Back } from "@element-plus/icons-vue";
import emptyPic from "@/assets/static/project_empty.png";
defineOptions({
name: "ProjectDetails"
});
@ -26,10 +29,10 @@ const INITIAL_DATA = {
const formDialogVisible = ref(false);
const formData = ref({ ...INITIAL_DATA });
const { height } = useWindowSize();
const count = ref(5);
const count = ref(2);
const echartsLoading = ref(true);
const loading = ref(false);
const noMore = computed(() => count.value >= 10);
const noMore = computed(() => count.value >= 5);
const disabled = computed(() => loading.value || noMore.value);
const load = () => {
loading.value = true;
@ -49,57 +52,74 @@ onMounted(() => {
<template>
<div class="main">
<div class="w-full flex justify-between mb-4">
<el-button :icon="Back" key="项目详情" text class="btn-style"
>项目详情</el-button
>
</div>
<el-row :gutter="24">
<el-col :value="24" :xs="24" :sm="24" class="mb-[18px]">
<el-card shadow="always">
<el-card shadow="never">
<template #header>
<div>
<span class="font-bold">项目信息</span>
</div>
</template>
<div class="flex align-baseline justify-around">
<div class="flex flex-col justify-around">
<span>项目名称{{ "文字识别" }}</span>
<span>负责人{{ "识别线主管" }}</span>
<span>联系方式{{ "13811111111" }}</span>
<div class="flex justify-stretch">
<span class="mr-4">项目名称{{ "文字识别" }}</span>
<span class="mr-4">负责人{{ "识别线主管" }}</span>
<span class="mr-4">联系方式{{ "13811111111" }}</span>
</div>
<div class="project-info">
<div class="project-info-box">
<el-skeleton animated :loading="echartsLoading">
<template #default>
<Pie style="width: 100%; height: 240px" />
</template>
</el-skeleton>
</div>
<div>
<el-progress
type="circle"
stroke-linecap="butt"
:stroke-width="30"
:percentage="80"
/>
<p>{{ "GPU占用" }}</p>
<div class="project-info-box">
<el-skeleton animated :loading="echartsLoading">
<template #default>
<Bar style="width: 100%; height: 240px" />
</template>
</el-skeleton>
</div>
<el-skeleton animated :loading="echartsLoading">
<template #default>
<Bar style="width: 240px; height: 240px" />
</template>
</el-skeleton>
</div>
</el-card>
</el-col>
<el-col :value="24" :xs="24" :sm="24">
<el-card
shadow="always"
:style="{ height: `calc(${height}px - 30vh - 100px)` }"
shadow="never"
:style="{ height: `calc(${height}px - 35vh - 100px)` }"
>
<template #header>
<div class="flex justify-between">
<span class="font-bold">模型列表</span>
<span class="font-bold">算法应用</span>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
class="button"
color="#1C0D82"
@click="formDialogVisible = true"
>新建模型</el-button
>新建算法应用</el-button
>
</div>
</template>
<el-empty
description="暂未添加任何项目"
:image="emptyPic"
v-show="count < 1"
>
<el-button
type="primary"
color="#1C0D82"
@click="formDialogVisible = true"
>
新建算法应用
</el-button>
</el-empty>
<el-scrollbar
class="infinite-list-wrapper"
:height="`calc(${height}px - 35vh - 150px)`"
:height="`calc(${height}px - 35vh - 200px)`"
>
<div
v-infinite-scroll="load"
@ -124,4 +144,47 @@ onMounted(() => {
// height: 720px;
text-align: center;
}
.btn-style {
// font-family: "PingFang SC";
font-size: 20px;
font-weight: 400;
color: #333;
&:hover {
color: #333;
opacity: 0.5;
}
}
.row-bg {
margin-right: 0 !important;
margin-left: 0 !important;
}
.col-bg {
background: #f2f6ff;
}
.project-info {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.project-info-box {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
padding: 20px;
margin-right: 16px;
background: #f2f6ff;
border-radius: 4px;
&:last-child {
margin-right: 0;
}
}
}
</style>

@ -1,11 +1,8 @@
<script setup lang="ts">
import { computed, PropType } from "vue";
import shopIcon from "@/assets/svg/shop.svg?component";
import laptopIcon from "@/assets/svg/laptop.svg?component";
import serviceIcon from "@/assets/svg/service.svg?component";
import calendarIcon from "@/assets/svg/calendar.svg?component";
import userAvatarIcon from "@/assets/svg/user_avatar.svg?component";
import More2Fill from "@iconify-icons/ri/more-2-fill";
// import MoreFilled from "@iconify-icons/ant-design/ellipsis-outlined";
import cover from "@/assets/static/cover.png";
import { MoreFilled } from "@element-plus/icons-vue";
defineOptions({
name: "ReCard"
@ -14,8 +11,10 @@ defineOptions({
interface CardProductType {
type: number;
isSetup: boolean;
description: string;
leader: string;
name: string;
phone: number;
modelNum: number;
}
const props = defineProps({
@ -47,11 +46,6 @@ const cardLogoClass = computed(() => [
"list-card-item_detail--logo",
{ "list-card-item_detail--logo__disabled": !props.product.isSetup }
]);
const cardInfoClass = computed(() => [
"list-card-item_detail--info",
{ "list-card-item_detail--info__disabled": !props.product.isSetup }
]);
</script>
<template>
@ -60,66 +54,45 @@ const cardInfoClass = computed(() => [
class="list-card-item_detail bg-bg_color"
@click="handleClickDetail(product)"
>
<el-row justify="space-between">
<el-col :span="8">
<div :class="cardLogoClass">
<shopIcon v-if="product.type === 1" />
<calendarIcon v-if="product.type === 2" />
<serviceIcon v-if="product.type === 3" />
<userAvatarIcon v-if="product.type === 4" />
<laptopIcon v-if="product.type === 5" />
</div>
</el-col>
<el-col :span="8">
<div :class="cardInfoClass">
<p class="list-card-item_detail--title text-text_color_primary">
{{ product.name }}
</p>
<div class="list-card-item_detail--content text-text_color_regular">
<!-- {{ product.description }} -->
<p>项目负责</p>
<p>联系方式</p>
<p>模型应用数</p>
<p>算力消耗</p>
</div>
<div :class="cardLogoClass">
<img :src="cover" class="bg" />
</div>
<div class="list-card-item_content">
<el-row justify="space-between">
<p class="list-card-item_detail--name text-text_color_primary">
{{ product.name }}
</p>
<div class="list-card-item_detail--operation" @click.stop>
<el-dropdown
trigger="click"
:disabled="false"
popper-class="dropDownStyle"
>
<!-- <IconifyIconOffline :icon="MoreFilled" class="text-[24px]" /> -->
<el-icon :size="16"><MoreFilled /></el-icon>
<template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup">
<el-dropdown-item @click="handleClickManage(product)">
编辑项目
</el-dropdown-item>
<el-dropdown-item @click="handleClickDelete(product)">
删除项目
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-col>
<!-- <div :class="cardLogoClass">
<shopIcon v-if="product.type === 1" />
<calendarIcon v-if="product.type === 2" />
<serviceIcon v-if="product.type === 3" />
<userAvatarIcon v-if="product.type === 4" />
<laptopIcon v-if="product.type === 5" />
</div> -->
<div class="list-card-item_detail--operation" @click.stop>
<!-- <el-tag
:color="product.isSetup ? '#00a870' : '#eee'"
effect="dark"
class="mx-1 list-card-item_detail--operation--tag"
>
{{ product.isSetup ? "已启用" : "已停用" }}
</el-tag> -->
<el-dropdown trigger="click" :disabled="!product.isSetup">
<IconifyIconOffline :icon="More2Fill" class="text-[24px]" />
<template #dropdown>
<el-dropdown-menu :disabled="!product.isSetup">
<el-dropdown-item @click="handleClickManage(product)">
修改
</el-dropdown-item>
<el-dropdown-item @click="handleClickDelete(product)">
删除
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-row>
<!-- <p class="list-card-item_detail--name text-text_color_primary">
{{ product.name }}
</p>
<p class="list-card-item_detail--desc text-text_color_regular">
{{ product.description }}
</p> -->
</el-row>
<p class="list-card-item_detail--desc">
项目负责人{{ product.leader }}
</p>
<p class="list-card-item_detail--desc text-text_color_regular">
联系方式{{ product.phone }}
</p>
<p class="list-card-item_detail--desc text-text_color_regular">
模型应用数{{ product.modelNum }}
</p>
</div>
</div>
</div>
</template>
@ -131,38 +104,28 @@ const cardInfoClass = computed(() => [
margin-bottom: 12px;
overflow: hidden;
cursor: pointer;
border: 1px solid #e0e0e0;
border-radius: 3px;
&_content {
padding: 16px 16px 8px;
}
&_detail {
flex: 1;
min-height: 140px;
padding: 24px 32px;
&--logo {
display: flex;
align-items: center;
justify-content: center;
width: 250px;
height: 150px;
font-size: 32px;
color: #0052d9;
background: #e0ebff;
// border-radius: 50%;
width: 100%;
&__disabled {
color: #a1c4ff;
}
}
&--info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-evenly;
width: 200px;
height: 100%;
}
&--operation {
display: flex;
height: 100%;
@ -173,46 +136,33 @@ const cardInfoClass = computed(() => [
}
&--name {
margin: 24px 0 8px;
font-size: 16px;
font-weight: 400;
}
&--title {
font-size: 24px;
font-weight: 400;
color: #a1c4ff;
}
&--content {
margin-bottom: 8px;
font-size: 16px;
font-weight: 400;
color: #000;
// font-family: "PingFang SC";
color: #333;
}
&--desc {
display: -webkit-box;
height: 40px;
margin-bottom: 24px;
overflow: hidden;
font-size: 12px;
line-height: 20px;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
margin-bottom: 8px;
font-size: 14px;
font-weight: 400;
line-height: 22px;
// font-family: "Roboto";
color: #666;
}
}
&__disabled {
.list-card-item_detail--name,
.list-card-item_detail--title,
.list-card-item_detail--desc {
color: var(--el-text-color-disabled);
}
// &__disabled {
// .list-card-item_detail--name,
// .list-card-item_detail--desc {
// // color: var(--el-text-color-disabled);
// }
.list-card-item_detail--operation--tag {
color: #bababa;
}
}
// .list-card-item_detail--operation--tag {
// // color: #bababa;
// }
// }
}
</style>

@ -34,9 +34,13 @@ const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate(valid => {
if (valid) {
const data = formData;
console.log(data);
message("提交成功", { type: "success" });
emit("submit-form", data);
formVisible.value = false;
resetForm(formEl);
formData.value = {};
}
});
};
@ -51,7 +55,7 @@ const closeDialog = () => {
resetForm(ruleFormRef.value);
};
const emit = defineEmits(["update:visible"]);
const emit = defineEmits(["update:visible", "submit-form"]);
watch(
() => formVisible.value,
val => {
@ -74,7 +78,7 @@ watch(
);
const rules = {
name: [{ required: true, message: "请输入产品名称", trigger: "blur" }]
name: [{ required: true, message: "请输入项目名称", trigger: "blur" }]
};
</script>
@ -82,37 +86,28 @@ const rules = {
<el-dialog
v-model="formVisible"
title="新建项目"
:width="680"
draggable
:width="560"
class="project-dialog"
append-to-body
style="border-radius: 8px"
:before-close="closeDialog"
>
<!-- 表单内容 -->
<el-form
ref="ruleFormRef"
:model="formData"
label-position="top"
:rules="rules"
label-width="100px"
>
<el-form-item label="项目名称" prop="name">
<el-input
v-model="formData.name"
:style="{ width: '480px' }"
placeholder="请输入项目名称"
/>
<el-input v-model="formData.name" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="项目负责人" prop="leader">
<el-input
v-model="formData.leader"
:style="{ width: '480px' }"
placeholder="请输入项目负责人"
/>
<el-input v-model="formData.leader" placeholder="请输入项目负责人" />
</el-form-item>
<el-form-item label="联系方式" prop="phone">
<el-input
v-model="formData.phone"
:style="{ width: '480px' }"
placeholder="请输入联系方式"
/>
<el-input v-model="formData.phone" placeholder="请输入联系方式" />
</el-form-item>
<!-- <el-form-item label="产品状态" prop="status">
<el-radio-group v-model="formData.status">
@ -120,14 +115,14 @@ const rules = {
<el-radio label="1">已启用</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="项目简介" prop="description">
<!-- <el-form-item label="项目简介" prop="description">
<el-input
v-model="formData.description"
type="textarea"
:style="{ width: '480px' }"
placeholder="请输入项目简介"
/>
</el-form-item>
</el-form-item> -->
<!-- <el-form-item label="产品类型" prop="type">
<el-select
v-model="formData.type"
@ -154,10 +149,35 @@ const rules = {
</el-form-item> -->
</el-form>
<template #footer>
<el-button @click="closeDialog"></el-button>
<el-button type="primary" @click="submitForm(ruleFormRef)">
<el-button class="btn-color" @click="closeDialog"></el-button>
<el-button
type="primary"
color="#1C0D82"
@click="submitForm(ruleFormRef)"
>
确定
</el-button>
</template>
</el-dialog>
</template>
<style lang="scss">
// :deep(.el-dialog, .is-draggable, .el-dialog__header) {
// border-bottom: 1px solid #eee !important;
// }
.project-dialog {
.el-dialog__header {
margin-right: 0;
border-bottom: 1px solid #e0e0e0;
}
.el-dialog__body {
padding: 30px 24px;
}
.btn-color:hover {
color: #fff;
background-color: #1c0d82;
opacity: 0.25;
}
}
</style>

@ -3,14 +3,16 @@ import Card from "./components/Card.vue";
import { getCardList } from "@/api/list";
import { message } from "@/utils/message";
import { ElMessageBox } from "element-plus";
import { ref, onMounted, nextTick } from "vue";
import { ref, onMounted, nextTick, markRaw } from "vue";
import dialogForm from "./components/DialogForm.vue";
import { useRouter } from "vue-router";
import { isString } from "@pureadmin/utils";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
// import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Search from "@iconify-icons/ep/search";
import AddFill from "@iconify-icons/ri/add-circle-line";
// import AddFill from "@iconify-icons/ri/add-circle-line";
import emptyPic from "@/assets/static/project_empty.png";
import { QuestionFilled } from "@element-plus/icons-vue";
defineOptions({
name: "ProjectList"
@ -76,15 +78,25 @@ const onCurrentChange = (current: number) => {
};
const handleDeleteItem = product => {
ElMessageBox.confirm(
product
? `确认删除后${product.name}的所有产品信息将被清空, 且无法恢复`
: "",
"提示",
product ? `确定删除这个项目吗,删除后将无法找回,请谨慎操作` : "",
"确定删除这个项目吗?",
{
type: "warning"
showClose: false,
type: "warning",
icon: markRaw(QuestionFilled),
customClass: "msg-box-style",
confirmButtonClass: "btn-custom-confirm",
cancelButtonClass: "btn-custom-cancel"
}
)
.then(() => {
productList.value.forEach((item, index) => {
console.log(item.type);
if (item.type == product.type) {
productList.value.splice(index, 1);
}
});
pagination.value.total = productList.value.length;
message("删除成功", { type: "success" });
})
.catch(() => {});
@ -113,19 +125,35 @@ const handleProductDetail = product => {
}
});
router.push({ name: "ProjectDetails", query: product });
// formDialogVisible.value = true;
// nextTick(() => {
// formData.value = { ...product, status: product?.isSetup ? "1" : "0" };
// });
};
const addProject = product => {
console.log(product.value);
if (!product.value.type) {
const data = product.value;
data.type = 1;
productList.value.unshift(data);
} else {
productList.value.forEach((item, index) => {
if (item.type == product.value.type) {
Object.assign(productList.value[index], product.value);
}
});
// Object.assign(productList.value, product.value);
}
pagination.value.total = productList.value.length;
};
</script>
<template>
<div class="main">
<div class="w-full flex justify-between mb-4">
<h2>项目列表</h2>
<el-button
:icon="useRenderIcon(AddFill)"
type="primary"
color="#1C0D82"
@click="formDialogVisible = true"
v-if="pagination.total > 0"
>
新建项目
</el-button>
@ -151,8 +179,14 @@ const handleProductDetail = product => {
:element-loading-svg="svg"
element-loading-svg-view-box="-10, -10, 50, 50"
>
<el-empty
description="暂无数据"
<el-card
class="box-card"
:body-style="{
height: '462px',
display: 'flex',
'justify-content': 'center',
'align-items': 'center'
}"
v-show="
productList
.slice(
@ -163,46 +197,90 @@ const handleProductDetail = product => {
v.name.toLowerCase().includes(searchValue.toLowerCase())
).length === 0
"
/>
<template v-if="pagination.total > 0">
<el-row :gutter="16">
<el-col
v-for="(product, index) in productList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.name.toLowerCase().includes(searchValue.toLowerCase())
)"
:key="index"
:xs="48"
:sm="36"
:md="24"
:lg="12"
:xl="8"
>
<el-empty description="暂未添加任何项目" :image="emptyPic">
<el-button
type="primary"
color="#1C0D82"
@click="formDialogVisible = true"
>
<Card
:product="product"
@delete-item="handleDeleteItem"
@manage-product="handleManageProduct"
@product-detail="handleProductDetail"
/>
</el-col>
</el-row>
<el-pagination
class="float-right"
v-model:currentPage="pagination.current"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 24, 36]"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"
@current-change="onCurrentChange"
/>
新建项目
</el-button>
</el-empty>
</el-card>
<template v-if="pagination.total > 0">
<el-card shadow="never">
<el-row :gutter="16">
<el-col
v-for="(product, index) in productList
.slice(
pagination.pageSize * (pagination.current - 1),
pagination.pageSize * pagination.current
)
.filter(v =>
v.name.toLowerCase().includes(searchValue.toLowerCase())
)"
:key="index"
:xs="24"
:sm="12"
:md="8"
:lg="6"
:xl="4"
>
<Card
:product="product"
@delete-item="handleDeleteItem"
@manage-product="handleManageProduct"
@product-detail="handleProductDetail"
/>
</el-col>
</el-row>
<el-pagination
class="justify-end"
v-model:currentPage="pagination.current"
:page-size="pagination.pageSize"
:total="pagination.total"
:page-sizes="[12, 24, 36]"
:background="true"
layout="total, sizes, prev, pager, next, jumper"
@size-change="onPageSizeChange"
@current-change="onCurrentChange"
/>
</el-card>
</template>
</div>
<dialogForm v-model:visible="formDialogVisible" :data="formData" />
<dialogForm
v-model:visible="formDialogVisible"
:data="formData"
@submit-form="addProject"
/>
</div>
</template>
<style lang="scss">
// :deep(.el-dialog, .is-draggable, .el-dialog__header) {
// border-bottom: 1px solid #eee !important;
// }
.msg-box-style {
// --el-messagebox-width: 580px;
// height: 184px;
.btn-custom-cancel:hover {
color: #fff;
// color: skyblue;
background-color: #1c0d82;
opacity: 0.5;
}
.btn-custom-confirm {
color: #fff;
background-color: #1c0d82;
border: #1c0d82;
&:hover {
color: #fff;
// color: skyblue;
background-color: #1c0d82;
opacity: 0.5;
}
}
}
</style>

Loading…
Cancel
Save