60 Commits

Author SHA1 Message Date
guanj
98e0f9de02 修改关键字 2026-05-28 19:28:12 +08:00
guanj
21756e05d4 修改地图 2026-05-27 10:47:31 +08:00
guanj
abfdf29a38 修改页面样式 调整查询条件 2026-05-22 09:58:07 +08:00
guanj
120892808b 提交代码 2026-04-25 15:21:53 +08:00
guanj
0f5cb1d3c5 提交代码 2026-04-09 11:44:06 +08:00
cdf
dbaa42ff7e 通用台账查询页面调整 2026-04-09 11:42:54 +08:00
guanj
48472bdb85 微调 2026-04-03 14:48:10 +08:00
guanj
fafc5f82c4 修改itic点击波形图 2026-03-26 14:53:34 +08:00
cdf
93ee7e4034 通用台账查询页面调整 2026-03-23 09:19:43 +08:00
guanj
7d2ce51510 修改问题 2026-03-17 08:43:51 +08:00
guanj
9202da17f1 微调 2026-03-05 15:42:15 +08:00
guanj
30eddd0572 修改用户台账管理接口 2026-03-05 11:08:36 +08:00
sjl
15bd1ac6d2 事件报告导出 2026-03-02 15:35:29 +08:00
sjl
f5c76c1b7a 报告模版配置 2026-02-27 14:46:19 +08:00
sjl
b25515b5db 系统相关配置 2026-02-27 08:49:57 +08:00
guanj
bfa061fb03 冀北数据总览添加导出功能 2026-02-06 14:45:15 +08:00
sjl
15e3d4aec8 微调 2026-02-06 10:10:24 +08:00
sjl
59489aaafa 微调 2026-01-30 15:01:19 +08:00
guanj
5d0421dd40 Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-29 14:10:32 +08:00
guanj
6d7ef7cf5d 修改终端型号 2026-01-29 14:10:18 +08:00
sjl
8d9ccf97a7 前置管理分配终端 2026-01-29 13:44:12 +08:00
sjl
7188e3e681 微调 2026-01-28 14:33:42 +08:00
sjl
a9fc77eb8b 区域概览未关联暂降次数和已关联处理事件合并 2026-01-28 10:33:59 +08:00
sjl
87af11288d 微调 2026-01-28 08:45:38 +08:00
sjl
0763187744 前置管理重启,稳态统计报表重置 2026-01-23 13:46:00 +08:00
sjl
ae641604ba 区域概览表格sarfi9总计 2026-01-23 09:20:57 +08:00
sjl
564e6ef4ab Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx
# Conflicts:
#	src/views/pqs/voltageSags/Region/components/echart.vue
2026-01-23 09:07:11 +08:00
sjl
c84c5dae3b 微调 2026-01-23 09:04:08 +08:00
guanj
c902dabb73 微调 2026-01-23 09:03:37 +08:00
guanj
8d1497032f Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-23 08:51:12 +08:00
guanj
6aeac753ef 修改触发类型 2026-01-23 08:51:03 +08:00
sjl
56d65a6c17 9000系统测试用例调整 2026-01-22 16:15:33 +08:00
sjl
8b356c87a3 微调 2026-01-20 14:33:06 +08:00
guanj
c0feeaee7b 删除海南备份技术监督 2026-01-20 14:25:24 +08:00
guanj
6a112c8ae2 修改表格操作列 2026-01-20 14:18:41 +08:00
guanj
a19952b771 调整云南曲靖问题 2026-01-16 14:03:40 +08:00
guanj
0b76347853 Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-12 14:49:30 +08:00
guanj
379951699d 修改日志 2026-01-12 14:49:21 +08:00
sjl
003737cf52 Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-12 14:02:06 +08:00
sjl
20e6d3719a 微调 2026-01-12 14:01:43 +08:00
guanj
77617412dd Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx
# Conflicts:
#	src/views/pqs/voltageSags/monitoringPoint/online/navigation/index.vue
修改冲突
2026-01-12 14:01:09 +08:00
guanj
68ea43c42b 修改在线监测数据问题 2026-01-12 13:56:49 +08:00
sjl
e65df4daad Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx
# Conflicts:
#	src/views/pqs/voltageSags/monitoringPoint/online/navigation/index.vue
2026-01-12 11:24:34 +08:00
sjl
136248eec2 角色用户管理,区域概览 2026-01-12 11:22:42 +08:00
guanj
bfafb6dc5b 修改曲靖问题 2026-01-12 11:19:05 +08:00
sjl
0b91027da4 微调 2026-01-09 11:21:07 +08:00
guanj
22aeb0bf4c Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-09 11:20:10 +08:00
guanj
87bc9d9017 添加绑定监测点筛选 2026-01-09 11:20:02 +08:00
sjl
43d4d37cd0 Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-09 10:45:07 +08:00
sjl
ad1528e53b 导出日志 2026-01-09 10:44:35 +08:00
guanj
c1e36440e7 修改实时数据 2026-01-09 10:40:55 +08:00
guanj
16f5213d7a Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx 2026-01-09 08:47:18 +08:00
guanj
ab891e6125 修改角色管理页面 2026-01-09 08:47:07 +08:00
sjl
36c8ab87a2 微调 2026-01-08 15:17:19 +08:00
guanj
6c3037f19b 修改云南曲靖项目 2026-01-08 14:52:01 +08:00
sjl
54517c0d5f 稳态合格率,畸变率表格调整 2026-01-08 14:50:29 +08:00
guanj
715cdb892f 修改树 2026-01-07 08:38:45 +08:00
sjl
953b96fe05 Merge branch 'master' of http://192.168.1.22:3000/Web/admin-sjzx
# Conflicts:
#	src/components/tree/pqs/bearingTree.vue
#	src/views/pqs/harmonicMonitoring/monitoringPoint/online/wentaizhibiaohegelv/index.vue
2026-01-06 08:38:11 +08:00
sjl
cb19fef4c6 微调 2026-01-06 08:35:36 +08:00
guanj
98c887b79d 添加云南曲靖打包命令修改5层树逻辑 2026-01-05 10:13:53 +08:00
429 changed files with 46976 additions and 69229 deletions

6
.env.qujing Normal file
View File

@@ -0,0 +1,6 @@
# 云南曲靖
NODE_ENV = qujing
VITE_NAME="qujing"
# 电网一张图 地图图层
VITE_NARIMAP=null
VITE_NRGISCOMMON=null

156
README.md
View File

@@ -1,78 +1,78 @@
#### 介绍
```
Vue 3 + TypeScript + Vite这个模板可以帮助您开始使用Vue 3和TypeScript在Vite中进行开发。该模板使用了Vue 3的<script setup>单文件组件请查看script setup文档了解更多信息。
```
#### 安装依赖&运行项目
> node version:^18.17.0 || >=20.5.0"
```shell
#项目使用pnpm包管理器
npm i pnpm -g
#安装依赖
pnpm i
#运行项目
npm run dev
#冀北现场启动命令 区分是否加载现场电网一张图内网api
npm run dev:jibei
#去除后台所有模块名 如除/xxxx-boot
npm run dev:removeMode
#因海南和冀北技术监督不同 通过修改文件的方式来区分
#海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb
#冀北打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn
```
#### 页面编写-示例
```
基础页面写法请查看`src/template`下的readme.md
```
#### 开发规范
> 初衷:养成合理的习惯,精力留在技术调研、业务开发中。
>
> 常见点如下描述,更多的规范待前端开发人员有时间后,慢慢丰富。
- 命名风格:所有的包(文件夹)、文件名以小驼峰的风格命名,比如 xxxAaa禁止 XxxAaa 或者 xxx-aaa。
- 命名语义:禁止中文命名或拼音,英文命名借用下工具,稍微准确一点,不要与实际业务相差太远。
- 功能组件创建风格:以**功能名称**命名文件夹,每个功能下以**index.vue**作为该功能的组件入口。正确示例参考:/src/views/auth/menu/index.vue。
![组件层级图](./src/assets/readme/moduleLevel.png)
- todo...:待后续补充。
#### 开发助手
##### 1、表格系列
- 页面表格以及表格页面按钮的弹出等功能参考:/views/pqs/voltageSags/sagGovern/index.vue
- 表格中需要替换数据:
```js
// 通过formatter函数返回实际需要返回的值
{
title: '数据来源', field: 'dataSource', minWidth: '130',
formatter: (row: any) => {
return row.dataSource == 0 ? '离线导入' : '监测点同步'
}
}****
```
##### 2、样式系列
- 获取当前主体的高度import { mainHeight } from '@/utils/layout'
- 弹框内输入框长度设置 1 行 1 个 class="form-one" 1 行 2 个 class="form-two"
#### 依赖变更记录
- 2024-04-25 新增 vform3by 洪圣文,用于页面表单设计保存为 json命令pnpm i vform3-builds
#### 介绍
```
Vue 3 + TypeScript + Vite这个模板可以帮助您开始使用Vue 3和TypeScript在Vite中进行开发。该模板使用了Vue 3的<script setup>单文件组件请查看script setup文档了解更多信息。
```
#### 安装依赖&运行项目
> node version:^18.17.0 || >=20.5.0"
```shell
#项目使用pnpm包管理器
npm i pnpm -g
#安装依赖
pnpm i
#运行项目
npm run dev
#jb现场启动命令 区分是否加载现场电网一张图内网api
npm run dev:jibei
#去除后台所有模块名 如除/xxxx-boot
npm run dev:removeMode
#因海南和jb技术监督不同 通过修改文件的方式来区分
#海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb
#jb打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn
```
#### 页面编写-示例
```
基础页面写法请查看`src/template`下的readme.md
```
#### 开发规范
> 初衷:养成合理的习惯,精力留在技术调研、业务开发中。
>
> 常见点如下描述,更多的规范待前端开发人员有时间后,慢慢丰富。
- 命名风格:所有的包(文件夹)、文件名以小驼峰的风格命名,比如 xxxAaa禁止 XxxAaa 或者 xxx-aaa。
- 命名语义:禁止中文命名或拼音,英文命名借用下工具,稍微准确一点,不要与实际业务相差太远。
- 功能组件创建风格:以**功能名称**命名文件夹,每个功能下以**index.vue**作为该功能的组件入口。正确示例参考:/src/views/auth/menu/index.vue。
![组件层级图](./src/assets/readme/moduleLevel.png)
- todo...:待后续补充。
#### 开发助手
##### 1、表格系列
- 页面表格以及表格页面按钮的弹出等功能参考:/views/pqs/voltageSags/sagGovern/index.vue
- 表格中需要替换数据:
```js
// 通过formatter函数返回实际需要返回的值
{
title: '数据来源', field: 'dataSource', minWidth: '130',
formatter: (row: any) => {
return row.dataSource == 0 ? '离线导入' : '监测点同步'
}
}****
```
##### 2、样式系列
- 获取当前主体的高度import { mainHeight } from '@/utils/layout'
- 弹框内输入框长度设置 1 行 1 个 class="form-one" 1 行 2 个 class="form-two"
#### 依赖变更记录
- 2024-04-25 新增 vform3by 洪圣文,用于页面表单设计保存为 json命令pnpm i vform3-builds

View File

@@ -15,7 +15,7 @@
<script src="/static/luckysheet/plugin.js"></script>
<script src="/static/luckysheet/luckysheet.umd.js"></script>
<!-- 冀北地图 -->
<!-- jb地图 -->
<!--引入样式文件-->
<script src="%VITE_NARIMAP%"></script>
<!-- <script src="%VITE_NRGISCOMMON%"></script> -->

View File

@@ -7,10 +7,12 @@
"dev": "vite --mode dev",
"dev:jibei": "vite --mode jibei",
"dev:hainan": "vite --mode hainan",
"dev:qujing": "vite --mode qujing",
"dev:removeMode": "vite --mode removeMode",
"build": "vite build --mode dev",
"build:jibei": "vite build --mode jibei",
"build:hainan": "vite build --mode hainan",
"build:qujing": "vite build --mode qujing",
"build:removeMode": "vite build --mode removeMode",
"preview": "vite preview"
},

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -13,9 +13,11 @@ onMounted(async () => {
const response = await fetch('/')
const WebSocketUrl:any = response.headers.get('X-WebSocket-Url')
const WebSocketUrl2:any = response.headers.get('X-WebSocket-Url2')
const WebSocketUrl3:any = response.headers.get('X-WebSocket-Url3')
const MqttUrl:any = response.headers.get('X-MqttUrl-Url')
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
localStorage.setItem('WebSocketUrl', WebSocketUrl)
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
localStorage.setItem('WebSocketUrl3', WebSocketUrl3)
localStorage.setItem('MqttUrl', MqttUrl)
})
</script>

View File

@@ -1,5 +1,6 @@
import createAxios from '@/utils/request'
// 密码规则修改
export function ruleUpdate(data) {
return createAxios({
@@ -24,3 +25,77 @@ export function unlockRoot(data) {
data
})
}
//根据客户端名查询信息
export function getClientInfoByPath() {
return createAxios({
url: '/user-boot/authClient/getAuthClientByName/njcn',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}
//客户端会话配置更新
export function updateClientSessionConfig(data) {
return createAxios({
url: '/user-boot/authClient/sessionConfigUpdate',
method: 'post',
data
})
}
//获取用户配置
export function getUserConfig() {
return createAxios({
url: '/user-boot/password/getUserStrategyList',
method: 'post'
})
}
//查询系统列表
export function getSystemList() {
return createAxios({
url: '/system-boot/config/getSysConfigData',
method: 'get'
})
}
//激活系统配置
export function activeSystemConfig(data) {
return createAxios({
url: '/system-boot/config/updateSysConfig',
method: 'post',
data
})
}
//删除系统配置
export function deleteSystemConfig( data) {
return createAxios({
url: '/system-boot/config/removeSysConfigById',
method: 'get',
params: data
})
}
//新增系统配置
export function addSystemConfig(data) {
return createAxios({
url: '/system-boot/config/addSysConfig',
method: 'post',
data
})
}
//修改系统配置
export function updateSystemConfig(data) {
return createAxios({
url: '/system-boot/config/updateSysConfig',
method: 'post',
data
})
}

View File

@@ -129,7 +129,7 @@ export function queryAllByType(params: any) {
//获取用户
export function selectUserList(data: any) {
return createAxios({
url: '/supervision-boot/userReport/selectUserList',
url: '/device-boot/userReport/selectUserList',
method: 'post',
data
})
@@ -206,3 +206,11 @@ export function exportTerminalBase() {
responseType: 'blob'
})
}
//一键分配终端
export function allotTerminal(data: any) {
return createAxios({
url: '/device-boot/nodeDevice/oneKeyDistribution',
method: 'post',
params: data
})
}

View File

@@ -45,3 +45,13 @@ export const getLineOverLimitData = (id: string) => {
method: 'post'
})
}
//导出数据总览
export function dataVerifyExcel(params: any) {
return request({
url: '/device-boot/dataVerify/dataVerifyExcel',
method: 'get',
params,
responseType: 'blob'
})
}

View File

@@ -31,4 +31,13 @@ export function getDevTypeList() {
method: 'post',
})
}
export const getDeviceTypeList = (params: any) => {
return createAxios({
url: '/device-boot/devType/pageDevTypeList',
method: 'POST',
data: params
})
}

View File

@@ -0,0 +1,103 @@
import request from '@/utils/request'
// 新增敏感用户
export function saveUser(data: any) {
return request({
url: '/device-boot/pqSensitiveUser/save',
method: 'post',
data: data
})
}
// 修改敏感用户
export function updateUser(data: any) {
return request({
url: '/device-boot/pqSensitiveUser/update',
method: 'post',
data: data
})
}
// 删除敏感用户
export function deleteUser(data: any) {
return request({
url: '/device-boot/pqSensitiveUser/delete',
method: 'post',
data: data
})
}
/**
* 干扰源接入功能删除流程
*/
export const deleteUserReport = (data: any) => {
return request({
url: '/device-boot/userReport/deleteUserReport',
method: 'POST',
data
})
}
/**
* 提交表单数据
*/
export const submitFormData = (data: any) => {
return request({
url: '/device-boot/userReport/add',
method: 'POST',
data: data
})
}
// 根据id获取用户档案录入的详细数据
export const getById = (data: any) => {
return request({
url: '/device-boot/userReport/getById',
method: 'get',
params: data
})
}
/**
* 提交表单数据
*/
export const addEditor = (data: any) => {
return request({
url: '/device-boot/userReportRenewal/addEditor',
method: 'POST',
data: data
})
}
// 根据id获取用户档案录入的详细数据
export const getByDeptDevLine = (params: any) => {
return request({
url: '/device-boot/line/getByDeptDevLine',
method: 'get',
params
})
}
/**
* 根据id获取用户档案录入的详细数据
*/
export const getUserReportUpdateById = (id: any) => {
return request({
url: '/device-boot/userReportRenewal/getUserReportUpdateById?businessId='+id,
method: 'POST',
})
}
// 根据id获取用户档案录入的详细数据
export const getUserReportById = (id: any) => {
return request({
url: '/device-boot/userReport/getUserReportById?id='+id,
method: 'get'
})
}
// 根据id查询文件信息集合
export const getFileById = (params: any) => {
return request({
url: '/device-boot/fileUrl/getFileById',
method: 'get',
params
})
}

View File

@@ -1,72 +1,137 @@
import createAxios from '@/utils/request'
//事件报告
export function getEventReport(data) {
return createAxios({
url: '/event-boot/report/getEventReport',
method: 'post',
data
})
}
// 生成报告
export function getAreaReport(data) {
return createAxios({
url: '/event-boot/report/getAreaReport',
method: 'post',
data,
responseType: 'blob'
})
}
//查询所有模板
export function getList(data) {
return createAxios({
url: '/system-boot/EventTemplate/getList',
method: 'post',
data
})
}
export function selectReleation(data) {
return createAxios({
url: '/system-boot/EventTemplate/selectReleation',
method: 'post',
params: data
})
}
export function getLineExport(data) {
return createAxios({
url: '/event-boot/report/getLineExport',
method: 'post',
data: data,
responseType: 'blob'
})
}
export function getVoltage(data: any) {
return createAxios({
url: '/event-boot/report/getVoltage',
method: 'post',
data
})
}
export function getGeneralSituation(data: any) {
return createAxios({
url: '/event-boot/report/getGeneralSituation',
method: 'post',
data
})
}
export function getTransientValue(data: any) {
return createAxios({
url: '/event-boot/transient/getTransientValue',
method: 'post',
data
})
}
// 周报导出
export function getExport(data: any) {
return createAxios({
url: '/event-boot/report/getExport',
method: 'post',
data,
responseType: 'blob'
})
}
import createAxios from '@/utils/request'
import { genFileId, ElMessage, ElNotification } from 'element-plus'
//事件报告
// export function getEventReport(data) {
// return createAxios({
// url: '/event-boot/report/getEventReport',
// method: 'post',
// data
// })
// }
export function getEventReport(data) {
return createAxios({
url: '/event-boot/report/createEventReport',
method: 'post',
data,
responseType: 'blob'
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
// 生成报告
export function getAreaReport(data) {
return createAxios({
url: '/event-boot/report/getAreaReport',
method: 'post',
data,
responseType: 'blob'
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
async function readJsonBlob(blob) {
try {
// 1. Blob.text() 读取二进制 → 直接转为 字符串(自动处理编码)
const jsonStr = await blob.text()
// 2. JSON.parse 解析字符串 → 得到可用的 JS 对象/数组
const jsonData = JSON.parse(jsonStr)
// 3. 拿到数据,后续随便用
return {
code: true,
data: jsonData
}
} catch (err) {
return {
code: false,
data: {}
}
// console.error('解析Blob的JSON数据失败', err)
}
}
//查询所有模板
export function getList(data) {
return createAxios({
url: '/system-boot/EventTemplate/getList',
method: 'post',
data
})
}
export function selectReleation(data) {
return createAxios({
url: '/system-boot/EventTemplate/selectReleation',
method: 'post',
params: data
})
}
export function getLineExport(data) {
return createAxios({
url: '/event-boot/report/getLineExport',
method: 'post',
data: data,
responseType: 'blob'
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
export function getVoltage(data: any) {
return createAxios({
url: '/event-boot/report/getVoltage',
method: 'post',
data
})
}
export function getGeneralSituation(data: any) {
return createAxios({
url: '/event-boot/report/getGeneralSituation',
method: 'post',
data
})
}
export function getTransientValue(data: any) {
return createAxios({
url: '/event-boot/transient/getTransientValue',
method: 'post',
data
})
}
// 周报导出
export function getExport(data: any) {
return createAxios({
url: '/event-boot/report/getExport',
method: 'post',
data,
responseType: 'blob'
})
}

View File

@@ -1,106 +1,114 @@
import request from '@/utils/request'
export function getTypeIdData(data: any) {
return request({
url: '/system-boot/dictData/getTypeIdData',
method: 'post',
data: data
})
}
export function getOnlineRateData2(data:any) {
return request({
url: '/harmonic-boot/onlineRateData/getOnlineRateData',
method: 'post',
data: data
})
}
export function getAreaDept() {
return request({
url: '/user-boot/dept/loginDeptTree',
method: 'post'
})
}
export function getOnlineRateDataCensus(data:any) {
return request({
url: '/device-boot/terminalOnlineRateData/getOnlineRateDataCensus',
method: 'post',
data: data
})
}
export function IntegrityIcon(data:any) {
return request({
url: '/harmonic-boot/integrity/getIntegrityIcon',
method: 'post',
data: data
})
}
export function getDeptIdAreaTree() {
return request({
url: '/system-boot/area/getDeptIdAreaTree',
method: 'post'
})
}
export function getOnlineRateData(data:any) {
return request({
url: '/device-boot/terminalOnlineRateData/getOnlineRateData',
method: 'post',
data: data
})
}
export function getSubstationInfoById(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getSubstationInfoById',
method: 'post',
data: data
})
}
export function getLineInfoById(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getLineInfoById',
method: 'post',
data: data
})
}
export function getLineRank(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getLineRank',
method: 'post',
data: data
})
}
export function deptInfo(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/deptInfo',
method: 'post',
data: data
})
}
export function getXbLineInfoById(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getXbLineInfoById',
method: 'post',
data: data
})
}
export function getSubInfoById(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getSubInfoById',
method: 'post',
data: data
})
}
export function getXbLineRank(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getXbLineRank',
method: 'post',
data: data
})
}
// 数据补招
export function FullRecall(data:any) {
return request({
url: '/data-processing-boot/data/FullRecall',
method: 'post',
data: data
})
}
import request from '@/utils/request'
export function getTypeIdData(data: any) {
return request({
url: '/system-boot/dictData/getTypeIdData',
method: 'post',
data: data
})
}
export function getOnlineRateData2(data:any) {
return request({
url: '/harmonic-boot/onlineRateData/getOnlineRateData',
method: 'post',
data: data
})
}
export function getAreaDept() {
return request({
url: '/user-boot/dept/loginDeptTree',
method: 'post'
})
}
// 承载能力评估去除前缀
export function getAreaDeptRemoveMode(params) {
return request({
url: '/user-boot/dept/loginDeptTree',
method: 'GET',
params: params
})
}
export function getOnlineRateDataCensus(data:any) {
return request({
url: '/device-boot/terminalOnlineRateData/getOnlineRateDataCensus',
method: 'post',
data: data
})
}
export function IntegrityIcon(data:any) {
return request({
url: '/harmonic-boot/integrity/getIntegrityIcon',
method: 'post',
data: data
})
}
export function getDeptIdAreaTree() {
return request({
url: '/system-boot/area/getDeptIdAreaTree',
method: 'post'
})
}
export function getOnlineRateData(data:any) {
return request({
url: '/device-boot/terminalOnlineRateData/getOnlineRateData',
method: 'post',
data: data
})
}
export function getSubstationInfoById(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getSubstationInfoById',
method: 'post',
data: data
})
}
export function getLineInfoById(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getLineInfoById',
method: 'post',
data: data
})
}
export function getLineRank(data:any) {
return request({
url: '/harmonic-boot/PollutionSubstation/getLineRank',
method: 'post',
data: data
})
}
export function deptInfo(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/deptInfo',
method: 'post',
data: data
})
}
export function getXbLineInfoById(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getXbLineInfoById',
method: 'post',
data: data
})
}
export function getSubInfoById(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getSubInfoById',
method: 'post',
data: data
})
}
export function getXbLineRank(data:any) {
return request({
url: '/harmonic-boot/detailAnalysis/getXbLineRank',
method: 'post',
data: data
})
}
// 数据补招
export function FullRecall(data:any) {
return request({
url: '/data-processing-boot/data/FullRecall',
method: 'post',
data: data
})
}

View File

@@ -1,18 +1,48 @@
import request from '@/utils/request'
export function getHistoryResult(data: any) {
return request({
url: '/harmonic-boot/harmonic/getHistoryResult',
method: 'post',
data: data
})
}
// word报告
export function exportModelJB(data: any) {
return request({
url: '/harmonic-boot/exportmodel/exportModelJB',
method: 'post',
responseType: 'blob',
data: data
})
}
import request from '@/utils/request'
import { genFileId, ElMessage, ElNotification } from 'element-plus'
export function getHistoryResult(data: any) {
return request({
url: '/harmonic-boot/harmonic/getHistoryResult',
method: 'post',
data: data
})
}
// word报告
export function exportModelJB(data: any) {
return request({
url: '/harmonic-boot/exportmodel/exportModelJB',
method: 'post',
responseType: 'blob',
data: data
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
async function readJsonBlob(blob) {
try {
// 1. Blob.text() 读取二进制 → 直接转为 字符串(自动处理编码)
const jsonStr = await blob.text()
// 2. JSON.parse 解析字符串 → 得到可用的 JS 对象/数组
const jsonData = JSON.parse(jsonStr)
// 3. 拿到数据,后续随便用
return {
code: true,
data: jsonData
}
} catch (err) {
return {
code: false,
data: {}
}
// console.error('解析Blob的JSON数据失败', err)
}
}

View File

@@ -1,10 +1,60 @@
import createAxios from '@/utils/request'
export function exportModel(data: any) {
return createAxios({
url: '/harmonic-boot/exportmodel/exportModel',
method: 'post',
data: data,
responseType: 'blob'
})
}
import createAxios from '@/utils/request'
import { genFileId, ElMessage, ElNotification } from 'element-plus'
export function exportModel(data: any) {
return createAxios({
url: '/harmonic-boot/exportmodel/exportModel',
method: 'post',
data: data,
responseType: 'blob'
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
export function areaHarmonicReport(data: any) {
return createAxios({
url: '/harmonic-boot/areaHarmonicReport/areaHarmonicReport',
method: 'post',
data: data,
responseType: 'blob'
}).then(async res => {
let load: any = await readJsonBlob(res)
if (load.code) {
if (load.data.code == 'A0011') {
ElMessage.warning('下载失败!')
} else {
ElMessage.warning(load.data.message)
}
} else {
return res
}
})
}
async function readJsonBlob(blob) {
try {
// 1. Blob.text() 读取二进制 → 直接转为 字符串(自动处理编码)
const jsonStr = await blob.text()
// 2. JSON.parse 解析字符串 → 得到可用的 JS 对象/数组
const jsonData = JSON.parse(jsonStr)
// 3. 拿到数据,后续随便用
return {
code: true,
data: jsonData
}
} catch (err) {
return {
code: false,
data: {}
}
// console.error('解析Blob的JSON数据失败', err)
}
}

View File

@@ -0,0 +1,42 @@
import request from "@/utils/request";
//查询所有模板
export function getList(data: any) {
return request({
url: "/system-boot/EventTemplate/getList",
method: "post",
data,
});
}
//字典树
export function getDictTree(data: any) {
return request({
url: "/system-boot/reportDict/DictTree",
method: "post",
params:data
});
}
//新增模板
export function addData(data: any) {
return request({
url: "/system-boot/EventTemplate/add",
method: "post",
data,
});
}
//修改模板
export function updateData(data: any) {
return request({
url: "/system-boot/EventTemplate/update",
method: "post",
data,
});
}
//删除模板
export function deleteData(data: any) {
return request({
url: "/system-boot/EventTemplate/delete",
method: "post",
data,
});
}

View File

@@ -0,0 +1,43 @@
import request from '@/utils/request'
//获取字典树数据
export function getDictTree(data) {
return request({
url: "/system-boot/reportDict/DictTree",
method: "post",
params:data
});
}
//查询字典列表
export function getReportDictList(data: any) {
return request({
url: "/system-boot/reportDict/getReportDictList",
method: "post",
data
});
}
//新增字典表
export function addDict(data: any) {
return request({
url: "/system-boot/reportDict/addDict",
method: "post",
data
});
}
//更新字典表
export function updateDict(data: any) {
return request({
url: "/system-boot/reportDict/updateDict",
method: "put",
data
});
}
//删除字典表
export function deleteDict(data: any) {
return request({
url: "/system-boot/reportDict/deleteDict",
method: "delete",
params:data
});
}

View File

@@ -0,0 +1,37 @@
import request from '@/utils/request'
//区域树形表格接口
export function areaTree(data: any) {
return request({
url: '/system-boot/area/areaTree',
method: 'post',
params: data,
})
}
export function areaAdd(data: any) {
return request({
url: '/system-boot/area/add',
method: 'post',
data: data,
})
}
export function areaDelete(data: any) {
return request({
url: '/system-boot/area/delete',
method: 'post',
data: data,
})
}
export function update(data: any) {
return request({
url: '/system-boot/area/update',
method: 'post',
data: data,
})
}
export function selectPid(data: any) {
return request({
url: '/system-boot/area/selectPid',
method: 'post',
data: data,
})
}

View File

@@ -31,7 +31,7 @@ export const uploadFile = (file: any, path: string) => {
data: form
}).then(res => {
if (res.code == `A0000`) {
ElMessage.success('上传成功!')
ElMessage.success('文件上传成功!')
return res
}
})

BIN
src/assets/img/region.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

BIN
src/assets/imgs/m0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
src/assets/imgs/m1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/imgs/m2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/assets/imgs/m3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
src/assets/imgs/m4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
src/assets/logo/海南.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
src/assets/logo/灿能.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
src/assets/logo/电网.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

BIN
src/assets/logo/电网1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

View File

@@ -23,7 +23,7 @@ export function upper(str) {
}
export function makeOptionsRule(t, to, userOptions) {
console.log(userOptions[0])
//console.log(userOptions[0])
const options = [
{ label: t('props.optionsType.struct'), value: 0 },
{ label: t('props.optionsType.json'), value: 1 },

View File

@@ -43,7 +43,6 @@ if (VITE_FLAG) {
})
} else {
setTimeout(async () => {
const previewUrl = await previewFile(currentRoute.value?.href?.split('?')[1])
url.value = previewUrl
excelOptions.value = ref({

View File

@@ -707,7 +707,7 @@ const processSave = async () => {
// return result.value || '&nbsp;'
// }
onBeforeMount(() => {
console.log(props, 'propspropspropsprops')
//console.log(props, 'propspropspropsprops')
})
onMounted(() => {
initBpmnModeler()

View File

@@ -15,7 +15,7 @@ const addTask = (event, options: any = {}) => {
const ElementFactory = bpmnInstances().elementFactory
const create = bpmnInstances().modeler.get('create')
console.log(ElementFactory, create)
//console.log(ElementFactory, create)
const shape = ElementFactory.createShape(assign({ type: 'bpmn:UserTask' }, options))
@@ -23,8 +23,8 @@ const addTask = (event, options: any = {}) => {
shape.businessObject.di.isExpanded = options.isExpanded
}
console.log(event, 'event')
console.log(shape, 'shape')
//console.log(event, 'event')
//console.log(shape, 'shape')
create.start(event, shape)
}
</script>

View File

@@ -172,7 +172,7 @@ const unwatchBpmn = watch(
return
}
console.log('props.bpmnModeler 有值了!!!')
//console.log('props.bpmnModeler 有值了!!!')
const w = window as any
w.bpmnInstances = {
modeler: props.bpmnModeler,

View File

@@ -179,7 +179,7 @@ onBeforeUnmount(() => {
watch(
() => props.businessObject,
(val) => {
console.log(val, 'val')
//console.log(val, 'val')
nextTick(() => {
resetFlowCondition()
})

View File

@@ -376,7 +376,7 @@ const openListenerForm = (listener, index?) => {
}
// 移除监听器
const removeListener = (listener, index?) => {
console.log(listener, 'listener')
//console.log(listener, 'listener')
ElMessageBox.confirm('确认移除该监听器吗?', '提示', {
confirmButtonText: '确 认',
cancelButtonText: '取 消'

View File

@@ -20,7 +20,7 @@ export function initListenerForm(listener) {
self.eventDefinitionType = key.replace('time', '').toLowerCase()
}
}
console.log(k)
//console.log(k)
self.eventTimeDefinitions = listener.eventDefinitions[0][k].body
}
}

View File

@@ -68,7 +68,7 @@ const modelConfig = computed(() => {
const bpmnInstances = () => (window as any)?.bpmnInstances
const initDataList = () => {
console.log(window, 'window')
//console.log(window, 'window')
rootElements.value = bpmnInstances().modeler.getDefinitions().rootElements
messageIdMap.value = {}
signalIdMap.value = {}

View File

@@ -39,7 +39,7 @@ function xml2json(xml) {
function xmlObj2json(xml) {
const xmlObj = xmlStr2XmlObj(xml)
console.log(xmlObj)
// console.log(xmlObj)
let jsonObj = {}
if (xmlObj.childNodes.length > 0) {
jsonObj = xml2json(xmlObj)

View File

@@ -183,7 +183,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0
} else {
return k.citName != '上送国网' && k.citName != '上送国网'
return !k.citName.includes('上送')
}
})
}
@@ -223,7 +223,7 @@ const echart = () => {
series: [
{
name: '异常总数',
name: '',
type: 'bar',
barWidth: 12,
data: [100],
@@ -240,7 +240,7 @@ const echart = () => {
colorStops: [
{
offset: 1,
color: '#57bc6e' // 100% 处的颜色
color: '#FF9100' // 100% 处的颜色
}
],
global: false // 缺省为 false
@@ -249,7 +249,7 @@ const echart = () => {
}
},
{
name: '异常占比',
name: '',
type: 'bar',
barWidth: 13,
data: [
@@ -270,11 +270,11 @@ const echart = () => {
colorStops: [
{
offset: 0,
color: '#FF9100' // 0% 处的颜色
color: '#57bc6e ' // 0% 处的颜色
},
{
offset: 1,
color: '#FF9100' // 100% 处的颜色
color: '#57bc6e' // 100% 处的颜色
}
],
global: false // 缺省为 false

View File

@@ -181,7 +181,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0
} else {
return k.citName != '上送国网' && k.citName != '上送国网'
return !k.citName.includes('上送')
}
})
@@ -222,7 +222,7 @@ const echart = () => {
series: [
{
name: '异常总数',
name: '',
type: 'bar',
barWidth: 12,
data: [100],
@@ -239,7 +239,7 @@ const echart = () => {
colorStops: [
{
offset: 1,
color: '#57bc6e' // 100% 处的颜色
color: '#FF9100' // 100% 处的颜色
}
],
global: false // 缺省为 false
@@ -248,7 +248,7 @@ const echart = () => {
}
},
{
name: '异常占比',
name: '',
type: 'bar',
barWidth: 13,
data: [
@@ -269,11 +269,11 @@ const echart = () => {
colorStops: [
{
offset: 0,
color: '#FF9100' // 0% 处的颜色
color: '#57bc6e' // 0% 处的颜色
},
{
offset: 1,
color: '#FF9100' // 100% 处的颜色
color: '#57bc6e' // 100% 处的颜色
}
],
global: false // 缺省为 false

View File

@@ -233,7 +233,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.count != 0
} else {
return k.name != '上送国网' && k.name != '上送国网'
return !k.citName.includes('上送')
}
})
}

View File

@@ -17,6 +17,7 @@ const config = useConfig()
// import { nextTick } from 'process'
const emit = defineEmits(['triggerPoint', 'group', 'echartClick'])
color[0] = config.layout.elementUiPrimary[0]
const chartRef = ref<HTMLDivElement>()
const props = defineProps(['options', 'isInterVal', 'pieInterVal'])
@@ -70,6 +71,8 @@ const initChart = () => {
const value =
item.value === 3.14159 || item.value === 0.14159
? '暂无数据'
: item.value === 0.14158
? 0
: Math.round(item.value * 100) / 100 // 处理特殊值
tips += `<div style=" display: flex;justify-content: space-between;">
<span>${item.marker}
@@ -154,7 +157,6 @@ const initChart = () => {
if (params.seriesName == '暂态触发点') {
emit('triggerPoint', params.data)
} else {
emit('echartClick', params)
}
})

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { onBeforeUnmount, ref, watch, onMounted, defineEmits } from 'vue'
import { onBeforeUnmount, ref, watch, onMounted, } from 'vue'
import * as echarts from 'echarts'
import 'echarts-gl'
import 'echarts-liquidfill'
@@ -19,14 +19,21 @@ const myCharts = ref()
const showCircle = ref(false)
const fetchConfig = async (name: string) => {
const res = await import(`../../assets/map/${name.replace(/市$/, "")}.json`)
return res.default
try {
// 处理城市名称(去掉末尾的"市")并尝试导入对应文件
const res = await import(`../../assets/map/${name.replace(/市$/, '')}.json`)
return res.default
} catch (error) {
const chinaRes = await import(`../../assets/map/中国.json`) // 请确认中国文件的实际命名
return chinaRes.default
}
// const res = await import(`../../assets/map/${name.replace(/市$/, "")}.json`)
// return res.default
// GetEchar(res.default)
}
// fetchConfig()
const emit = defineEmits(['getRegionByRegion', 'eliminate', 'clickMap'])
onMounted(() => { })
const GetEchar = async (name: string) => {
let chartDom = document.getElementById('chartMap')
@@ -36,6 +43,7 @@ const GetEchar = async (name: string) => {
name == dictData.state.area?.[0].name ? (showCircle.value = false) : (showCircle.value = true)
echarts.registerMap(name, await fetchConfig(name)) //注册可用的地图
let option = {
title: {
left: 'center',
@@ -91,6 +99,7 @@ const GetEchar = async (name: string) => {
// top: 10,
// bottom: 0,
roam: true,
label: {
normal: {
show: true,
@@ -170,6 +179,7 @@ const GetEchar = async (name: string) => {
}, 0)
window.addEventListener('resize', resizeHandler)
const flag1 = ref(true)
// 点击事件
myCharts.value.off('click')
myCharts.value.on('click', (e: any) => {

View File

@@ -1,441 +1,499 @@
<template>
<div v-loading="loading">
<div>
<div id="boxi" :style="`height:${vh};overflow: hidden;`">
<div class="bx" id="wave"></div>
</div>
<el-tabs type="border-card">
<el-tab-pane label="暂态波形上送" :style="'height:' + vhh">
<el-table stripe :data="Data" :height="height" border style="width: 100%"
header-cell-class-name="table_header">
<el-table-column align="center" prop="number" label="事件段"></el-table-column>
<el-table-column align="center" prop="number" label="波形起始点相位(°)">
<el-table-column align="center" prop="number" label="A相"></el-table-column>
<el-table-column align="center" prop="number" label="B相"></el-table-column>
<el-table-column align="center" prop="number" label="C相"></el-table-column>
</el-table-column>
<el-table-column align="center" prop="number" label="跳变段电压变化率(V/ms)">
<el-table-column align="center" prop="number" label="A相"></el-table-column>
<el-table-column align="center" prop="number" label="B相"></el-table-column>
<el-table-column align="center" prop="number" label="C相"></el-table-column>
</el-table-column>
<el-table-column align="center" prop="number" label="相位跳变(°)">
<el-table-column align="center" prop="number" label="A相"></el-table-column>
<el-table-column align="center" prop="number" label="B相"></el-table-column>
<el-table-column align="center" prop="number" label="C相"></el-table-column>
</el-table-column>
<el-table-column align="center" prop="number" label="总分段数目"></el-table-column>
<el-table-column align="center" prop="number" label="三相电压不平衡度(%)" width="180"></el-table-column>
<el-table-column align="center" prop="number" label="暂降类型"></el-table-column>
<el-table-column align="center" prop="number" label="暂降原因"></el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import { downloadWaveFile, getMonitorEventAnalyseWave } from '@/api/event-boot/transient'
import { mainHeight } from '@/utils/layout'
import * as echarts from 'echarts'
import url from '@/assets/img/point.png'
import $ from 'jquery'
export default {
props: {
flag: {
type: Boolean,
default: false
},
DColor: {
type: Boolean,
default: false
},
boxoList: {
type: [Object, Array]
},
GJList: {
type: [Object, Array]
}
},
data() {
return {
loading: true,
valA: 0,
isOpen: false,
time: '',
type: '',
severity: '',
iphasic: '',
eventValue: '',
persistTime: '',
lineName: '',
subName: '',
waveDatas: [],
Data: [],
height: null,
vhh: null,
ptpass: '',
waveHeight: undefined,
$wave: undefined,
color: '#006565',
charts: {},
arrpoints: [],
titles: '',
vh: null,
vw: null,
zoom: ''
}
},
created() { },
watch: {
value: function (a, b) {
if (a == 2) {
// $("#wave1").remove();
this.initWaves()
} else {
$('#wave1').remove()
this.initWaves()
}
}
},
mounted() {
this.setHeight()
window.addEventListener('resize', this.setHeight)
this.$wave = $('#wave').eq(0)
this.$nextTick(() => {
this.query()
})
},
beforeDestroy() {
window.removeEventListener('resize', this.setHeight)
},
methods: {
setHeight() {
this.zoom = 1 / document.body.style.zoom
if (this.flag) {
// console.log(123);
this.vh = mainHeight(250).height
} else {
// console.log(3333);
this.vh = mainHeight(270).height
}
},
query() {
this.loading = true
this.initWave()
},
//开始画图
initWave() {
//清除之前增加的div
// $("#wave ~ .bx1").remove();
$('div.bx1').remove()
//设置暂降触发点的位置 一次值与二次值Y轴不同不是计算出来的
// var height = $(window).height() - 90;
var picHeight
var show = true
//var v = $("#interval").val();
var isvisible = false
picHeight = this.vh
// this.$wave.css('height', picHeight)
// this.$wave.css('width', '100%')
$('#wave').css('height', picHeight)
$('#wave').css('width', this.vw)
var adata = []
var bdata = []
var cdata = []
var max = 0
var min = 0
//绘制横向第一个波形图
this.GJList.smp_x.forEach((item, ind) => {
if (this.GJList.smp_a[ind] > max) {
max = this.GJList.smp_a[ind]
} else if (this.GJList.smp_a[ind] < min) {
min = this.GJList.smp_a[ind]
}
if (this.GJList.smp_b[ind] > max) {
max = this.GJList.smp_b[ind]
} else if (this.GJList.smp_b[ind] < min) {
min = this.GJList.smp_b[ind]
}
if (this.GJList.smp_c[ind] > max) {
max = this.GJList.smp_c[ind]
} else if (this.GJList.smp_c[ind] < min) {
min = this.GJList.smp_c[ind]
}
adata.push([item, this.GJList.smp_a[ind]])
bdata.push([item, this.GJList.smp_b[ind]])
cdata.push([item, this.GJList.smp_c[ind]])
})
//绘制瞬时波形图
// const echarts = require('echarts')
let wave = document.getElementById('wave')
let _this = this
var myChartes = echarts.init(wave)
let echartsColor = {
WordColor: '#000',
thread: '#000000',
FigureColor: [
'#07CCCA ',
'#00BFF5',
'#FFBF00',
'#77DA63',
'#D5FF6B',
'#Ff6600',
'#FF9100',
'#5B6E96',
'#66FFCC',
'#B3B3B3',
'#FF00FF',
'#CC00FF',
'#FF9999'
]
}
var option = {
tooltip: {
top: '10px',
trigger: 'axis',
borderColor: 'grey',
backgroundColor: '#fff',
style: {
color: '#000',
fontSize: '15px',
padding: 10
},
formatter: function (params) {
// console.log(params)
var tips = ''
tips += '时刻:' + params[0].data[0] + '</br/>'
for (var i = 0; i < params.length; i++) {
if (params[i].seriesName != '暂降触发点') {
tips += params[i].seriesName + ':' + params[i].value[1] + '<br/>'
}
}
return tips
},
// axisPointer: {
// type: "cross",
// label: {
// color: "#fff",
// fontSize: 16,
// },
// },
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0
},
title: {
left: 'center',
text: '发生时刻:' + this.boxoList.startTime + ' PT变化:' + this.boxoList.measurementPointName,
textStyle: {
fontSize: 16,
color: _this.DColor ? '#fff' : echartsColor.WordColor
}
},
legend: {
left: '5%',
top: '20',
verticalAlign: 'top',
enabled: true,
itemDistance: 5,
textStyle: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
rich: {
a: {
verticalAlign: 'middle'
}
},
padding: [2, 0, 0, 0] //[上、右、下、左]
}
},
toolbox: {
show: false,
feature: {
//restore: {},
saveAsImage: {
iconStyle: {
borderColor: _this.DColor ? '#fff' : echartsColor.WordColor
}
}
}
},
xAxis: {
type: 'value',
name: '时刻',
boundaryGap: false,
min: this.GJList.smp_x[0],
max: this.GJList.smp_x[this.GJList.smp_x.length - 1] + 1,
title: {
text: 'ms',
textStyle: {
fontSize: 12,
color: _this.DColor ? '#fff' : echartsColor.WordColor
},
enabled: true,
align: 'high'
},
splitLine: {
show: false
},
axisTick: {
alignWithLabel: true
},
axisLine: {
lineStyle: {
color: _this.DColor ? '#fff' : echartsColor.thread
},
onZero: false //-----------重点
},
axisLabel: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value, index) {
if (_this.valA != (value - 0).toFixed(0)) {
_this.valA = (value - 0).toFixed(0)
return (value - 0).toFixed(0)
}
}
//rotate:39
}
// data: this.syncExtremes,
},
yAxis: {
type: 'value',
name: 'kV',
title: {
align: 'high',
offset: 0,
text: 'kV',
rotation: 0,
y: -10
},
boundaryGap: [0, '100%'],
showLastLabel: true,
max: (max + 10).toFixed(2),
min: (min - 10).toFixed(2),
opposite: false,
nameTextStyle: {
color: _this.DColor ? '#fff' : echartsColor.WordColor
},
//minInterval: 1,
type: 'value',
axisLine: {
show: true,
lineStyle: {
color: _this.DColor ? '#fff' : echartsColor.thread
},
onZero: false //-----------重点
},
axisLabel: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value, index) {
return (value - 0).toFixed(2)
}
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: [_this.DColor ? '#fff' : echartsColor.thread],
type: 'dashed',
opacity: 0.5
}
}
},
grid: {
left: '1%',
right: '40px',
bottom: '40px',
top: '55px',
containLabel: true
},
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
}
],
series: [
{
name: 'A相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#DAA520'
},
data: adata
},
{
name: 'B相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#2E8B57'
},
data: bdata
},
{
name: 'C相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#A52a2a'
},
data: cdata
},
{
name: '暂降触发点',
type: 'scatter',
symbol: 'image://' + url,
itemStyle: {
width: 16,
height: 16
},
data: [[0, min]]
}
]
}
myChartes.setOption(option)
// window.echartsArr.push(myChartes)
setTimeout(() => {
myChartes.resize()
this.loading = false
}, 400)
//第一个波形图数据绘制完毕后,绘制后续的波形图
// let waveDatasTemp = waveDatas.slice(1);
// waveDatasTemp.reverse();
}
}
}
</script>
<template>
<div v-loading="loading">
<div>
<div id="boxi" :style="`height:${vh};overflow: hidden;`">
<div class="bx" id="wave"></div>
</div>
<el-tabs type="border-card">
<el-tab-pane label="暂态波形上送" :style="'height:' + vhh">
<vxe-table
stripe
:data="Data"
:height="height"
border
style="width: 100%"
header-cell-class-name="table_header"
>
<vxe-column align="center" field="number" title="事件段"></vxe-column>
<vxe-colgroup align="center" field="number1" title="波形起始点相位(°)">
<vxe-column align="center" field="number2" title="A相"></vxe-column>
<vxe-column align="center" field="number3" title="B相"></vxe-column>
<vxe-column align="center" field="number4" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup align="center" field="number" title="跳变段电压变化率(V/ms)">
<vxe-column align="center" field="number5" title="A相"></vxe-column>
<vxe-column align="center" field="number6" title="B相"></vxe-column>
<vxe-column align="center" field="number7" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-colgroup align="center" field="number" title="相位跳变(°)">
<vxe-column align="center" field="number8" title="A相"></vxe-column>
<vxe-column align="center" field="number9" title="B相"></vxe-column>
<vxe-column align="center" field="number10" title="C相"></vxe-column>
</vxe-colgroup>
<vxe-column align="center" field="number11" title="总分段数目"></vxe-column>
<vxe-column
align="center"
field="number12"
title="三相电压不平衡度(%)"
width="180"
></vxe-column>
<vxe-column align="center" field="number13" title="触发类型"></vxe-column>
<vxe-column align="center" field="number14" title="暂降原因"></vxe-column>
</vxe-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</template>
<script>
import { downloadWaveFile, getMonitorEventAnalyseWave } from '@/api/event-boot/transient'
import { mainHeight } from '@/utils/layout'
import * as echarts from 'echarts'
import url from '@/assets/img/point.png'
import $ from 'jquery'
export default {
props: {
flag: {
type: Boolean,
default: false
},
DColor: {
type: Boolean,
default: false
},
boxoList: {
type: [Object, Array]
},
GJList: {
type: [Object, Array]
}
},
data() {
return {
loading: true,
valA: 0,
isOpen: false,
time: '',
type: '',
severity: '',
iphasic: '',
eventValue: '',
persistTime: '',
lineName: '',
subName: '',
waveDatas: [],
Data: [
{
number: 1,
number1: 0,
number2: 0,
number3: 0,
number4: 0,
number5: 0,
number6: 0,
number7: 0,
number8: 0,
number9: 0,
number10: 0,
number11: 1,
number12: 0,
number13: '其他',
number14: '其他'
}
],
height: null,
vhh: null,
ptpass: '',
waveHeight: undefined,
$wave: undefined,
color: '#006565',
charts: {},
arrpoints: [],
titles: '',
vh: null,
vw: null,
zoom: ''
}
},
created() {},
watch: {
value: function (a, b) {
if (a == 2) {
// $("#wave1").remove();
this.initWaves()
} else {
$('#wave1').remove()
this.initWaves()
}
}
},
mounted() {
this.setHeight()
window.addEventListener('resize', this.setHeight)
this.$wave = $('#wave').eq(0)
this.$nextTick(() => {
this.query()
})
},
beforeDestroy() {
window.removeEventListener('resize', this.setHeight)
},
methods: {
setHeight() {
this.zoom = 1 / document.body.style.zoom
if (this.flag) {
// console.log(123);
this.vh = mainHeight(280).height
} else {
// console.log(3333);
this.vh = mainHeight(305).height
}
},
query() {
this.loading = true
this.initWave()
},
//开始画图
initWave() {
//清除之前增加的div
// $("#wave ~ .bx1").remove();
$('div.bx1').remove()
//设置暂降触发点的位置 一次值与二次值Y轴不同不是计算出来的
// var height = $(window).height() - 90;
var picHeight
var show = true
//var v = $("#interval").val();
var isvisible = false
picHeight = this.vh
// this.$wave.css('height', picHeight)
// this.$wave.css('width', '100%')
$('#wave').css('height', picHeight)
$('#wave').css('width', this.vw)
var adata = []
var bdata = []
var cdata = []
var max = 0
var min = 0
//绘制横向第一个波形图
this.GJList.smp_x.forEach((item, ind) => {
if (this.GJList.smp_a[ind] > max) {
max = this.GJList.smp_a[ind]
} else if (this.GJList.smp_a[ind] < min) {
min = this.GJList.smp_a[ind]
}
if (this.GJList.smp_b[ind] > max) {
max = this.GJList.smp_b[ind]
} else if (this.GJList.smp_b[ind] < min) {
min = this.GJList.smp_b[ind]
}
if (this.GJList.smp_c[ind] > max) {
max = this.GJList.smp_c[ind]
} else if (this.GJList.smp_c[ind] < min) {
min = this.GJList.smp_c[ind]
}
adata.push([item, this.GJList.smp_a[ind]])
bdata.push([item, this.GJList.smp_b[ind]])
cdata.push([item, this.GJList.smp_c[ind]])
})
//绘制瞬时波形图
// const echarts = require('echarts')
let wave = document.getElementById('wave')
let _this = this
var myChartes = echarts.init(wave)
let echartsColor = {
WordColor: '#000',
thread: '#000000',
FigureColor: [
'#07CCCA ',
'#00BFF5',
'#FFBF00',
'#77DA63',
'#D5FF6B',
'#Ff6600',
'#FF9100',
'#5B6E96',
'#66FFCC',
'#B3B3B3',
'#FF00FF',
'#CC00FF',
'#FF9999'
]
}
console.log('🚀 ~ this.boxoList:', this.boxoList)
var option = {
tooltip: {
top: '10px',
trigger: 'axis',
borderColor: 'grey',
backgroundColor: '#fff',
style: {
color: '#000',
fontSize: '15px',
padding: 10
},
formatter: function (params) {
// console.log(params)
var tips = ''
tips += '时刻:' + params[0].data[0] + '</br/>'
for (var i = 0; i < params.length; i++) {
if (params[i].seriesName != '暂降触发点') {
tips += params[i].seriesName + ':' + params[i].value[1] + '<br/>'
}
}
return tips
},
// axisPointer: {
// type: "cross",
// label: {
// color: "#fff",
// fontSize: 16,
// },
// },
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0
},
title: {
left: 'center',
text: '发生时刻:' + this.boxoList.startTime + ' PT变化:' + this.boxoList.pt,
textStyle: {
fontSize: 16,
color: _this.DColor ? '#fff' : echartsColor.WordColor
}
},
legend: {
left: '5%',
top: '20',
verticalAlign: 'top',
enabled: true,
itemDistance: 5,
textStyle: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
rich: {
a: {
verticalAlign: 'middle'
}
},
padding: [2, 0, 0, 0] //[上、右、下、左]
}
},
toolbox: {
show: false,
feature: {
//restore: {},
saveAsImage: {
iconStyle: {
borderColor: _this.DColor ? '#fff' : echartsColor.WordColor
}
}
}
},
xAxis: {
type: 'value',
name: '时刻',
boundaryGap: false,
min: this.GJList.smp_x[0],
max: this.GJList.smp_x[this.GJList.smp_x.length - 1] + 1,
title: {
text: 'ms',
textStyle: {
fontSize: 12,
color: _this.DColor ? '#fff' : echartsColor.WordColor
},
enabled: true,
align: 'high'
},
splitLine: {
show: false
},
axisTick: {
alignWithLabel: true
},
axisLine: {
lineStyle: {
color: _this.DColor ? '#fff' : echartsColor.thread
},
onZero: false //-----------重点
},
axisLabel: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value, index) {
if (_this.valA != (value - 0).toFixed(0)) {
_this.valA = (value - 0).toFixed(0)
return (value - 0).toFixed(0)
}
}
//rotate:39
}
// data: this.syncExtremes,
},
yAxis: {
type: 'value',
name: 'kV',
title: {
align: 'high',
offset: 0,
text: 'kV',
rotation: 0,
y: -10
},
boundaryGap: [0, '100%'],
showLastLabel: true,
max: (max + 10).toFixed(2),
min: (min - 10).toFixed(2),
opposite: false,
nameTextStyle: {
color: _this.DColor ? '#fff' : echartsColor.WordColor
},
//minInterval: 1,
type: 'value',
axisLine: {
show: true,
lineStyle: {
color: _this.DColor ? '#fff' : echartsColor.thread
},
onZero: false //-----------重点
},
axisLabel: {
color: _this.DColor ? '#fff' : echartsColor.WordColor,
formatter: function (value, index) {
return (value - 0).toFixed(2)
}
},
splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: [_this.DColor ? '#fff' : echartsColor.thread],
type: 'dashed',
opacity: 0.5
}
}
},
grid: {
left: '1%',
right: '40px',
bottom: '40px',
top: '55px',
containLabel: true
},
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100
},
{
start: 0,
height: 13,
bottom: '20px',
end: 100
}
],
series: [
{
name: '跳变期',
type: 'line',
data: [],
showSymbol: true, // 强制显示标记
symbol: 'rect', // 标记形状为方块
symbolSize: 10, // 方块大小
itemStyle: {
color: '#888888', // 方块颜色为灰色
borderWidth: 0
},
markArea: {
silent: true, // 不响应交互
itemStyle: { color: '#ccc' },
data: [
[
{ xAxis: '0' }, // 第一个跳变期起始
{ xAxis: '5' } // 第一个跳变期结束
],
[
{ xAxis: '210' }, // 第二个跳变期起始
{ xAxis: '220' } // 第二个跳变期结束
]
]
}
},
{
name: 'A相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#DAA520'
},
data: adata
},
{
name: 'B相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#2E8B57'
},
data: bdata
},
{
name: 'C相',
type: 'line',
smooth: true,
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: '#A52a2a'
},
data: cdata
},
{
name: '暂降触发点',
type: 'scatter',
symbol: 'image://' + url,
itemStyle: {
width: 16,
height: 16
},
data: [[0, min]]
}
]
}
myChartes.setOption(option)
// window.echartsArr.push(myChartes)
setTimeout(() => {
myChartes.resize()
this.loading = false
}, 400)
//第一个波形图数据绘制完毕后,绘制后续的波形图
// let waveDatasTemp = waveDatas.slice(1);
// waveDatasTemp.reverse();
}
}
}
</script>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -16,18 +16,12 @@
:value="item.value"
></el-option>
</el-select>
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary"
@click="AdvancedAnalytics">高级分析</el-button> -->
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics">
高级分析
</el-button> -->
</el-col>
<el-col :span="12">
<el-button
@click="backbxlb"
class="el-icon-refresh-right"
icon="el-icon-Back"
style="float: right"
>
返回
</el-button>
<el-button @click="backbxlb" icon="el-icon-Back" style="float: right">返回</el-button>
</el-col>
</el-row>
<div v-loading="loading" style="height: calc(100vh - 190px)">
@@ -108,12 +102,12 @@ const options = ref([
const shushiboxiRef = ref()
const bxecharts = ref(mainHeight(95).height as any)
const view2 = ref(true)
const boxoList = ref(null)
const boxoList: any = ref(null)
const wp = ref(null)
const showBoxi = ref(true)
const view3 = ref(false)
const view4 = ref(false)
const GJList = ref([])
const GJList = ref({})
const open = async (row: any) => {
loading.value = true
@@ -122,6 +116,7 @@ const open = async (row: any) => {
row.loading = false
if (res != undefined) {
boxoList.value = row
boxoList.value.pt = res.data.pt
wp.value = res.data
loading.value = false
view4.value = true
@@ -129,6 +124,7 @@ const open = async (row: any) => {
})
.catch(() => {
loading.value = false
backbxlb()
})
}
const bxhandleClick = (tab: any) => {
@@ -168,10 +164,13 @@ const AdvancedAnalytics = () => {
analysis({
eventIndex: boxoList.value.eventId
}).then(res => {
GJList.value = res.data
view3.value = true
view2.value = false
// GJList.value = res.data
// view3.value = true
// view2.value = false
})
GJList.value = {}
view3.value = true
view2.value = false
}
const changeView = () => {
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()

View File

@@ -127,7 +127,7 @@ const timeChange = (e: number) => {
// 当前
const nowTime = () => {
console.log(interval.value, '000000000')
//console.log(interval.value, '000000000')
timeChange(interval.value)
}
// 上一个
@@ -312,7 +312,7 @@ const next = () => {
}
} else {
month = month + 3
console.log('🚀 ~ next ~ presentM:', presentM, month)
// console.log('🚀 ~ next ~ presentM:', presentM, month)
// 季度进位后,超过当前月份是不科学的
if (year == presentY && !props.nextFlag) {
@@ -327,7 +327,7 @@ const next = () => {
endTime = year + '-0' + presentM + '-' + presentD
}
} else if (presentM > 3 && presentM < 7) {
console.log(123123)
// console.log(123123)
// 第二季度
startTime = year + '-04-01'
if (presentD < 10) {
@@ -380,7 +380,7 @@ const next = () => {
}
}
}
console.log(startTime, endTime)
// console.log(startTime, endTime)
} else if (interval.value == 5) {
} else if (interval.value == 4) {
//根据开始时间推

View File

@@ -1,29 +1,20 @@
<template>
<div ref="tableHeader" class="cn-table-header">
<div class="table-header ba-scroll-style">
<el-form
style="flex: 1; height: 32px; display: flex; flex-wrap: wrap"
ref="headerForm"
@submit.prevent=""
@keyup.enter="onComSearch"
label-position="left"
:inline="true"
>
<el-form style="flex: 1; height: 32px; display: flex; flex-wrap: wrap" ref="headerForm" @submit.prevent=""
@keyup.enter="onComSearch" label-position="left" :inline="true">
<el-form-item v-if="datePicker" style="grid-column: span 2; max-width: 630px">
<template #label>
<el-checkbox v-if="showTimeAll" v-model="timeAll" label="统计时间" />
<span v-else>{{ dateLabel }}</span>
</template>
<DatePicker
ref="datePickerRef"
v-if="timeAll"
:nextFlag="nextFlag"
:theCurrentTime="theCurrentTime"
></DatePicker>
<DatePicker ref="datePickerRef" v-if="timeAll" :nextFlag="nextFlag"
:theCurrentTime="theCurrentTime"></DatePicker>
</el-form-item>
<el-form-item label="区域" v-if="area">
<Area ref="areaRef" v-model="tableStore.table.params.deptIndex" />
<Area ref="areaRef" v-model="tableStore.table.params.deptIndex" @change-value="onAreaChange"
style="width: 200px;" />
</el-form-item>
<slot name="select"></slot>
</el-form>
@@ -32,43 +23,24 @@
<Icon size="14" name="el-icon-ArrowUp" style="color: #fff" v-if="showSelect" />
<Icon size="14" name="el-icon-ArrowDown" style="color: #fff" v-else />
</el-button>
<el-button
@click="onComSearch"
v-if="showSearch"
:loading="tableStore.table.loading"
type="primary"
:icon="Search"
>
<el-button @click="onComSearch" v-if="showSearch" :loading="tableStore.table.loading" type="primary"
:icon="Search">
查询
</el-button>
<el-button
@click="onResetForm"
v-if="showSearch && showReset"
:loading="tableStore.table.loading"
:icon="RefreshLeft"
>
<el-button @click="onResetForm" v-if="showSearch && showReset" :loading="tableStore.table.loading"
:icon="RefreshLeft">
重置
</el-button>
<el-button
@click="onExport"
v-if="showExport"
:loading="tableStore.table.loading"
type="primary"
icon="el-icon-Download"
>
<el-button @click="onExport" v-if="showExport" :loading="tableStore.table.exportLoading" type="primary"
icon="el-icon-Download">
导出
</el-button>
</template>
<slot name="operation"></slot>
</div>
<el-form
:style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose"
ref="headerFormSecond"
@submit.prevent=""
@keyup.enter="onComSearch"
label-position="left"
:inline="true"
></el-form>
<el-form :style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose"
ref="headerFormSecond" @submit.prevent="" @keyup.enter="onComSearch" label-position="left"
:inline="true"></el-form>
</div>
</template>
@@ -81,7 +53,7 @@ import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
import { Search, RefreshLeft } from '@element-plus/icons-vue'
import { defineProps } from 'vue'
const emit = defineEmits(['selectChange'])
const emit = defineEmits(['selectChange', 'areaChange'])
const tableStore = inject('tableStore') as TableStore
const tableHeader = ref()
const datePickerRef = ref()
@@ -132,6 +104,10 @@ const headerFormSecondStyleClose = {
padding: '0'
}
const onAreaChange = data => {
emit('areaChange', { label: data.label })
}
watch(
() => tableStore?.table.params.deptIndex,
newVal => {
@@ -232,14 +208,14 @@ const onResetForm = () => {
//时间重置成默认值
datePickerRef.value?.setTheDate(3)
if(props.showTimeAll){
timeAll.value = false
delete tableStore.table.params.searchBeginTime
delete tableStore.table.params.searchEndTime
delete tableStore.table.params.startTime
delete tableStore.table.params.endTime
delete tableStore.table.params.timeFlag
delete tableStore.table.params.interval
if (props.showTimeAll) {
timeAll.value = false
delete tableStore.table.params.searchBeginTime
delete tableStore.table.params.searchEndTime
delete tableStore.table.params.startTime
delete tableStore.table.params.endTime
delete tableStore.table.params.timeFlag
delete tableStore.table.params.interval
}
if (props.datePicker && timeAll.value) {
@@ -258,7 +234,6 @@ const setTheDate = (val: any) => {
}
// 导出
const onExport = () => {
console.log('222')
tableStore.onTableAction('export', { showAllFlag: true })
}
@@ -294,6 +269,7 @@ defineExpose({
padding: 13px 15px;
font-size: 14px;
overflow: hidden;
.table-header-operate-text {
margin-left: 6px;
}
@@ -321,7 +297,7 @@ defineExpose({
margin-left: 12px;
}
.mlr-12 + .el-button {
.mlr-12+.el-button {
margin-left: 12px;
}
@@ -356,7 +332,7 @@ defineExpose({
border-radius: 0;
}
.el-button + .el-button {
.el-button+.el-button {
margin: 0;
}
@@ -367,6 +343,7 @@ defineExpose({
html.dark {
.table-search-button-group {
button:focus,
button:active {
background-color: var(--el-color-info-dark-2);

View File

@@ -0,0 +1,187 @@
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="transition: all 0.3s; overflow: hidden">
<div class="mt15 mr10" style="display: flex; justify-content: end">
<el-button type="primary" icon="el-icon-Select" @click="save" :loading="loading">保存</el-button>
</div>
<Icon
v-show="menuCollapse"
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
<el-tooltip placement="bottom" :hide-after="0" v-if="props.showPush">
<template #content>
<span>台账推送</span>
</template>
<Icon
name="el-icon-Promotion"
size="20"
class="fold ml10 menu-collapse"
style="cursor: pointer"
:style="{ color: config.getColorVal('elementUiPrimary') }"
@click="onAdd"
/>
</el-tooltip>
<!-- <Icon @click='onMenuCollapse' :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" v-else
:class="menuCollapse ? 'unfold' : ''" size='18' class='fold ml10 menu-collapse'
style='cursor: pointer' v-if='props.canExpand' /> -->
</div>
<el-tree
:style="{ height: 'calc(100vh - 235px)' }"
style="overflow: auto"
ref="treeRef"
:props="defaultProps"
highlight-current
:default-expand-all="false"
@check-change="checkTreeNodeChange"
:filter-node-method="filterNode"
node-key="id"
v-bind="$attrs"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</div>
</template>
<script lang="ts" setup>
import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus'
import { emit } from 'process'
import { ref, watch } from 'vue'
import { t } from 'vxe-table'
import { useConfig } from '@/stores/config'
defineOptions({
name: 'govern/tree'
})
interface Props {
width?: string
canExpand?: boolean
showPush?: boolean
}
const loading = ref(false)
const props = withDefaults(defineProps<Props>(), {
width: '280px',
canExpand: true,
showPush: false
})
const config = useConfig()
const { proxy } = useCurrentInstance()
const menuCollapse = ref(false)
const filterText = ref('')
const defaultProps = {
label: 'name',
value: 'id'
}
const emit = defineEmits(['checkTreeNodeChange', 'onAdd', 'checkChange'])
watch(filterText, val => {
treeRef.value!.filter(val)
})
const onMenuCollapse = () => {
menuCollapse.value = !menuCollapse.value
proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
}
const save = () => {
loading.value = true
emit('checkChange')
}
const filterNode = (value: string, data: any, node: any) => {
console.log(value, data, node, 'filterNode')
if (!value) return true
// return data.name.includes(value)
if (data.name) {
return chooseNode(value, data, node)
}
}
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
return true
}
const level = node.level
// 如果传入的节点本身就是一级节点就不用校验了
if (level === 1) {
return false
}
// 先取当前节点的父节点
let parentData = node.parent
// 遍历当前节点的父节点
let index = 0
while (index < level - 1) {
// 如果匹配到直接返回此处name值是中文字符enName是英文字符。判断匹配中英文过滤
if (parentData.data.name.indexOf(value) !== -1) {
return true
}
// 否则的话再往上一层做匹配
parentData = parentData.parent
index++
}
// 没匹配到返回false
return false
}
const checkTreeNodeChange = () => {
// console.log(treeRef.value?.getCheckedNodes(), "ikkkkkiisiiisis");
emit('checkTreeNodeChange', treeRef.value?.getCheckedNodes())
}
const onAdd = () => {
emit('onAdd')
}
const treeRef = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef, loading })
</script>
<style lang="scss" scoped>
.cn-tree {
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
height: 100%;
width: 100%;
:deep(.el-tree) {
border: 1px solid var(--el-border-color);
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
.menu-collapse {
color: var(--el-color-primary);
}
}
.custom-tree-node {
display: flex;
align-items: center;
}
</style>

View File

@@ -22,7 +22,7 @@
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
</el-input>
<Icon
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
@@ -147,7 +147,7 @@ const onMenuCollapse = () => {
}
// 查看详情
const viewDetails = (data: any) => {
console.log('🚀 ~ viewDetails ~ data:', data)
// console.log('🚀 ~ viewDetails ~ data:', data)
if (data.level == 3) {
// 变电站详情
// substationDetails
@@ -201,7 +201,7 @@ onMounted(async () => {
})
const scrollToNode = (id: string) => {
console.log("🚀 ~ scrollToNode ~ id:", id)
// console.log("🚀 ~ scrollToNode ~ id:", id)
if (!treeRef.value) return
// 获取目标节点的元素

View File

@@ -28,66 +28,66 @@ const info = (id: any) => {
expanded.value = [id]
getTerminalTree().then(res => {
// let arr: any[] = []
if (VITE_FLAG) {
res.data.forEach((item: any) => {
item.icon = 'el-icon-Menu'
item.plevel = item.level
item.level = 0
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-HomeFilled'
// if (VITE_FLAG) {
// res.data.forEach((item: any) => {
// item.icon = 'el-icon-Menu'
// item.plevel = item.level
// item.level = 0
// item.children.forEach((item2: any) => {
// item2.icon = 'el-icon-HomeFilled'
item2.plevel = item2.level
item2.level = 100
expanded.value.push(item2.id)
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-CollectionTag'
item3.plevel = item3.level
item3.level = 200
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Flag'
item4.plevel = item4.level
item4.level = 300
// arr.push(item4)
item4.children.forEach((item5: any) => {
item5.icon = 'el-icon-OfficeBuilding'
item5.plevel = item5.level
item5.level = 300
// item5.id = item4.id
item5.children.forEach((item6: any) => {
item6.icon = 'el-icon-HelpFilled'
item6.plevel = 4
if (item6.name == '电网侧' && item6.children.length == 0) {
item6.level = 400
} else {
item6.level = 400
}
item6.children.forEach((item7: any) => {
item7.icon = 'el-icon-Film'
item7.plevel = item7.level
item7.level = 400
item7.children.forEach((item8: any) => {
item8.icon = 'el-icon-Collection'
item8.plevel = item8.level
item8.level = 500
item8.children.forEach((item9: any) => {
item9.icon = 'el-icon-Share'
item9.plevel = item9.level
item9.level = 600
item9.children.forEach((item10: any) => {
item10.icon = 'el-icon-Location'
item10.plevel = item10.level
item10.level = 700
})
})
})
})
})
})
})
})
})
})
} else {
// item2.plevel = item2.level
// item2.level = 100
// expanded.value.push(item2.id)
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-CollectionTag'
// item3.plevel = item3.level
// item3.level = 200
// item3.children.forEach((item4: any) => {
// item4.icon = 'el-icon-Flag'
// item4.plevel = item4.level
// item4.level = 300
// // arr.push(item4)
// item4.children.forEach((item5: any) => {
// item5.icon = 'el-icon-OfficeBuilding'
// item5.plevel = item5.level
// item5.level = 300
// // item5.id = item4.id
// item5.children.forEach((item6: any) => {
// item6.icon = 'el-icon-HelpFilled'
// item6.plevel = 4
// if (item6.name == '电网侧' && item6.children.length == 0) {
// item6.level = 400
// } else {
// item6.level = 400
// }
// item6.children.forEach((item7: any) => {
// item7.icon = 'el-icon-Film'
// item7.plevel = item7.level
// item7.level = 400
// item7.children.forEach((item8: any) => {
// item8.icon = 'el-icon-Collection'
// item8.plevel = item8.level
// item8.level = 500
// item8.children.forEach((item9: any) => {
// item9.icon = 'el-icon-Share'
// item9.plevel = item9.level
// item9.level = 600
// item9.children.forEach((item10: any) => {
// item10.icon = 'el-icon-Location'
// item10.plevel = item10.level
// item10.level = 700
// })
// })
// })
// })
// })
// })
// })
// })
// })
// })
// } else {
res.data.forEach((item: any) => {
item.icon = 'el-icon-Menu'
item.plevel = item.level
@@ -129,7 +129,7 @@ const info = (id: any) => {
})
})
})
}
// }
tree.value = res.data

View File

@@ -19,7 +19,6 @@ import { nextTick, onMounted, ref, useAttrs } from 'vue'
import Tree from '../index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useDictData } from '@/stores/dictData'
import { getTerminalTreeForFive } from '@/api/device-boot/terminalTree'
import { useConfig } from '@/stores/config'
import { queryAllAlgorithmLibrary } from '@/api/supervision-boot/database/index'
defineOptions({
@@ -35,7 +34,7 @@ const tree = ref()
const treeRef = ref()
const loadData = (id?: any) => {
console.log('🚀 ~ loadData ~ id:', id)
// console.log('🚀 ~ loadData ~ id:', id)
let nodeKey = ''
queryAllAlgorithmLibrary().then(res => {
res.data.forEach((item: any) => {

View File

@@ -0,0 +1,150 @@
<template>
<div class="point-tree">
<div style="flex: 1; overflow: hidden">
<Tree ref="treeRef" :data="tree" style="width: 100%; height: 100%" :canExpand="false" v-bind="$attrs" />
</div>
</div>
</template>
<script lang="ts" setup>
import { nextTick, onMounted, ref, useAttrs } from 'vue'
import Tree from '../index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useDictData } from '@/stores/dictData'
import { getTerminalTreeForFive } from '@/api/device-boot/terminalTree'
import { useConfig } from '@/stores/config'
import { getAreaList } from '@/api/common'
const VITE_FLAG = import.meta.env.VITE_NAME == 'qujing'
defineOptions({
name: 'pms/pointTree'
})
interface Props {
showSelect?: boolean
}
const props = withDefaults(defineProps<Props>(), {
showSelect: true
})
const emit = defineEmits(['init'])
const attrs = useAttrs()
const adminInfo = useAdminInfo()
const dictData = useDictData()
const config = useConfig()
const tree = ref()
const treeRef = ref()
const loadData = () => {
let nodeKey = ''
getAreaList().then(res => {
processTreeData(res.data, res.data[0].level)
let firstLevel6Node = getDeepestFirstChildData(res.data)
nodeKey = firstLevel6Node.id
emit('init', firstLevel6Node)
tree.value = res.data
if (nodeKey) {
nextTick(() => {
treeRef.value.treeRef.setCurrentKey(nodeKey)
// treeRef.value.treeRef.setExpandedKeys(nodeKey)
})
}
})
}
const scrollToNode = (id: string) => {
// 树滚动
treeRef.value.scrollToNode(id)
}
// 定义不同层级对应的图标配置(可根据实际需求调整)
const levelIconMap = {
'-1': 'el-icon-HomeFilled',
0: 'el-icon-CollectionTag',
1: 'el-icon-CollectionTag',
2: 'el-icon-Flag',
3: 'el-icon-OfficeBuilding',
4: 'el-icon-DataAnalysis',
5: 'el-icon-DataAnalysis',
7: 'el-icon-DataAnalysis',
6: 'fa-solid fa-location-dot'
}
/**
* 递归处理树形数据,为不同层级节点设置图标和颜色
* @param data 树形数据数组
* @param level 当前层级默认从1开始
*/
function processTreeData(data: any[], level: number = -1, alias: string = '') {
// 空值判断避免数组为空或undefined时报错
if (!Array.isArray(data) || data.length === 0) return
data.forEach(item => {
// 1. 设置基础图标(根据层级匹配)
item.icon = levelIconMap[level] || ''
item.alias = alias + `${item.name}`
// 2. 设置基础颜色
item.color = config.getColorVal('elementUiPrimary')
// 3. 第6层特殊处理根据comFlag调整颜色
if (level === 6 && item.hasOwnProperty('comFlag')) {
switch (item.comFlag) {
case 0:
item.color = 'red !important'
break
case 1:
item.color = '#00f93b !important'
break
case 2:
item.color = '#8c8c8c !important'
break
// 默认值:保持原有基础颜色
default:
item.color = config.getColorVal('elementUiPrimary')
}
}
// 4. 递归处理子节点,层级+1
if (item.children && item.children.length > 0) {
processTreeData(item.children, item.children[0].level, level == '-1' ? '' : item.alias + '>')
}
})
}
/**
* 递归获取树形结构中一直向下的第一个children的最后一组有效数据
* @param {Array} treeData - 原始递归树形数据
* @returns {Object|null} 路径最后一组有效数据无有效数据时返回null
*/
function getDeepestFirstChildData(treeData) {
// 递归辅助函数逐层查找第一个children
function findDeepestNode(currentNode) {
// 检查当前节点是否有有效的children数组
if (currentNode && Array.isArray(currentNode.children) && currentNode.children.length > 0) {
// 有下一级children继续递归查找下一级第一个元素
return findDeepestNode(currentNode.children[0])
}
// 没有下一级children返回当前节点递归终止
return currentNode
}
// 边界处理:原始数据非数组/空数组时返回null
if (!Array.isArray(treeData) || treeData.length === 0) {
return null
}
// 从根节点第一个元素开始递归查找
return findDeepestNode(treeData[0])
}
defineExpose({ treeRef, scrollToNode, tree })
loadData()
</script>
<style lang="scss">
.point-tree {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
background: #fff;
border: 1px solid var(--el-border-color);
}
</style>

View File

@@ -11,7 +11,6 @@ import { nextTick, onMounted, ref, useAttrs } from 'vue'
import Tree from '../index.vue'
import { useAdminInfo } from '@/stores/adminInfo'
import { useDictData } from '@/stores/dictData'
import { getTerminalTreeForFive } from '@/api/device-boot/terminalTree'
import { useConfig } from '@/stores/config'
import { defineProps } from 'vue'
import { getTree } from '@/api/advance-boot/assess'

View File

@@ -36,6 +36,7 @@ const adminInfo = useAdminInfo()
const dictData = useDictData()
const config = useConfig()
const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Type'])
const VITE_FLAG = import.meta.env.VITE_NAME == 'qujing'
const tree = ref()
const treeRef = ref()
const formData = ref({
@@ -54,6 +55,9 @@ const loadData = () => {
}) || { code: '' }
let form = JSON.parse(JSON.stringify(formData.value))
form.statisticalType = classificationData.find((item: any) => item.id == form.statisticalType)
if (VITE_FLAG && form.statisticalType.code == 'Power_Network') {
form.statisticalType.deptName = 'qujing'
}
let nodeKey = ''
getTerminalTreeForFive(form).then(res => {
console.log(res)
@@ -67,56 +71,62 @@ const loadData = () => {
}
]
}
res.data.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-CollectionTag'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Flag'
item3.color = config.getColorVal('elementUiPrimary')
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-OfficeBuilding'
item4.color = config.getColorVal('elementUiPrimary')
item4.children.forEach((item5: anyObj) => {
if (item5.level == 7) {
item5.icon = 'el-icon-DataAnalysis'
item5.color = config.getColorVal('elementUiPrimary')
item5.children.forEach((item6: anyObj) => {
item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`
item6.pid = item4.id
item6.icon = 'fa-solid fa-location-dot'
item6.color = config.getColorVal('elementUiPrimary')
if (item6.comFlag == 0) {
item6.color = 'red !important'
} else if (item6.comFlag == 1) {
item6.color = '#00f93b !important'
} else if (item6.comFlag == 2) {
item6.color = '#8c8c8c !important'
}
})
} else {
item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`
item5.pid = item4.id
item5.icon = 'fa-solid fa-location-dot'
item5.color = config.getColorVal('elementUiPrimary')
if (item5.comFlag == 0) {
item5.color = 'red !important'
} else if (item5.comFlag == 1) {
item5.color = '#00f93b !important'
} else if (item5.comFlag == 2) {
item5.color = '#8c8c8c !important'
}
}
})
})
})
})
})
// if (VITE_FLAG) {
processTreeData(res.data)
let firstLevel6Node = findFirstLevel6Node(res.data)
nodeKey = res.data[0].children[0].children[0].children[0].children[0].id
emit('init', res.data[0].children[0].children[0].children[0].children[0])
nodeKey = firstLevel6Node.id
emit('init', firstLevel6Node)
// res.data.forEach((item: any) => {
// item.icon = 'el-icon-HomeFilled'
// item.color = config.getColorVal('elementUiPrimary')
// item.children.forEach((item2: any) => {
// item2.icon = 'el-icon-CollectionTag'
// item2.color = config.getColorVal('elementUiPrimary')
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Flag'
// item3.color = config.getColorVal('elementUiPrimary')
// item3.children.forEach((item4: any) => {
// item4.icon = 'el-icon-OfficeBuilding'
// item4.color = config.getColorVal('elementUiPrimary')
// item4.children.forEach((item5: anyObj) => {
// if (item5.level == 7) {
// item5.icon = 'el-icon-DataAnalysis'
// item5.color = config.getColorVal('elementUiPrimary')
// item5.children.forEach((item6: anyObj) => {
// item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`
// item6.pid = item4.id
// item6.icon = 'fa-solid fa-location-dot'
// item6.color = config.getColorVal('elementUiPrimary')
// if (item6.comFlag == 0) {
// item6.color = 'red !important'
// } else if (item6.comFlag == 1) {
// item6.color = '#00f93b !important'
// } else if (item6.comFlag == 2) {
// item6.color = '#8c8c8c !important'
// }
// })
// } else {
// item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`
// item5.pid = item4.id
// item5.icon = 'fa-solid fa-location-dot'
// item5.color = config.getColorVal('elementUiPrimary')
// if (item5.comFlag == 0) {
// item5.color = 'red !important'
// } else if (item5.comFlag == 1) {
// item5.color = '#00f93b !important'
// } else if (item5.comFlag == 2) {
// item5.color = '#8c8c8c !important'
// }
// }
// })
// })
// })
// })
// })
// nodeKey = res.data[0].children[0].children[0].children[0].children[0].id
// emit('init', res.data[0].children[0].children[0].children[0].children[0])
tree.value = res.data
if (nodeKey) {
@@ -127,9 +137,113 @@ const loadData = () => {
}
})
}
const setKey = (key: string) => {
treeRef.value.treeRef.setCurrentKey(key)
}
// 定义不同层级对应的图标配置(可根据实际需求调整)
const levelIconMap = {
'-1': 'el-icon-HomeFilled',
0: 'el-icon-CollectionTag',
1: 'el-icon-CollectionTag',
2: 'el-icon-Flag',
3: 'el-icon-OfficeBuilding',
4: 'el-icon-DataAnalysis',
5: 'el-icon-DataAnalysis',
7: 'el-icon-DataAnalysis',
6: 'fa-solid fa-location-dot'
}
/**
* 递归处理树形数据,为不同层级节点设置图标和颜色
* @param data 树形数据数组
* @param level 当前层级默认从1开始
*/
function processTreeData(data: any[], level: number = -1) {
// 空值判断避免数组为空或undefined时报错
if (!Array.isArray(data) || data.length === 0) return
data.forEach(item => {
// 1. 设置基础图标(根据层级匹配)
item.icon = levelIconMap[level] || ''
// 2. 设置基础颜色
item.color = config.getColorVal('elementUiPrimary')
// 3. 第6层特殊处理根据comFlag调整颜色
if (level === 6 && item.hasOwnProperty('comFlag')) {
switch (item.comFlag) {
case 0:
item.color = 'red !important'
break
case 1:
item.color = '#00f93b !important'
break
case 2:
item.color = '#8c8c8c !important'
break
// 默认值:保持原有基础颜色
default:
item.color = config.getColorVal('elementUiPrimary')
}
}
// 4. 递归处理子节点,层级+1
if (item.children && item.children.length > 0) {
processTreeData(item.children, item.children[0].level)
}
})
}
/**
* 递归查找树形结构中第一个level===6的节点找到即终止递归
* @param {Object|Array} tree - 树形数据(根节点数组 或 单个根节点)
* @returns {Object|null} 第一个level为6的节点无则返回null
*/
function findFirstLevel6Node(tree: any) {
// 统一处理入参:如果是数组,遍历根节点数组(按顺序找第一个符合条件的)
if (Array.isArray(tree)) {
for (const rootNode of tree) {
const result = traverse(rootNode)
// 找到第一个匹配节点,立即返回(终止根节点遍历)
if (result) return result
}
// 所有根节点遍历完未找到
return null
} else {
// 入参是单个节点,直接递归遍历
return traverse(tree)
}
// 核心递归遍历函数
function traverse(node) {
// 终止条件1节点不存在返回null
if (!node) return null
// 终止条件2找到level===6的节点立即返回终止递归
if (node.level === 6) {
return node
}
// 终止条件3节点无children返回null
if (!node.children || node.children.length === 0) {
return null
}
// 按顺序遍历当前节点的子节点
for (const child of node.children) {
const foundNode = traverse(child)
// 子节点中找到目标节点,立即返回(终止后续子节点遍历)
if (foundNode) {
return foundNode
}
}
// 当前节点及所有子节点都无匹配返回null
return null
}
}
defineExpose({ setKey })
loadData()
</script>

View File

@@ -11,7 +11,7 @@
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<el-input v-model="filterText" placeholder="请输入内容" clearable>
<el-input v-model="filterText" placeholder="请输入内容" maxlength="10" show-word-limit clearable>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>

View File

@@ -28,6 +28,7 @@ import { useDictData } from '@/stores/dictData'
import { getTerminalTreeForFive } from '@/api/device-boot/terminalTree'
import { useConfig } from '@/stores/config'
import { defineProps } from 'vue'
const VITE_FLAG = import.meta.env.VITE_NAME == 'qujing'
defineOptions({
name: 'pms/pointTree'
})
@@ -61,6 +62,9 @@ const loadData = () => {
}) || { code: '' }
let form = JSON.parse(JSON.stringify(formData.value))
form.statisticalType = classificationData.find((item: any) => item.id == form.statisticalType)
if (VITE_FLAG && form.statisticalType.code == 'Power_Network') {
form.statisticalType.deptName = 'qujing'
}
let nodeKey = ''
getTerminalTreeForFive(form).then(res => {
//console.log('---',res)
@@ -74,62 +78,71 @@ const loadData = () => {
}
]
}
res.data.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-CollectionTag'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Flag'
item3.color = config.getColorVal('elementUiPrimary')
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-OfficeBuilding'
item4.color = config.getColorVal('elementUiPrimary')
item4.children.forEach((item5: anyObj) => {
if (item5.level == 7) {
item5.icon = 'el-icon-DataAnalysis'
item5.color = config.getColorVal('elementUiPrimary')
item5.children.forEach((item6: anyObj) => {
item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`
item6.pid = item4.id
item6.icon = 'fa-solid fa-location-dot'
item6.color = config.getColorVal('elementUiPrimary')
if (item6.comFlag == 0) {
item6.color = 'red !important'
} else if (item6.comFlag == 1) {
item6.color = '#00f93b !important'
} else if (item6.comFlag == 2) {
item6.color = '#8c8c8c !important'
}
})
} else {
item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`
item5.pid = item4.id
item5.icon = 'fa-solid fa-location-dot'
item5.color = config.getColorVal('elementUiPrimary')
if (item5.comFlag == 0) {
item5.color = 'red !important'
} else if (item5.comFlag == 1) {
item5.color = '#00f93b !important'
} else if (item5.comFlag == 2) {
item5.color = '#8c8c8c !important'
}
}
})
})
})
})
})
// if (VITE_FLAG) {
processTreeData(res.data)
let firstLevel6Node = findFirstLevel6Node(res.data)
nodeKey =
res.data[0].children[0].children[0].children[0].children[0].children[0]?.id ||
res.data[0].children[0].children[0].children[0].children[0]?.id
emit(
'init',
res.data[0].children[0].children[0].children[0].children[0]?.children[0] ||
res.data[0].children[0].children[0].children[0].children[0]
)
nodeKey = firstLevel6Node.id
emit('init', firstLevel6Node)
// } else {
// // 正常树处理
// res.data.forEach((item: any) => {
// item.icon = 'el-icon-HomeFilled'
// item.color = config.getColorVal('elementUiPrimary')
// item.children.forEach((item2: any) => {
// item2.icon = 'el-icon-CollectionTag'
// item2.color = config.getColorVal('elementUiPrimary')
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Flag'
// item3.color = config.getColorVal('elementUiPrimary')
// item3.children.forEach((item4: any) => {
// item4.icon = 'el-icon-OfficeBuilding'
// item4.color = config.getColorVal('elementUiPrimary')
// item4.children.forEach((item5: anyObj) => {
// if (item5.level == 7) {
// item5.icon = 'el-icon-DataAnalysis'
// item5.color = config.getColorVal('elementUiPrimary')
// item5.children.forEach((item6: anyObj) => {
// item6.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}>${item6.name}`
// item6.pid = item4.id
// item6.icon = 'fa-solid fa-location-dot'
// item6.color = config.getColorVal('elementUiPrimary')
// if (item6.comFlag == 0) {
// item6.color = 'red !important'
// } else if (item6.comFlag == 1) {
// item6.color = '#00f93b !important'
// } else if (item6.comFlag == 2) {
// item6.color = '#8c8c8c !important'
// }
// })
// } else {
// item5.alias = `${item.name}>${item2.name}>${item3.name}>${item4.name}>${item5.name}`
// item5.pid = item4.id
// item5.icon = 'fa-solid fa-location-dot'
// item5.color = config.getColorVal('elementUiPrimary')
// if (item5.comFlag == 0) {
// item5.color = 'red !important'
// } else if (item5.comFlag == 1) {
// item5.color = '#00f93b !important'
// } else if (item5.comFlag == 2) {
// item5.color = '#8c8c8c !important'
// }
// }
// })
// })
// })
// })
// })
// nodeKey =
// res.data[0].children[0].children[0].children[0].children[0].children[0]?.id ||
// res.data[0].children[0].children[0].children[0].children[0]?.id
// emit(
// 'init',
// res.data[0].children[0].children[0].children[0].children[0]?.children[0] ||
// res.data[0].children[0].children[0].children[0].children[0]
// )
// }
tree.value = res.data
if (nodeKey) {
@@ -145,6 +158,109 @@ const scrollToNode = (id: string) => {
// 树滚动
treeRef.value.scrollToNode(id)
}
// 定义不同层级对应的图标配置(可根据实际需求调整)
const levelIconMap = {
'-1': 'el-icon-HomeFilled',
0: 'el-icon-CollectionTag',
1: 'el-icon-CollectionTag',
2: 'el-icon-Flag',
3: 'el-icon-OfficeBuilding',
4: 'el-icon-DataAnalysis',
5: 'el-icon-DataAnalysis',
7: 'el-icon-DataAnalysis',
6: 'fa-solid fa-location-dot'
}
/**
* 递归处理树形数据,为不同层级节点设置图标和颜色
* @param data 树形数据数组
* @param level 当前层级默认从1开始
*/
function processTreeData(data: any[], level: number = -1, alias: string = '') {
// 空值判断避免数组为空或undefined时报错
if (!Array.isArray(data) || data.length === 0) return
data.forEach(item => {
// 1. 设置基础图标(根据层级匹配)
item.icon = levelIconMap[level] || ''
item.alias = alias + `${item.name}`
// 2. 设置基础颜色
item.color = config.getColorVal('elementUiPrimary')
// 3. 第6层特殊处理根据comFlag调整颜色
if (level === 6 && item.hasOwnProperty('comFlag')) {
switch (item.comFlag) {
case 0:
item.color = 'red !important'
break
case 1:
item.color = '#00f93b !important'
break
case 2:
item.color = '#8c8c8c !important'
break
// 默认值:保持原有基础颜色
default:
item.color = config.getColorVal('elementUiPrimary')
}
}
// 4. 递归处理子节点,层级+1
if (item.children && item.children.length > 0) {
processTreeData(item.children, item.children[0].level, level == '-1' ? '' : item.alias + '>')
}
})
}
/**
* 递归查找树形结构中第一个level===6的节点找到即终止递归
* @param {Object|Array} tree - 树形数据(根节点数组 或 单个根节点)
* @returns {Object|null} 第一个level为6的节点无则返回null
*/
function findFirstLevel6Node(tree: any) {
// 统一处理入参:如果是数组,遍历根节点数组(按顺序找第一个符合条件的)
if (Array.isArray(tree)) {
for (const rootNode of tree) {
const result = traverse(rootNode)
// 找到第一个匹配节点,立即返回(终止根节点遍历)
if (result) return result
}
// 所有根节点遍历完未找到
return null
} else {
// 入参是单个节点,直接递归遍历
return traverse(tree)
}
// 核心递归遍历函数
function traverse(node) {
// 终止条件1节点不存在返回null
if (!node) return null
// 终止条件2找到level===6的节点立即返回终止递归
if (node.level === 6) {
return node
}
// 终止条件3节点无children返回null
if (!node.children || node.children.length === 0) {
return null
}
// 按顺序遍历当前节点的子节点
for (const child of node.children) {
const foundNode = traverse(child)
// 子节点中找到目标节点,立即返回(终止后续子节点遍历)
if (foundNode) {
return foundNode
}
}
// 当前节点及所有子节点都无匹配返回null
return null
}
}
defineExpose({ treeRef, scrollToNode, tree })
loadData()
</script>

View File

@@ -28,7 +28,7 @@ const tree = ref()
const treeRef = ref()
const loadData = (id?: any) => {
console.log('🚀 ~ loadData ~ id:', id)
let nodeKey = ''
queryAll().then(res => {
res.data.forEach((item: any) => {

View File

@@ -25,7 +25,7 @@
{{ Math.floor(row.eventValue * 10000) / 100 }}
</template>
</vxe-column>
<vxe-column field="eventType" width="100px" title="暂降类型">
<vxe-column field="eventType" width="100px" title="触发类型">
<template #default="{ row }">
{{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }}
</template>
@@ -50,7 +50,8 @@ import { ref, reactive, onMounted } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
import MQTT from '@/utils/mqtt'
// import MQTT from '@/utils/mqtt'
import socketClient from '@/utils/webSocketClient'
const dictData = useDictData()
const event = dictData.getBasicData('Event_Statis')
import { useAdminInfo } from '@/stores/adminInfo'
@@ -68,37 +69,72 @@ const handleClose = (done: any) => {
drawer.value = false
done()
}
const init = async () => {
const mqttClient = new MQTT('/sendEvent')
// 设置消息接收回调
try {
await mqttClient.init()
const dataSocket = reactive({
socketServe: socketClient.Instance
})
// const init = async () => {
// const mqttClient = new MQTT('/sendEvent')
// // 设置消息接收回调
// try {
// await mqttClient.init()
// 订阅主题
await mqttClient.subscribe()
// 设置消息接收回调
mqttClient.onMessage((topic, message) => {
const msg = JSON.parse(message.toString())
console.log('🚀 ~ init ~ msg:', msg)
if (msg.deptList.includes(adminInfo.$state.deptId)) {
drawer.value = true
isLoading.value = true
eventList.value.unshift(msg)
setTimeout(() => {
isLoading.value = false
}, 500)
}
})
} catch (error) {
console.error('MQTT 初始化失败:', error)
}
// // 订阅主题
// await mqttClient.subscribe()
// // 设置消息接收回调
// mqttClient.onMessage((topic, message) => {
// const msg = JSON.parse(message.toString())
// // console.log('🚀 ~ init ~ msg:', msg)
// if (msg.deptList.includes(adminInfo.$state.deptId)) {
// drawer.value = true
// isLoading.value = true
// eventList.value.unshift(msg)
// setTimeout(() => {
// isLoading.value = false
// }, 500)
// }
// })
// } catch (error) {
// // console.error('MQTT 初始化失败:', error)
// }
// }
const socket = async () => {
const url = localStorage.getItem('WebSocketUrl3') || 'null' //'ws://192.168.2.130:10203/event/'
// const url = 'ws://192.168.1.68:10203/event/'
await dataSocket.socketServe.connect(`${url}${adminInfo.id}`)
await dataSocket.socketServe.registerCallBack('message', (res: any) => {
if (res.deptList.includes(adminInfo.$state.deptId)) {
drawer.value = true
isLoading.value = true
eventList.value.unshift(res)
setTimeout(() => {
isLoading.value = false
}, 500)
}
// logList.value.push({
// type: res.code == 500 ? 'error' : '',
// time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'),
// name: res.message
// })
})
}
onUnmounted(() => {
dataSocket.socketServe?.closeWs()
})
onMounted(() => {
// startMqtt('/sendEvent', (topic, message) => {
// const msg = JSON.parse(message.toString())
// console.log(msg)
// })
init()
setTimeout(() => {
socket()
}, 3000)
})
defineExpose({
open,

View File

@@ -122,7 +122,7 @@ const onFullScreen = () => {
})
}
const handleCommand = (key: string) => {
const handleCommand = async(key: string) => {
console.log(key)
switch (key) {
case 'adminInfo':
@@ -132,10 +132,17 @@ const handleCommand = (key: string) => {
popupPwd.value.open()
break
case 'layout':
navTabs.closeTabs()
window.localStorage.clear()
adminInfo.reset()
router.push({ name: 'login' })
await window.location.reload()
setTimeout(() => {
navTabs.closeTabs()
window.localStorage.clear()
adminInfo.reset()
router.push({ name: 'login' })
}, 0)
// navTabs.closeTabs()
// window.localStorage.clear()
// adminInfo.reset()
// router.push({ name: 'login' })
break
default:
break

View File

@@ -1,109 +1,117 @@
<template>
<el-dialog draggable width="500px" v-model="dialogVisible" :title="title">
<el-scrollbar>
<el-form :inline="false" :model="form" label-width="120px" :rules="rules" ref="formRef">
<el-form-item label="校验密码:" prop="password">
<el-input v-model="form.password" type="password" placeholder="请输入校验密码" show-password />
</el-form-item>
<el-form-item label="新密码:" prop="newPwd" style="margin-top: 20px">
<el-input v-model="form.newPwd" type="password" placeholder="请输入新密码" show-password />
</el-form-item>
<el-form-item label="确认密码:" prop="confirmPwd" style="margin-top: 20px">
<el-input v-model="form.confirmPwd" type="password" placeholder="请输入确认密码" show-password />
</el-form-item>
</el-form>
</el-scrollbar>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, inject } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { passwordConfirm, updatePassword } from '@/api/user-boot/user'
import { validatePwd } from '@/utils/common'
import { useAdminInfo } from '@/stores/adminInfo'
const adminInfo = useAdminInfo()
const dialogVisible = ref(false)
const title = ref('修改密码')
const formRef = ref()
// 注意不要和表单ref的命名冲突
const form = reactive({
password: '',
newPwd: '',
confirmPwd: ''
})
const rules = {
password: [
{ required: true, message: '请输入校验密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
}
],
newPwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
},
{ validator: validatePwd, trigger: 'blur' }
],
confirmPwd: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
},
{
validator: (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== form.newPwd) {
callback(new Error('次输入密码不一致!'))
} else {
callback()
}
},
trigger: 'blur',
required: true
}
]
}
const open = () => {
dialogVisible.value = true
form.password = ''
form.newPwd = ''
form.confirmPwd = ''
}
const submit = () => {
formRef.value.validate(async (valid: boolean) => {
if (valid) {
passwordConfirm(form.password).then(res => {
updatePassword({
id: adminInfo.$state.userIndex,
newPassword: form.newPwd
}).then((res: any) => {
ElMessage.success('密码修改成功')
dialogVisible.value = false
})
})
}
})
}
defineExpose({ open })
</script>
<template>
<el-dialog draggable width="500px" v-model="dialogVisible" :title="title">
<el-scrollbar>
<el-form :inline="false" :model="form" label-width="120px" :rules="rules" ref="formRef">
<el-form-item label="校验密码:" prop="password">
<el-input v-model="form.password" type="password" placeholder="请输入校验密码" show-password />
</el-form-item>
<el-form-item label="新密码:" prop="newPwd" style="margin-top: 20px">
<el-input v-model="form.newPwd" type="password" placeholder="请输入新密码" show-password />
</el-form-item>
<el-form-item label="确认密码:" prop="confirmPwd" style="margin-top: 20px">
<el-input v-model="form.confirmPwd" type="password" placeholder="请输入确认密码" show-password />
</el-form-item>
</el-form>
</el-scrollbar>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, inject } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { passwordConfirm, updatePassword } from '@/api/user-boot/user'
import { validatePwd } from '@/utils/common'
import { useAdminInfo } from '@/stores/adminInfo'
import router from '@/router'
import { useNavTabs } from '@/stores/navTabs'
const navTabs = useNavTabs()
const adminInfo = useAdminInfo()
const dialogVisible = ref(false)
const title = ref('修改密码')
const formRef = ref()
// 注意不要和表单ref的命名冲突
const form = reactive({
password: '',
newPwd: '',
confirmPwd: ''
})
const rules = {
password: [
{ required: true, message: '请输入校验密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
}
],
newPwd: [
{ required: true, message: '请输入密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
},
{ validator: validatePwd, trigger: 'blur' }
],
confirmPwd: [
{ required: true, message: '请确认密码', trigger: 'blur' },
{
min: 6,
max: 12,
message: '长度在 6 到 12 个字符',
trigger: 'blur'
},
{
validator: (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请再次输入密码'))
} else if (value !== form.newPwd) {
callback(new Error('两次输入密码不一致!'))
} else {
callback()
}
},
trigger: 'blur',
required: true
}
]
}
const open = () => {
dialogVisible.value = true
form.password = ''
form.newPwd = ''
form.confirmPwd = ''
}
const submit = () => {
formRef.value.validate(async (valid: boolean) => {
if (valid) {
passwordConfirm(form.password).then(res => {
updatePassword({
id: adminInfo.$state.userIndex,
newPassword: form.newPwd
}).then((res: any) => {
ElMessage.success('密码修改成功,请重新登录!')
dialogVisible.value = false
setTimeout(() => {
navTabs.closeTabs()
window.localStorage.clear()
adminInfo.reset()
router.push({ name: 'login' })
}, 0)
})
})
}
})
}
defineExpose({ open })
</script>

View File

@@ -29,7 +29,7 @@ const emit = defineEmits(['update:modelValue'])
const dialogVisible = computed({
get: () => props.modelValue,
set: (val) => {
console.log('set: ', val)
emit('update:modelValue', val)
}
})

View File

@@ -1,49 +1,49 @@
import { createRouter, createWebHashHistory } from 'vue-router'
import staticRoutes from '@/router/static'
import { useAdminInfo } from '@/stores/adminInfo'
import NProgress from 'nprogress'
import { loading } from '@/utils/loading'
import { ElMessage } from 'element-plus'
const router = createRouter({
history: createWebHashHistory(),
routes: staticRoutes
})
router.beforeEach((to, from, next) => {
NProgress.configure({ showSpinner: false })
NProgress.start()
if (!window.existLoading) {
loading.show()
window.existLoading = true
}
if (to.path == '/login' || to.path == '/404') {
// 登录或者注册才可以往下进行
next()
} else if (to.path == '/admin/center/homePage') {
window.open(window.location.origin + '/homePage/#/')
} else {
// 获取 token
const adminInfo = useAdminInfo()
const token = adminInfo.getToken()
// token 不存在
if (token === null || token === '') {
ElMessage.error('您还没有登录,请先登录')
next('/login')
} else {
next()
}
}
// next()
})
// 路由加载后
router.afterEach(() => {
if (window.existLoading) {
loading.hide()
}
NProgress.done()
})
export default router
import { createRouter, createWebHashHistory } from 'vue-router'
import staticRoutes from '@/router/static'
import { useAdminInfo } from '@/stores/adminInfo'
import NProgress from 'nprogress'
import { loading } from '@/utils/loading'
import { ElMessage } from 'element-plus'
const router = createRouter({
history: createWebHashHistory(),
routes: staticRoutes
})
router.beforeEach((to, from, next) => {
NProgress.configure({ showSpinner: false })
NProgress.start()
if (!window.existLoading) {
loading.show()
window.existLoading = true
}
if (to.path == '/login' || to.path == '/404') {
// 登录或者注册才可以往下进行
next()
} else if (to.path == '/admin/center/homePage') {
window.open(window.location.origin + '/homePage/#/')
} else {
// 获取 token
const adminInfo = useAdminInfo()
const token = adminInfo.getToken()
// token 不存在
if (token === null || token === '') {
// ElMessage.error('您还没有登录,请先登录')
next('/login')
} else {
next()
}
}
// next()
})
// 路由加载后
router.afterEach(() => {
if (window.existLoading) {
loading.hide()
}
NProgress.done()
})
export default router

View File

@@ -1,246 +1,246 @@
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_CONFIG } from '@/stores/constant/cacheKey'
import type { Layout } from '@/stores/interface'
export const useConfig = defineStore(
'config',
() => {
const layout: Layout = reactive({
/* 全局 */
showDrawer: false,
// 是否收缩布局(小屏终端)
shrink: false,
// 后台布局方式,可选值<Default|Classic|Streamline|Double>
layoutMode: 'Classic',
// 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
mainAnimation: 'slide-right',
// 是否暗黑模式
isDark: false,
elementUiPrimary: ['#002B6A', '#002B6A'],
tableHeaderBackground: ['#F3F6F9', '#F3F6F9'],
tableHeaderColor: ['#111', '#fff'],
tableCurrent: ['#F3F6F9', '#F3F6F9'],
/* 侧边菜单 */
// 侧边菜单背景色
menuBackground: ['#002B6A', '#1d1e1f'],
// 侧边菜单文字颜色
menuColor: ['#FFFFFF', '#CFD3DC'],
// 侧边菜单激活项背景色
menuActiveBackground: ['#002255', '#1d1e1f'],
// 侧边菜单激活项文字色
menuActiveColor: ['#409eff', '#3375b9'],
// 侧边菜单顶栏背景色
menuTopBarBackground: ['#002B6A', '#1d1e1f'],
// 侧边菜单宽度(展开时)单位px
menuWidth: 260,
// 侧边菜单项默认图标
menuDefaultIcon: 'fa fa-circle-o',
// 是否水平折叠收起菜单
menuCollapse: false,
// 是否只保持一个子菜单的展开(手风琴)
menuUniqueOpened: false,
// 显示菜单栏顶栏(LOGO)
menuShowTopBar: true,
/* 顶栏 */
// 顶栏文字色
headerBarTabColor: ['#FFFFFF', '#CFD3DC'],
// // 顶栏激活项背景色
headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'],
// 顶栏激活项文字色
headerBarTabActiveColor: ['#000000', '#409EFF'],
// 顶栏背景色
headerBarBackground: ['#002B6A', '#1d1e1f'],
// 顶栏悬停时背景色
headerBarHoverBackground: ['#f5f5f5', '#18222c']
})
const lang = reactive({
// 默认语言,可选值<zh-cn|en>
defaultLang: 'zh-cn',
// 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译
fallbackLang: 'zh-cn',
// 支持的语言列表
langArray: [
{ name: 'zh-cn', value: '中文简体' },
{ name: 'en', value: 'English' }
]
})
function menuWidth() {
if (layout.shrink) {
return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
}
// 菜单是否折叠
return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
}
function setLang(val: string) {
lang.defaultLang = val
}
function onSetLayoutColor(data = layout.layoutMode) {
// 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值
const tempValue = layout.isDark
? { idx: 1, color: '#1d1e1f', newColor: '#141414' }
: { idx: 0, color: '#ffffff', newColor: '#f5f5f5' }
if (
data == 'Classic' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor
} else if (
data == 'Default' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color
}
}
function setLayoutMode(data: string) {
layout.layoutMode = data
onSetLayoutColor(data)
}
const setLayout = (name: keyof Layout, value: any) => {
layout[name] = value as never
}
const getColorVal = function (name: keyof Layout): string {
const colors = layout[name] as string[]
if (layout.isDark) {
return colors[1]
} else {
return colors[0]
}
}
return { layout, lang, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor }
},
// () => {
//
// console.log('🚀 ~ subject:', subject)
// const layout: Layout = reactive({
// /* 全局 */
// showDrawer: false,
// // 是否收缩布局(小屏终端)
// shrink: false,
// // 后台布局方式,可选值<Default|Classic|Streamline|Double>
// layoutMode: 'Classic',
// // 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
// mainAnimation: subject.mainAnimation,
// // 是否暗黑模式
// isDark: false,
// elementUiPrimary: JSON.parse(subject.elementUiPrimary),
// tableHeaderBackground: JSON.parse(subject.tableHeaderBackground),
// tableHeaderColor:JSON.parse(subject.tableHeaderColor),
// tableCurrent: JSON.parse(subject.tableCurrent),
// /* 侧边菜单 */
// // 侧边菜单背景色
// menuBackground: JSON.parse(subject.menuBackground),
// // 侧边菜单文字颜色
// menuColor:JSON.parse(subject.menuColor),
// // 侧边菜单激活项背景色
// menuActiveBackground:JSON.parse(subject.menuActiveBackground),
// // 侧边菜单激活项文字色
// menuActiveColor:JSON.parse(subject.menuActiveColor),
// // 侧边菜单顶栏背景色
// menuTopBarBackground: JSON.parse(subject.menuTopBarBackground),
// // 侧边菜单宽度(展开时)单位px
// menuWidth: 260,
// // 侧边菜单项默认图标
// menuDefaultIcon: 'fa fa-circle-o',
// // 是否水平折叠收起菜单
// menuCollapse: false,
// // 是否只保持一个子菜单的展开(手风琴)
// menuUniqueOpened: false,
// // 显示菜单栏顶栏(LOGO)
// menuShowTopBar: true,
// /* 顶栏 */
// // 顶栏文字色
// headerBarTabColor:JSON.parse(subject.headerBarTabColor),
// // // 顶栏激活项背景色
// headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'],
// // 顶栏激活项文字色
// headerBarTabActiveColor: ['#000000', '#409EFF'],
// // 顶栏背景色
// headerBarBackground: JSON.parse(subject.headerBarBackground),
// // 顶栏悬停时背景色
// headerBarHoverBackground: ['#f5f5f5', '#18222c']
// })
// // console.log(123, window.localStorage.getItem('getTheme'))
// const lang = reactive({
// // 默认语言,可选值<zh-cn|en>
// defaultLang: 'zh-cn',
// // 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译
// fallbackLang: 'zh-cn',
// // 支持的语言列表
// langArray: [
// { name: 'zh-cn', value: '中文简体' },
// { name: 'en', value: 'English' }
// ]
// })
// function menuWidth() {
// if (layout.shrink) {
// return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
// }
// // 菜单是否折叠
// return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
// }
// function setLang(val: string) {
// lang.defaultLang = val
// }
// function onSetLayoutColor(data = layout.layoutMode) {
// // 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值
// const tempValue = layout.isDark
// ? { idx: 1, color: '#1d1e1f', newColor: '#141414' }
// : { idx: 0, color: '#ffffff', newColor: '#f5f5f5' }
// if (
// data == 'Classic' &&
// layout.headerBarBackground[tempValue.idx] == tempValue.color &&
// layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color
// ) {
// layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor
// } else if (
// data == 'Default' &&
// layout.headerBarBackground[tempValue.idx] == tempValue.color &&
// layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor
// ) {
// layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color
// }
// }
// function setLayoutMode(data: string) {
// layout.layoutMode = data
// onSetLayoutColor(data)
// }
// const setLayout = (name: keyof Layout, value: any) => {
// layout[name] = value as never
// }
// const getColorVal = function (name: keyof Layout): string {
// const colors = layout[name] as string[]
// if (layout.isDark) {
// return colors[1]
// } else {
// return colors[0]
// }
// }
// return { layout, lang, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor }
// },
{
persist: {
key: STORE_CONFIG
}
}
)
import { reactive } from 'vue'
import { defineStore } from 'pinia'
import { STORE_CONFIG } from '@/stores/constant/cacheKey'
import type { Layout } from '@/stores/interface'
export const useConfig = defineStore(
'config',
() => {
const layout: Layout = reactive({
/* 全局 */
showDrawer: false,
// 是否收缩布局(小屏终端)
shrink: false,
// 后台布局方式,可选值<Default|Classic|Streamline|Double>
layoutMode: 'Classic',
// 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
mainAnimation: 'slide-right',
// 是否暗黑模式
isDark: false,
elementUiPrimary: ['#002B6A', '#002B6A'],
tableHeaderBackground: ['#F3F6F9', '#F3F6F9'],
tableHeaderColor: ['#111', '#fff'],
tableCurrent: ['#F3F6F9', '#F3F6F9'],
/* 侧边菜单 */
// 侧边菜单背景色
menuBackground: ['#002B6A', '#1d1e1f'],
// 侧边菜单文字颜色
menuColor: ['#FFFFFF', '#CFD3DC'],
// 侧边菜单激活项背景色
menuActiveBackground: ['#002255', '#1d1e1f'],
// 侧边菜单激活项文字色
menuActiveColor: ['#409eff', '#3375b9'],
// 侧边菜单顶栏背景色
menuTopBarBackground: ['#002B6A', '#1d1e1f'],
// 侧边菜单宽度(展开时)单位px
menuWidth: 260,
// 侧边菜单项默认图标
menuDefaultIcon: 'fa fa-circle-o',
// 是否水平折叠收起菜单
menuCollapse: false,
// 是否只保持一个子菜单的展开(手风琴)
menuUniqueOpened: false,
// 显示菜单栏顶栏(LOGO)
menuShowTopBar: true,
/* 顶栏 */
// 顶栏文字色
headerBarTabColor: ['#FFFFFF', '#CFD3DC'],
// // 顶栏激活项背景色
headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'],
// 顶栏激活项文字色
headerBarTabActiveColor: ['#000000', '#409EFF'],
// 顶栏背景色
headerBarBackground: ['#002B6A', '#1d1e1f'],
// 顶栏悬停时背景色
headerBarHoverBackground: ['#f5f5f5', '#18222c']
})
const lang = reactive({
// 默认语言,可选值<zh-cn|en>
defaultLang: 'zh-cn',
// 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译
fallbackLang: 'zh-cn',
// 支持的语言列表
langArray: [
{ name: 'zh-cn', value: '中文简体' },
{ name: 'en', value: 'English' }
]
})
function menuWidth() {
if (layout.shrink) {
return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
}
// 菜单是否折叠
return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
}
function setLang(val: string) {
lang.defaultLang = val
}
function onSetLayoutColor(data = layout.layoutMode) {
// 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值
const tempValue = layout.isDark
? { idx: 1, color: '#1d1e1f', newColor: '#141414' }
: { idx: 0, color: '#ffffff', newColor: '#f5f5f5' }
if (
data == 'Classic' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor
} else if (
data == 'Default' &&
layout.headerBarBackground[tempValue.idx] == tempValue.color &&
layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor
) {
layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color
}
}
function setLayoutMode(data: string) {
layout.layoutMode = data
onSetLayoutColor(data)
}
const setLayout = (name: keyof Layout, value: any) => {
layout[name] = value as never
}
const getColorVal = function (name: keyof Layout): string {
const colors = layout[name] as string[] || ['#082E6C', '#0e8780']
if (layout.isDark) {
return colors[1]
} else {
return colors[0]
}
}
return { layout, lang, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor }
},
// () => {
//
// console.log('🚀 ~ subject:', subject)
// const layout: Layout = reactive({
// /* 全局 */
// showDrawer: false,
// // 是否收缩布局(小屏终端)
// shrink: false,
// // 后台布局方式,可选值<Default|Classic|Streamline|Double>
// layoutMode: 'Classic',
// // 后台主页面切换动画,可选值<slide-right|slide-left|el-fade-in-linear|el-fade-in|el-zoom-in-center|el-zoom-in-top|el-zoom-in-bottom>
// mainAnimation: subject.mainAnimation,
// // 是否暗黑模式
// isDark: false,
// elementUiPrimary: JSON.parse(subject.elementUiPrimary),
// tableHeaderBackground: JSON.parse(subject.tableHeaderBackground),
// tableHeaderColor:JSON.parse(subject.tableHeaderColor),
// tableCurrent: JSON.parse(subject.tableCurrent),
// /* 侧边菜单 */
// // 侧边菜单背景色
// menuBackground: JSON.parse(subject.menuBackground),
// // 侧边菜单文字颜色
// menuColor:JSON.parse(subject.menuColor),
// // 侧边菜单激活项背景色
// menuActiveBackground:JSON.parse(subject.menuActiveBackground),
// // 侧边菜单激活项文字色
// menuActiveColor:JSON.parse(subject.menuActiveColor),
// // 侧边菜单顶栏背景色
// menuTopBarBackground: JSON.parse(subject.menuTopBarBackground),
// // 侧边菜单宽度(展开时)单位px
// menuWidth: 260,
// // 侧边菜单项默认图标
// menuDefaultIcon: 'fa fa-circle-o',
// // 是否水平折叠收起菜单
// menuCollapse: false,
// // 是否只保持一个子菜单的展开(手风琴)
// menuUniqueOpened: false,
// // 显示菜单栏顶栏(LOGO)
// menuShowTopBar: true,
// /* 顶栏 */
// // 顶栏文字色
// headerBarTabColor:JSON.parse(subject.headerBarTabColor),
// // // 顶栏激活项背景色
// headerBarTabActiveBackground: ['#ffffff', '#1d1e1f'],
// // 顶栏激活项文字色
// headerBarTabActiveColor: ['#000000', '#409EFF'],
// // 顶栏背景色
// headerBarBackground: JSON.parse(subject.headerBarBackground),
// // 顶栏悬停时背景色
// headerBarHoverBackground: ['#f5f5f5', '#18222c']
// })
// // console.log(123, window.localStorage.getItem('getTheme'))
// const lang = reactive({
// // 默认语言,可选值<zh-cn|en>
// defaultLang: 'zh-cn',
// // 当在默认语言包找不到翻译时,继续在 fallbackLang 语言包内查找翻译
// fallbackLang: 'zh-cn',
// // 支持的语言列表
// langArray: [
// { name: 'zh-cn', value: '中文简体' },
// { name: 'en', value: 'English' }
// ]
// })
// function menuWidth() {
// if (layout.shrink) {
// return layout.menuCollapse ? '0px' : layout.menuWidth + 'px'
// }
// // 菜单是否折叠
// return layout.menuCollapse ? '64px' : layout.menuWidth + 'px'
// }
// function setLang(val: string) {
// lang.defaultLang = val
// }
// function onSetLayoutColor(data = layout.layoutMode) {
// // 切换布局时,如果是为默认配色方案,对菜单激活背景色重新赋值
// const tempValue = layout.isDark
// ? { idx: 1, color: '#1d1e1f', newColor: '#141414' }
// : { idx: 0, color: '#ffffff', newColor: '#f5f5f5' }
// if (
// data == 'Classic' &&
// layout.headerBarBackground[tempValue.idx] == tempValue.color &&
// layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.color
// ) {
// layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.newColor
// } else if (
// data == 'Default' &&
// layout.headerBarBackground[tempValue.idx] == tempValue.color &&
// layout.headerBarTabActiveBackground[tempValue.idx] == tempValue.newColor
// ) {
// layout.headerBarTabActiveBackground[tempValue.idx] = tempValue.color
// }
// }
// function setLayoutMode(data: string) {
// layout.layoutMode = data
// onSetLayoutColor(data)
// }
// const setLayout = (name: keyof Layout, value: any) => {
// layout[name] = value as never
// }
// const getColorVal = function (name: keyof Layout): string {
// const colors = layout[name] as string[]
// if (layout.isDark) {
// return colors[1]
// } else {
// return colors[0]
// }
// }
// return { layout, lang, menuWidth, setLang, setLayoutMode, setLayout, getColorVal, onSetLayoutColor }
// },
{
persist: {
key: STORE_CONFIG
}
}
)

View File

@@ -29,12 +29,10 @@ export const useMonitoringPoint = defineStore(
const setShowCheckBox = (val: boolean) => {
if (val && state.lineIds.length === 0) {
state.lineIds = [state.lineId]
console.log('====================================')
console.log(state.lineIds)
console.log('====================================')
}
state.showCheckBox = val
}
return { state, setValue, setShowCheckBox }
},
{

View File

@@ -404,6 +404,11 @@ body,
.el-select__wrapper {
height: 32px !important;
}
.BMap_center,
.BMap_top,
.BMap_bottom {
background-color: #fff;
}
@font-face {
font-family: 'AlimamaFangYuanTiVF';
src: url('../assets/font/ali/AlimamaFangYuanTiVF-Thin.woff') format('woff'),

View File

@@ -1,176 +1,176 @@
<template>
<div class='default-main'>
<!-- 表头 -->
<!-- date-picker 时间组件 area区域组件-->
<TableHeader date-picker area>
<template v-slot:select>
<el-form-item label='关键词:'>
<el-input
style='width: 240px'
v-model='tableStore.table.params.searchValue'
clearable
placeholder='仅根据用户名/登录名'
/>
</el-form-item>
</template>
<template v-slot:operation>
<el-button :icon='Plus' type='primary' @click='addUser'>添加</el-button>
</template>
</TableHeader>
<!-- 表格 -->
<Table ref='tableRef' />
<!-- 弹框 -->
<PopupEdit ref='popupEdit' />
</div>
</template>
<script setup lang='ts'>
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, provide, defineOptions } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import PopupEdit from './dialog.vue'
import { mainHeight } from '@/utils/layout'
// 注意名字不要重复若要保持页面存活名字需要和路由admin后面的字符保持一致
defineOptions({
name: 'auth/userlist'
})
const popupEdit = ref()
const tableStore = new TableStore({
// 若页面表格高度需要调整请修改publicHeight(内容区域除表格外其他内容的高度)
// publicHeight: 60,
url: '/user-boot/user/list',
method: 'POST',
column: [
{ title: '用户名称', field: 'name', minWidth: '130' },
{ title: '登录名', field: 'loginName', minWidth: '130' },
{ title: '角色', field: 'roleName', minWidth: '130' },
{ title: '部门', field: 'deptName', minWidth: '200' },
{ title: '电话', field: 'phoneShow', minWidth: '100' },
{ title: '注册时间', field: 'registerTime', minWidth: '130' },
{ title: '登录时间', field: 'loginTime', minWidth: '130' },
{ title: '类型', field: 'casualUserName', minWidth: '80' },
{
title: '状态',
field: 'state',
width: '100',
render: 'tag',
custom: {
0: 'danger',
1: 'success',
2: 'warning',
3: 'warning',
4: 'info',
5: 'danger'
},
replaceValue: {
0: '注销',
1: '正常',
2: '锁定',
3: '待审核',
4: '休眠',
5: '密码过期'
}
},
{
title: '操作',
width: '180',
render: 'buttons',
fixed: 'right',
buttons: [
{
name: 'edit',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
}
},
{
name: 'edit',
title: '修改密码',
type: 'primary',
icon: 'el-icon-Lock',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputType: 'password'
}).then(({ value }) => {
})
}
},
{
name: 'edit',
title: '激活',
type: 'primary',
icon: 'el-icon-Open',
render: 'basicButton',
disabled: row => {
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
},
click: row => {
}
},
{
name: 'edit',
title: '注销',
type: 'danger',
icon: 'el-icon-SwitchButton',
render: 'basicButton',
disabled: row => {
return row.state !== 1 && row.state !== 3
},
click: row => {
}
}
]
}
],
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {
item.deptName = item.deptName || '/'
item.phoneShow = item.phone || '/'
item.roleName = item.role.length ? item.role : '/'
switch (item.casualUser) {
case 0:
item.casualUserName = '临时用户'
break
case 1:
item.casualUserName = '长期用户'
break
default:
item.casualUserName = '/'
break
}
})
}
})
// 注入到子组件
provide('tableStore', tableStore)
// 默认参数 参数多的话可以使用Object.assign方法
tableStore.table.params.searchState = 1
tableStore.table.params.searchValue = ''
tableStore.table.params.casualUser = -1
tableStore.table.params.orderBy = ''
onMounted(() => {
// 加载数据
tableStore.index()
})
// 弹框
const addUser = () => {
popupEdit.value.open('新增用户')
}
</script>
<template>
<div class='default-main'>
<!-- 表头 -->
<!-- date-picker 时间组件 area区域组件-->
<TableHeader date-picker area>
<template v-slot:select>
<el-form-item label='关键词:'>
<el-input
style='width: 240px'
v-model='tableStore.table.params.searchValue'
clearable
placeholder='仅根据用户名/登录名'
/>
</el-form-item>
</template>
<template v-slot:operation>
<el-button :icon='Plus' type='primary' @click='addUser'>添加</el-button>
</template>
</TableHeader>
<!-- 表格 -->
<Table ref='tableRef' />
<!-- 弹框 -->
<PopupEdit ref='popupEdit' />
</div>
</template>
<script setup lang='ts'>
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, provide, defineOptions } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import PopupEdit from './dialog.vue'
import { mainHeight } from '@/utils/layout'
// 注意名字不要重复若要保持页面存活名字需要和路由admin后面的字符保持一致
defineOptions({
name: 'auth/userlist'
})
const popupEdit = ref()
const tableStore = new TableStore({
// 若页面表格高度需要调整请修改publicHeight(内容区域除表格外其他内容的高度)
// publicHeight: 60,
url: '/user-boot/user/list',
method: 'POST',
column: [
{ title: '用户名称', field: 'name', minWidth: '130' },
{ title: '登录名', field: 'loginName', minWidth: '130' },
{ title: '角色', field: 'roleName', minWidth: '130' },
{ title: '部门', field: 'deptName', minWidth: '200' },
{ title: '电话', field: 'phoneShow', minWidth: '100' },
{ title: '注册时间', field: 'registerTime', minWidth: '130' },
{ title: '登录时间', field: 'loginTime', minWidth: '130' },
{ title: '类型', field: 'casualUserName', minWidth: '80' },
{
title: '状态',
field: 'state',
width: '100',
render: 'tag',
custom: {
0: 'danger',
1: 'success',
2: 'warning',
3: 'warning',
4: 'info',
5: 'danger'
},
replaceValue: {
0: '注销',
1: '正常',
2: '锁定',
3: '待审核',
4: '休眠',
5: '密码过期'
}
},
{
title: '操作',fixed: 'right',
width: '180',
render: 'buttons',
buttons: [
{
name: 'edit',
title: '编辑',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
}
},
{
name: 'edit',
title: '修改密码',
type: 'primary',
icon: 'el-icon-Lock',
render: 'basicButton',
disabled: row => {
return row.state !== 1
},
click: row => {
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputType: 'password'
}).then(({ value }) => {
})
}
},
{
name: 'edit',
title: '激活',
type: 'primary',
icon: 'el-icon-Open',
render: 'basicButton',
disabled: row => {
return row.state !== 2 && row.state !== 5 && row.state !== 0 && row.state !== 4
},
click: row => {
}
},
{
name: 'edit',
title: '注销',
type: 'danger',
icon: 'el-icon-SwitchButton',
render: 'basicButton',
disabled: row => {
return row.state !== 1 && row.state !== 3
},
click: row => {
}
}
]
}
],
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {
item.deptName = item.deptName || '/'
item.phoneShow = item.phone || '/'
item.roleName = item.role.length ? item.role : '/'
switch (item.casualUser) {
case 0:
item.casualUserName = '临时用户'
break
case 1:
item.casualUserName = '长期用户'
break
default:
item.casualUserName = '/'
break
}
})
}
})
// 注入到子组件
provide('tableStore', tableStore)
// 默认参数 参数多的话可以使用Object.assign方法
tableStore.table.params.searchState = 1
tableStore.table.params.searchValue = ''
tableStore.table.params.casualUser = -1
tableStore.table.params.orderBy = ''
onMounted(() => {
// 加载数据
tableStore.index()
})
// 弹框
const addUser = () => {
popupEdit.value.open('新增用户')
}
</script>

View File

@@ -1,14 +1,14 @@
// 高级算法
export const ADVANCE_BOOT = '/advance-boot'
//技术监督
export const PROCESS_BOOT = '/process-boot'
//工作流模块
export const BPM_BOOT = '/bpm-boot'
//冀北技术监督
export const SUPERVISION_BOOT = '/supervision-boot'
//终端模块
// 高级算法
export const ADVANCE_BOOT = '/advance-boot'
//技术监督
export const PROCESS_BOOT = '/process-boot'
//工作流模块
export const BPM_BOOT = '/bpm-boot'
//网公司技术监督
export const SUPERVISION_BOOT = '/supervision-boot'
//终端模块
export const DEVICE_BOOT = '/device-boot'

View File

@@ -1,286 +1,337 @@
//指标类型
export const indexOptions = [
{
label: '电压趋势',
options: [
{
value: '10',
label: '相电压有效值'
},
{
value: '11',
label: '线电压有效值'
},
{
value: '12',
label: '电压偏差'
},
{
value: '13',
label: '三相电压不平衡'
},
{
value: '14',
label: '电压不平衡'
},
{
value: '15',
label: '电压总谐波畸变率'
}
]
},
{
label: '电流趋势',
options: [
{
value: '20',
label: '电流有效值'
},
{
value: '21',
label: '电流总谐波畸变率'
},
{
value: '22',
label: '负序电流'
}
]
},
{
label: '频率趋势',
options: [
{
value: '30',
label: '频率'
}
]
},
{
label: '谐波趋势',
options: [
{
value: '40',
label: '谐波电压含有率'
},
{
value: '43',
label: '谐波电流幅值'
},
{
value: '44',
label: '谐波电压相角'
},
{
value: '45',
label: '谐波电流相角'
},
{
value: '46',
label: '间谐波电压含有率'
},
// {
// value: '47',
// label: '间谐波电流含有率'
// },
// {
// value: '48',
// label: '间谐波电压幅值'
// },
{
value: '49',
label: '间谐波电流幅值'
}
]
},
{
label: '功率趋势',
options: [
{
value: '50',
label: '谐波有功功率'
},
{
value: '51',
label: '谐波无功功率'
},
{
value: '52',
label: '谐波视在功率'
},
{
value: '53',
label: '三相有功功率'
},
{
value: '54',
label: '三相无功功率'
},
{
value: '55',
label: '三相视在功率'
},
{
value: '56',
label: '三相总有功功率'
},
{
value: '57',
label: '三相总无功功率'
},
{
value: '58',
label: '三相总视在功率'
},
{
value: '59',
label: '视在功率因数'
},
{
value: '591',
label: '位移功率因数'
},
{
value: '592',
label: '总视在功率因数'
},
{
value: '593',
label: '总位移功率因数'
}
]
},
{
label: '闪变趋势',
options: [
{
value: '60',
label: '短时电压闪变'
},
{
value: '61',
label: '长时电压闪变'
},
{
value: '62',
label: '电压波动'
}
]
}
]
//谐波次数
export const harmonicOptions = [
{ label: '基波', value: 1 },
{ label: '2次', value: 2 },
{ label: '3次', value: 3 },
{ label: '4次', value: 4 },
{ label: '5次', value: 5 },
{ label: '6次', value: 6 },
{ label: '7次', value: 7 },
{ label: '8次', value: 8 },
{ label: '9次', value: 9 },
{ label: '10次', value: 10 },
{ label: '11次', value: 11 },
{ label: '12次', value: 12 },
{ label: '13次', value: 13 },
{ label: '14次', value: 14 },
{ label: '15次', value: 15 },
{ label: '16次', value: 16 },
{ label: '17次', value: 17 },
{ label: '18次', value: 18 },
{ label: '19次', value: 19 },
{ label: '20次', value: 20 },
{ label: '21次', value: 21 },
{ label: '22次', value: 22 },
{ label: '23次', value: 23 },
{ label: '24次', value: 24 },
{ label: '25次', value: 25 },
{ label: '26次', value: 26 },
{ label: '27次', value: 27 },
{ label: '28次', value: 28 },
{ label: '29次', value: 29 },
{ label: '30次', value: 30 },
{ label: '31次', value: 31 },
{ label: '32次', value: 32 },
{ label: '33次', value: 33 },
{ label: '34次', value: 34 },
{ label: '35次', value: 35 },
{ label: '36次', value: 36 },
{ label: '37次', value: 37 },
{ label: '38次', value: 38 },
{ label: '39次', value: 39 },
{ label: '40次', value: 40 },
{ label: '41次', value: 41 },
{ label: '42次', value: 42 },
{ label: '43次', value: 43 },
{ label: '44次', value: 44 },
{ label: '45次', value: 45 },
{ label: '46次', value: 46 },
{ label: '47次', value: 47 },
{ label: '48次', value: 48 },
{ label: '49次', value: 49 },
{ label: '50次', value: 50 }
]
//简谐波次数
export const inharmonicOptions = [
{ label: '0.5次', value: 1 },
{ label: '1.5次', value: 2 },
{ label: '2.5次', value: 3 },
{ label: '3.5次', value: 4 },
{ label: '4.5次', value: 5 },
{ label: '5.5次', value: 6 },
{ label: '6.5次', value: 7 },
{ label: '7.5次', value: 8 },
{ label: '8.5次', value: 9 },
{ label: '9.5次', value: 10 },
{ label: '10.5次', value: 11 },
{ label: '11.5次', value: 12 },
{ label: '12.5次', value: 13 },
{ label: '13.5次', value: 14 },
{ label: '14.5次', value: 15 },
{ label: '15.5次', value: 16 },
{ label: '16.5次', value: 17 },
{ label: '17.5次', value: 18 },
{ label: '18.5次', value: 19 },
{ label: '19.5次', value: 20 },
{ label: '20.5次', value: 21 },
{ label: '21.5次', value: 22 },
{ label: '22.5次', value: 23 },
{ label: '23.5次', value: 24 },
{ label: '24.5次', value: 25 },
{ label: '25.5次', value: 26 },
{ label: '26.5次', value: 27 },
{ label: '27.5次', value: 28 },
{ label: '28.5次', value: 29 },
{ label: '29.5次', value: 30 },
{ label: '30.5次', value: 31 },
{ label: '31.5次', value: 32 },
{ label: '32.5次', value: 33 },
{ label: '33.5次', value: 34 },
{ label: '34.5次', value: 35 },
{ label: '35.5次', value: 36 },
{ label: '36.5次', value: 37 },
{ label: '37.5次', value: 38 },
{ label: '38.5次', value: 39 },
{ label: '39.5次', value: 40 },
{ label: '40.5次', value: 41 },
{ label: '41.5次', value: 42 },
{ label: '42.5次', value: 43 },
{ label: '43.5次', value: 44 },
{ label: '44.5次', value: 45 },
{ label: '45.5次', value: 46 },
{ label: '46.5次', value: 47 },
{ label: '47.5次', value: 48 },
{ label: '48.5次', value: 49 },
{ label: '49.5次', value: 50 },
]
//值类型
export const typeOptions = [
{ label: '平均值', value: 1 },
{ label: '最小值', value: 2 },
{ label: '最大值', value: 3 },
{ label: 'cp95值', value: 4 }
]
//指标类型
export const indexOptions = [
{
label: '电压趋势',
options: [
{
value: '10',
label: '相电压有效值'
},
{
value: '11',
label: '线电压有效值'
},
{
value: '12',
label: '电压偏差'
},
{
value: '13',
label: '三相电压不平衡'
},
{
value: '14',
label: '电压不平衡'
},
{
value: '15',
label: '电压总谐波畸变率'
}
]
},
{
label: '电流趋势',
options: [
{
value: '20',
label: '电流有效值'
},
{
value: '21',
label: '电流总谐波畸变率'
},
{
value: '22',
label: '负序电流'
}
]
},
{
label: '频率趋势',
options: [
{
value: '30',
label: '频率'
}
]
},
{
label: '谐波趋势',
options: [
{
value: '40',
label: '谐波电压含有率'
},
{
value: '43',
label: '谐波电流幅值'
},
{
value: '44',
label: '谐波电压相角'
},
{
value: '45',
label: '谐波电流相角'
},
{
value: '46',
label: '间谐波电压含有率'
},
// {
// value: '47',
// label: '间谐波电流含有率'
// },
// {
// value: '48',
// label: '间谐波电压幅值'
// },
{
value: '49',
label: '间谐波电流幅值'
}
]
},
{
label: '功率趋势',
options: [
{
value: '50',
label: '谐波有功功率'
},
{
value: '51',
label: '谐波无功功率'
},
{
value: '52',
label: '谐波视在功率'
},
{
value: '53',
label: '三相有功功率'
},
{
value: '54',
label: '三相无功功率'
},
{
value: '55',
label: '三相视在功率'
},
{
value: '56',
label: '三相总有功功率'
},
{
value: '57',
label: '三相总无功功率'
},
{
value: '58',
label: '三相总视在功率'
},
{
value: '59',
label: '视在功率因数'
},
{
value: '591',
label: '位移功率因数'
},
{
value: '592',
label: '总视在功率因数'
},
{
value: '593',
label: '总位移功率因数'
}
]
},
{
label: '闪变趋势',
options: [
{
value: '60',
label: '短时电压闪变'
},
{
value: '61',
label: '长时电压闪变'
},
{
value: '62',
label: '电压波动'
}
]
}
]
//谐波次数
export const harmonicOptions = [
{ label: '基波', value: 1 },
{ label: '2次', value: 2 },
{ label: '3次', value: 3 },
{ label: '4次', value: 4 },
{ label: '5次', value: 5 },
{ label: '6次', value: 6 },
{ label: '7次', value: 7 },
{ label: '8次', value: 8 },
{ label: '9次', value: 9 },
{ label: '10次', value: 10 },
{ label: '11次', value: 11 },
{ label: '12次', value: 12 },
{ label: '13次', value: 13 },
{ label: '14次', value: 14 },
{ label: '15次', value: 15 },
{ label: '16次', value: 16 },
{ label: '17次', value: 17 },
{ label: '18次', value: 18 },
{ label: '19次', value: 19 },
{ label: '20次', value: 20 },
{ label: '21次', value: 21 },
{ label: '22次', value: 22 },
{ label: '23次', value: 23 },
{ label: '24次', value: 24 },
{ label: '25次', value: 25 },
{ label: '26次', value: 26 },
{ label: '27次', value: 27 },
{ label: '28次', value: 28 },
{ label: '29次', value: 29 },
{ label: '30次', value: 30 },
{ label: '31次', value: 31 },
{ label: '32次', value: 32 },
{ label: '33次', value: 33 },
{ label: '34次', value: 34 },
{ label: '35次', value: 35 },
{ label: '36次', value: 36 },
{ label: '37次', value: 37 },
{ label: '38次', value: 38 },
{ label: '39次', value: 39 },
{ label: '40次', value: 40 },
{ label: '41次', value: 41 },
{ label: '42次', value: 42 },
{ label: '43次', value: 43 },
{ label: '44次', value: 44 },
{ label: '45次', value: 45 },
{ label: '46次', value: 46 },
{ label: '47次', value: 47 },
{ label: '48次', value: 48 },
{ label: '49次', value: 49 },
{ label: '50次', value: 50 }
]
export const harmonicOptions1 = [
{ label: '2次', value: 2 },
{ label: '3次', value: 3 },
{ label: '4次', value: 4 },
{ label: '5次', value: 5 },
{ label: '6次', value: 6 },
{ label: '7次', value: 7 },
{ label: '8次', value: 8 },
{ label: '9次', value: 9 },
{ label: '10次', value: 10 },
{ label: '11次', value: 11 },
{ label: '12次', value: 12 },
{ label: '13次', value: 13 },
{ label: '14次', value: 14 },
{ label: '15次', value: 15 },
{ label: '16次', value: 16 },
{ label: '17次', value: 17 },
{ label: '18次', value: 18 },
{ label: '19次', value: 19 },
{ label: '20次', value: 20 },
{ label: '21次', value: 21 },
{ label: '22次', value: 22 },
{ label: '23次', value: 23 },
{ label: '24次', value: 24 },
{ label: '25次', value: 25 },
{ label: '26次', value: 26 },
{ label: '27次', value: 27 },
{ label: '28次', value: 28 },
{ label: '29次', value: 29 },
{ label: '30次', value: 30 },
{ label: '31次', value: 31 },
{ label: '32次', value: 32 },
{ label: '33次', value: 33 },
{ label: '34次', value: 34 },
{ label: '35次', value: 35 },
{ label: '36次', value: 36 },
{ label: '37次', value: 37 },
{ label: '38次', value: 38 },
{ label: '39次', value: 39 },
{ label: '40次', value: 40 },
{ label: '41次', value: 41 },
{ label: '42次', value: 42 },
{ label: '43次', value: 43 },
{ label: '44次', value: 44 },
{ label: '45次', value: 45 },
{ label: '46次', value: 46 },
{ label: '47次', value: 47 },
{ label: '48次', value: 48 },
{ label: '49次', value: 49 },
{ label: '50次', value: 50 }
]
//简谐波次数
export const inharmonicOptions = [
{ label: '0.5次', value: 1 },
{ label: '1.5次', value: 2 },
{ label: '2.5次', value: 3 },
{ label: '3.5次', value: 4 },
{ label: '4.5次', value: 5 },
{ label: '5.5次', value: 6 },
{ label: '6.5次', value: 7 },
{ label: '7.5次', value: 8 },
{ label: '8.5次', value: 9 },
{ label: '9.5次', value: 10 },
{ label: '10.5次', value: 11 },
{ label: '11.5次', value: 12 },
{ label: '12.5次', value: 13 },
{ label: '13.5次', value: 14 },
{ label: '14.5次', value: 15 },
{ label: '15.5次', value: 16 },
{ label: '16.5次', value: 17 },
{ label: '17.5次', value: 18 },
{ label: '18.5次', value: 19 },
{ label: '19.5次', value: 20 },
{ label: '20.5次', value: 21 },
{ label: '21.5次', value: 22 },
{ label: '22.5次', value: 23 },
{ label: '23.5次', value: 24 },
{ label: '24.5次', value: 25 },
{ label: '25.5次', value: 26 },
{ label: '26.5次', value: 27 },
{ label: '27.5次', value: 28 },
{ label: '28.5次', value: 29 },
{ label: '29.5次', value: 30 },
{ label: '30.5次', value: 31 },
{ label: '31.5次', value: 32 },
{ label: '32.5次', value: 33 },
{ label: '33.5次', value: 34 },
{ label: '34.5次', value: 35 },
{ label: '35.5次', value: 36 },
{ label: '36.5次', value: 37 },
{ label: '37.5次', value: 38 },
{ label: '38.5次', value: 39 },
{ label: '39.5次', value: 40 },
{ label: '40.5次', value: 41 },
{ label: '41.5次', value: 42 },
{ label: '42.5次', value: 43 },
{ label: '43.5次', value: 44 },
{ label: '44.5次', value: 45 },
{ label: '45.5次', value: 46 },
{ label: '46.5次', value: 47 },
{ label: '47.5次', value: 48 },
{ label: '48.5次', value: 49 },
{ label: '49.5次', value: 50 },
]
//值类型
export const typeOptions = [
{ label: '平均值', value: 1 },
{ label: '最小值', value: 2 },
{ label: '最大值', value: 3 },
{ label: 'cp95值', value: 4 }
]

View File

@@ -11,6 +11,7 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (value > -1 && value < 0 && isMin == false) {
return 0
}
let base
if (Math.abs(o) >= 100) {
base = 100
@@ -19,8 +20,11 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (Math.abs(o) >= 1) {
base = 1
} else {
base = 0.1
const multiple = 1 / 0.1
base = Math.ceil(Math.abs(o) * multiple) / multiple
}
let calculatedValue
if (isMin) {
if (value < 0) {
@@ -35,18 +39,19 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
calculatedValue = value + num * value
}
}
if (base === 0.1) {
return parseFloat(calculatedValue.toFixed(1))
// return parseFloat(calculatedValue.toFixed(1))
return Math.ceil(calculatedValue * 10) / 10
} else if (isMin) {
return Math.floor(calculatedValue / base) * base
} else {
return Math.ceil(calculatedValue / base) * base
}
}
// 处理y轴最大最小值
export const yMethod = (arr: any) => {
let num = 0.1
let num = 0.2
let numList = dataProcessing(arr)
let maxValue = 0
let minValue = 0
@@ -54,12 +59,9 @@ export const yMethod = (arr: any) => {
let min = 0
maxValue = Math.max(...numList)
minValue = Math.min(...numList)
const o = maxValue - minValue
if (Math.abs(o) >= 300) {
num = 0.02
}
const o = maxValue - minValue == 0 ? maxValue : maxValue - minValue
min = calculateValue(o, minValue, num, true)
max = calculateValue(o, maxValue, num, false)
// if (-100 >= minValue) {
// min = Math.floor((minValue + num * minValue) / 100) * 100
@@ -158,8 +160,6 @@ export const exportCSV = (title: object, data: any, filename: string) => {
URL.revokeObjectURL(link.href)
}
/**
* 补全时间序列数据中缺失的条目
* @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...]

View File

@@ -1,8 +1,13 @@
import { downloadFile } from '@/api/system-boot/file'
const sanitizeUrl = (url: string): string => {
return url.replace(/\[/g, '(').replace(/\]/g, ')')
}
// 下载文件
export const download = (urls: string) => {
//console.log('下载', urls)
downloadFile({ filePath: urls })
.then((res: any) => {
// 1. 确定文件MIME类型优化用更简洁的方式
@@ -55,10 +60,8 @@ function removeLastDotSuffix(str: string) {
export const previewFile = async (urls: any) => {
//console.log('预览', urls)
let url = ''
//console.log('urls', decodeURI(urls))
await downloadFile({ filePath: decodeURI(urls) })
.then((res: any) => {
.then((res: any) => {
// 1. 确定文件MIME类型优化用更简洁的方式
const getFileType = (url: string) => {
const ext = url.split('.').pop()?.toLowerCase() || ''
@@ -74,11 +77,8 @@ export const previewFile = async (urls: any) => {
jpg: 'image/jpg'
}
return mimeMap[ext] || ''
}
}
const blob = new Blob([res], { type: getFileType(decodeURI(urls)) })
// 3. 创建下载链接
url = window.URL.createObjectURL(blob)
})

View File

@@ -27,8 +27,8 @@ class MQTT {
clean: true,
connectTimeout: 30 * 1000,
clientId: `mqttjs_${Math.random().toString(16).substr(2, 8)}`,
username: 't_user',
password: 'njcnpqs',
username: '',
password: '',
reconnectPeriod: 1000, // 默认1秒重试一次
maxReconnectTimes: 3 // 默认最大重连5次
}
@@ -50,12 +50,16 @@ class MQTT {
if (this.client) {
throw new Error('MQTT 客户端已初始化')
}
const mqttUrl = localStorage.getItem('MqttUrl')
console.log('MQTT URL:', mqttUrl)
if (!mqttUrl || mqttUrl === 'null') {
return Promise.resolve()
}
try {
const mqttUrl =
localStorage.getItem('MqttUrl') == 'null'
? 'ws://192.168.1.68:8083/mqtt'
: localStorage.getItem('MqttUrl')
// const mqttUrl =
// localStorage.getItem('MqttUrl') == 'null'
// ? 'ws://192.168.1.68:8083/mqtt'
// : localStorage.getItem('MqttUrl')
this.client = mqtt.connect(mqttUrl, this.defaultOptions as IClientOptions)
this.setupEventListeners()
@@ -77,12 +81,12 @@ class MQTT {
this.client?.on('error', error => {
clearTimeout(timeout)
console.error('MQTT 连接错误:', error)
console.log('MQTT 连接错误:', error)
reject(error)
})
})
} catch (error) {
console.error('初始化 MQTT 失败:', error)
// console.log('初始化 MQTT 失败:', error)
throw error
}
}
@@ -131,7 +135,7 @@ class MQTT {
return new Promise((resolve, reject) => {
this.client?.subscribe(this.topic, { qos: this.defaultOptions.qos, ...subscribeOptions }, error => {
if (error) {
console.error('订阅失败:', error)
console.log('订阅失败:', error)
reject(error)
} else {
console.log('订阅成功')
@@ -153,7 +157,7 @@ class MQTT {
return new Promise((resolve, reject) => {
this.client?.unsubscribe(this.topic, error => {
if (error) {
console.error('取消订阅失败:', error)
console.log('取消订阅失败:', error)
reject(error)
} else {
console.log('取消订阅成功')
@@ -188,7 +192,7 @@ class MQTT {
return new Promise((resolve, reject) => {
this.client?.publish(this.topic, message, { qos: this.defaultOptions.qos, ...options }, error => {
if (error) {
console.error('消息发布失败:', error)
console.log('消息发布失败:', error)
reject(error)
} else {
console.log('消息发布成功')

View File

@@ -104,11 +104,11 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
if (token) {
;(config.headers as anyObj).Authorization = token
} else {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
config.headers.Authorization = 'Basic bmpjbjpuamNucHFz'
}
}
if (config.url == '/user-boot/user/generateSm2Key' || config.url == '/pqs-auth/oauth/token') {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
config.headers.Authorization = 'Basic bmpjbjpuamNucHFz'
}
return config
@@ -145,12 +145,14 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
return refreshToken()
.then(res => {
adminInfo.setToken(res.data.access_token, 'auth')
adminInfo.setToken(res.data.refresh_token, 'refresh')
window.requests.forEach(cb => cb(res.data.access_token))
window.requests = []
return Axios(response.config)
})
.catch(err => {
window.location.reload()
adminInfo.removeToken()
router.push({ name: 'login' })
return Promise.reject(err)

View File

@@ -19,7 +19,7 @@ interface TableStoreParams {
publicHeight?: number //计算高度
resetCallback?: () => void // 重置
loadCallback?: () => void // 接口调用后的回调
exportProcessingData?:() => void //导出处理数据
exportProcessingData?: () => void //导出处理数据
beforeSearchFun?: () => void // 接口调用前的回调
}
@@ -45,8 +45,9 @@ export default class TableStore {
pageNum: 1,
pageSize: 20
},
filename:null,
filename: null,
loading: true,
exportLoading: false,
column: [],
loadCallback: null,
exportProcessingData: null,
@@ -65,7 +66,7 @@ export default class TableStore {
this.table.filename = options.filename || null
this.table.column = options.column
this.showPage = options.showPage !== false
this.table.publicHeight = options.publicHeight || 0
this.table.resetCallback = options.resetCallback || null
this.table.loadCallback = options.loadCallback || null
@@ -76,6 +77,7 @@ export default class TableStore {
}
index() {
this.table.beforeSearchFun && this.table.beforeSearchFun()
this.table.data = []
this.table.loading = true
@@ -84,13 +86,11 @@ export default class TableStore {
this.initData = JSON.parse(JSON.stringify(this.table.params))
}
if (!this.timeAll) {
delete this.table.params.startTime;
delete this.table.params.endTime;
delete this.table.params.searchBeginTime;
delete this.table.params.searchEndTime;
delete this.table.params.timeFlag;
delete this.table.params.startTime
delete this.table.params.endTime
delete this.table.params.searchBeginTime
delete this.table.params.searchEndTime
delete this.table.params.timeFlag
}
createAxios(
Object.assign(
@@ -98,10 +98,12 @@ export default class TableStore {
url: this.url,
method: this.method
},
requestPayload(this.method, this.table.params, this.paramsPOST)
)
)
.then((res: any) => {
if (res.data) {
this.table.data = res.data.records || res.data
this.table.total = res.data?.total || res.data.length || 0
@@ -130,13 +132,15 @@ export default class TableStore {
* @param data 携带数据
*/
onTableAction = (event: string, data: anyObj) => {
const actionFun = new Map([
[
'search',
() => {
this.table.params.pageNum = 1
this.index()
}
],
[
@@ -202,8 +206,10 @@ export default class TableStore {
[
'export',
() => {
this.table.exportLoading = true
// this.index()
console.log('export')
let params = { ...this.table.params, pageNum: 1, pageSize: this.table.total }
createAxios(
Object.assign(
@@ -213,12 +219,17 @@ export default class TableStore {
},
requestPayload(this.method, params, this.paramsPOST)
)
).then(res => {
this.table.allData = filtration(res.data.records || res.data)
console.log('11111',this.table)
this.table.exportProcessingData && this.table.exportProcessingData()
this.table.allFlag = data.showAllFlag || true
})
)
.then(res => {
this.table.allData = filtration(res.data.records || res.data)
this.table.exportProcessingData && this.table.exportProcessingData()
this.table.allFlag = data.showAllFlag || true
this.table.exportLoading = false
})
.catch(() => {
this.table.exportLoading = false
})
}
]
])

View File

@@ -1,400 +1,432 @@
interface TreeHelperConfig {
id: string
children: string
pid: string
}
const DEFAULT_CONFIG: TreeHelperConfig = {
id: 'id',
children: 'children',
pid: 'pid'
}
export const defaultProps = {
children: 'children',
label: 'name',
value: 'id',
isLeaf: 'leaf',
emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false则只返回该节点的值
}
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
// tree from list
export const listToTree = <T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] => {
const conf = getConfig(config) as TreeHelperConfig
const nodeMap = new Map()
const result: T[] = []
const { id, children, pid } = conf
for (const node of list) {
node[children] = node[children] || []
nodeMap.set(node[id], node)
}
for (const node of list) {
const parent = nodeMap.get(node[pid])
;(parent ? parent.children : result).push(node)
}
return result
}
export const treeToList = <T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T => {
config = getConfig(config)
const { children } = config
const result: any = [...tree]
for (let i = 0; i < result.length; i++) {
if (!result[i][children!]) continue
result.splice(i + 1, 0, ...result[i][children!])
}
return result
}
export const findNode = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T | null => {
config = getConfig(config)
const { children } = config
const list = [...tree]
for (const node of list) {
if (func(node)) return node
node[children!] && list.push(...node[children!])
}
return null
}
export const findNodeAll = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T[] => {
config = getConfig(config)
const { children } = config
const list = [...tree]
const result: T[] = []
for (const node of list) {
func(node) && result.push(node)
node[children!] && list.push(...node[children!])
}
return result
}
export const findPath = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T | T[] | null => {
config = getConfig(config)
const path: T[] = []
const list = [...tree]
const visitedSet = new Set()
const { children } = config
while (list.length) {
const node = list[0]
if (visitedSet.has(node)) {
path.pop()
list.shift()
} else {
visitedSet.add(node)
node[children!] && list.unshift(...node[children!])
path.push(node)
if (func(node)) {
return path
}
}
}
return null
}
export const findPathAll = (tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) => {
config = getConfig(config)
const path: any[] = []
const list = [...tree]
const result: any[] = []
const visitedSet = new Set(),
{ children } = config
while (list.length) {
const node = list[0]
if (visitedSet.has(node)) {
path.pop()
list.shift()
} else {
visitedSet.add(node)
node[children!] && list.unshift(...node[children!])
path.push(node)
func(node) && result.push([...path])
}
}
return result
}
export const filter = <T = any>(
tree: T[],
func: (n: T) => boolean,
config: Partial<TreeHelperConfig> = {}
): T[] => {
config = getConfig(config)
const children = config.children as string
function listFilter(list: T[]) {
return list
.map((node: any) => ({ ...node }))
.filter((node) => {
node[children] = node[children] && listFilter(node[children])
return func(node) || (node[children] && node[children].length)
})
}
return listFilter(tree)
}
export const forEach = <T = any>(
tree: T[],
func: (n: T) => any,
config: Partial<TreeHelperConfig> = {}
): void => {
config = getConfig(config)
const list: any[] = [...tree]
const { children } = config
for (let i = 0; i < list.length; i++) {
// func 返回true就终止遍历避免大量节点场景下无意义循环引起浏览器卡顿
if (func(list[i])) {
return
}
children && list[i][children] && list.splice(i + 1, 0, ...list[i][children])
}
}
/**
* @description: Extract tree specified structure
*/
export const treeMap = <T = any>(
treeData: T[],
opt: { children?: string; conversion: Fn }
): T[] => {
return treeData.map((item) => treeMapEach(item, opt))
}
/**
* @description: Extract tree specified structure
*/
export const treeMapEach = (
data: any,
{ children = 'children', conversion }: { children?: string; conversion: Fn }
) => {
const haveChildren = Array.isArray(data[children]) && data[children].length > 0
const conversionData = conversion(data) || {}
if (haveChildren) {
return {
...conversionData,
[children]: data[children].map((i: number) =>
treeMapEach(i, {
children,
conversion
})
)
}
} else {
return {
...conversionData
}
}
}
/**
* 递归遍历树结构
* @param treeDatas 树
* @param callBack 回调
* @param parentNode 父节点
*/
export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => {
treeDatas.forEach((element) => {
const newNode = callBack(element, parentNode) || element
if (element.children) {
eachTree(element.children, callBack, newNode)
}
})
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => {
if (!Array.isArray(data)) {
console.warn('data must be an array')
return []
}
const config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
}
const childrenListMap = {}
const nodeIds = {}
const tree: any[] = []
for (const d of data) {
const parentId = d[config.parentId]
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = []
}
nodeIds[d[config.id]] = d
childrenListMap[parentId].push(d)
}
for (const d of data) {
const parentId = d[config.parentId]
if (nodeIds[parentId] == null) {
tree.push(d)
}
}
for (const t of tree) {
adaptToChildrenList(t)
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]]
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c)
}
}
}
return tree
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
* @param {*} rootId 根Id 默认 0
*/
// @ts-ignore
export const handleTree2 = (data, id, parentId, children, rootId) => {
id = id || 'id'
parentId = parentId || 'parentId'
// children = children || 'children'
rootId =
rootId ||
Math.min(
...data.map((item) => {
return item[parentId]
})
) ||
0
// 对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
// 循环所有项
const treeData = cloneData.filter((father) => {
const branchArr = cloneData.filter((child) => {
// 返回每一项的子级数组
return father[id] === child[parentId]
})
branchArr.length > 0 ? (father.children = branchArr) : ''
// 返回第一层
return father[parentId] === rootId
})
return treeData !== '' ? treeData : data
}
/**
* 校验选中的节点,是否为指定 level
*
* @param tree 要操作的树结构数据
* @param nodeId 需要判断在什么层级的数据
* @param level 检查的级别, 默认检查到二级
* @return true 是false 否
*/
export const checkSelectedNode = (tree: any[], nodeId: any, level = 2): boolean => {
if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
console.warn('tree must be an array')
return false
}
// 校验是否是一级节点
if (tree.some((item) => item.id === nodeId)) {
return false
}
// 递归计数
let count = 1
// 深层次校验
function performAThoroughValidation(arr: any[]): boolean {
count += 1
for (const item of arr) {
if (item.id === nodeId) {
return true
} else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
if (performAThoroughValidation(item.children)) {
return true
}
}
}
return false
}
for (const item of tree) {
count = 1
if (performAThoroughValidation(item.children)) {
// 找到后对比是否是期望的层级
if (count >= level) {
return true
}
}
}
return false
}
/**
* 获取节点的完整结构
* @param tree 树数据
* @param nodeId 节点 id
*/
export const treeToString = (tree: any[], nodeId) => {
if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
console.warn('tree must be an array')
return ''
}
// 校验是否是一级节点
const node = tree.find((item) => item.id === nodeId)
if (typeof node !== 'undefined') {
return node.name
}
let str = ''
function performAThoroughValidation(arr) {
for (const item of arr) {
if (item.id === nodeId) {
str += ` / ${item.name}`
return true
} else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
str += ` / ${item.name}`
if (performAThoroughValidation(item.children)) {
return true
}
}
}
return false
}
for (const item of tree) {
str = `${item.name}`
if (performAThoroughValidation(item.children)) {
break
}
}
return str
}
interface TreeHelperConfig {
id: string
children: string
pid: string
}
const DEFAULT_CONFIG: TreeHelperConfig = {
id: 'id',
children: 'children',
pid: 'pid'
}
export const defaultProps = {
children: 'children',
label: 'name',
value: 'id',
isLeaf: 'leaf',
emitPath: false // 用于 cascader 组件:在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false则只返回该节点的值
}
const getConfig = (config: Partial<TreeHelperConfig>) => Object.assign({}, DEFAULT_CONFIG, config)
// tree from list
export const listToTree = <T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] => {
const conf = getConfig(config) as TreeHelperConfig
const nodeMap = new Map()
const result: T[] = []
const { id, children, pid } = conf
for (const node of list) {
node[children] = node[children] || []
nodeMap.set(node[id], node)
}
for (const node of list) {
const parent = nodeMap.get(node[pid])
;(parent ? parent.children : result).push(node)
}
return result
}
export const treeToList = <T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T => {
config = getConfig(config)
const { children } = config
const result: any = [...tree]
for (let i = 0; i < result.length; i++) {
if (!result[i][children!]) continue
result.splice(i + 1, 0, ...result[i][children!])
}
return result
}
export const findNode = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T | null => {
config = getConfig(config)
const { children } = config
const list = [...tree]
for (const node of list) {
if (func(node)) return node
node[children!] && list.push(...node[children!])
}
return null
}
export const findNodeAll = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T[] => {
config = getConfig(config)
const { children } = config
const list = [...tree]
const result: T[] = []
for (const node of list) {
func(node) && result.push(node)
node[children!] && list.push(...node[children!])
}
return result
}
export const findPath = <T = any>(
tree: any,
func: Fn,
config: Partial<TreeHelperConfig> = {}
): T | T[] | null => {
config = getConfig(config)
const path: T[] = []
const list = [...tree]
const visitedSet = new Set()
const { children } = config
while (list.length) {
const node = list[0]
if (visitedSet.has(node)) {
path.pop()
list.shift()
} else {
visitedSet.add(node)
node[children!] && list.unshift(...node[children!])
path.push(node)
if (func(node)) {
return path
}
}
}
return null
}
export const findPathAll = (tree: any, func: Fn, config: Partial<TreeHelperConfig> = {}) => {
config = getConfig(config)
const path: any[] = []
const list = [...tree]
const result: any[] = []
const visitedSet = new Set(),
{ children } = config
while (list.length) {
const node = list[0]
if (visitedSet.has(node)) {
path.pop()
list.shift()
} else {
visitedSet.add(node)
node[children!] && list.unshift(...node[children!])
path.push(node)
func(node) && result.push([...path])
}
}
return result
}
export const filter = <T = any>(
tree: T[],
func: (n: T) => boolean,
config: Partial<TreeHelperConfig> = {}
): T[] => {
config = getConfig(config)
const children = config.children as string
function listFilter(list: T[]) {
return list
.map((node: any) => ({ ...node }))
.filter((node) => {
node[children] = node[children] && listFilter(node[children])
return func(node) || (node[children] && node[children].length)
})
}
return listFilter(tree)
}
export const filterTree = <T = any>(
tree: T[],
func: (n: T) => boolean,
config: Partial<TreeHelperConfig> = {}
): T[] => {
config = getConfig(config)
const children = config.children as string
function listFilter(list: T[]) {
return list
.map((node: any) => ({ ...node }))
.filter((node) => {
// 1. 如果当前节点匹配 → 直接保留【所有子节点】,不再过滤下级
if (func(node)) {
return true;
}
// 2. 如果当前节点不匹配,递归过滤子节点
if (node[children]) {
const filteredChildren = listFilter(node[children]);
if (filteredChildren.length > 0) {
node[children] = filteredChildren;
return true;
}
}
// 3. 都不匹配,过滤掉
return false;
})
}
return listFilter(tree)
}
export const forEach = <T = any>(
tree: T[],
func: (n: T) => any,
config: Partial<TreeHelperConfig> = {}
): void => {
config = getConfig(config)
const list: any[] = [...tree]
const { children } = config
for (let i = 0; i < list.length; i++) {
// func 返回true就终止遍历避免大量节点场景下无意义循环引起浏览器卡顿
if (func(list[i])) {
return
}
children && list[i][children] && list.splice(i + 1, 0, ...list[i][children])
}
}
/**
* @description: Extract tree specified structure
*/
export const treeMap = <T = any>(
treeData: T[],
opt: { children?: string; conversion: Fn }
): T[] => {
return treeData.map((item) => treeMapEach(item, opt))
}
/**
* @description: Extract tree specified structure
*/
export const treeMapEach = (
data: any,
{ children = 'children', conversion }: { children?: string; conversion: Fn }
) => {
const haveChildren = Array.isArray(data[children]) && data[children].length > 0
const conversionData = conversion(data) || {}
if (haveChildren) {
return {
...conversionData,
[children]: data[children].map((i: number) =>
treeMapEach(i, {
children,
conversion
})
)
}
} else {
return {
...conversionData
}
}
}
/**
* 递归遍历树结构
* @param treeDatas 树
* @param callBack 回调
* @param parentNode 父节点
*/
export const eachTree = (treeDatas: any[], callBack: Fn, parentNode = {}) => {
treeDatas.forEach((element) => {
const newNode = callBack(element, parentNode) || element
if (element.children) {
eachTree(element.children, callBack, newNode)
}
})
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export const handleTree = (data: any[], id?: string, parentId?: string, children?: string) => {
if (!Array.isArray(data)) {
console.warn('data must be an array')
return []
}
const config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
}
const childrenListMap = {}
const nodeIds = {}
const tree: any[] = []
for (const d of data) {
const parentId = d[config.parentId]
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = []
}
nodeIds[d[config.id]] = d
childrenListMap[parentId].push(d)
}
for (const d of data) {
const parentId = d[config.parentId]
if (nodeIds[parentId] == null) {
tree.push(d)
}
}
for (const t of tree) {
adaptToChildrenList(t)
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]]
}
if (o[config.childrenList]) {
for (const c of o[config.childrenList]) {
adaptToChildrenList(c)
}
}
}
return tree
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
* @param {*} rootId 根Id 默认 0
*/
// @ts-ignore
export const handleTree2 = (data, id, parentId, children, rootId) => {
id = id || 'id'
parentId = parentId || 'parentId'
// children = children || 'children'
rootId =
rootId ||
Math.min(
...data.map((item) => {
return item[parentId]
})
) ||
0
// 对源数据深度克隆
const cloneData = JSON.parse(JSON.stringify(data))
// 循环所有项
const treeData = cloneData.filter((father) => {
const branchArr = cloneData.filter((child) => {
// 返回每一项的子级数组
return father[id] === child[parentId]
})
branchArr.length > 0 ? (father.children = branchArr) : ''
// 返回第一层
return father[parentId] === rootId
})
return treeData !== '' ? treeData : data
}
/**
* 校验选中的节点,是否为指定 level
*
* @param tree 要操作的树结构数据
* @param nodeId 需要判断在什么层级的数据
* @param level 检查的级别, 默认检查到二级
* @return true 是false 否
*/
export const checkSelectedNode = (tree: any[], nodeId: any, level = 2): boolean => {
if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
console.warn('tree must be an array')
return false
}
// 校验是否是一级节点
if (tree.some((item) => item.id === nodeId)) {
return false
}
// 递归计数
let count = 1
// 深层次校验
function performAThoroughValidation(arr: any[]): boolean {
count += 1
for (const item of arr) {
if (item.id === nodeId) {
return true
} else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
if (performAThoroughValidation(item.children)) {
return true
}
}
}
return false
}
for (const item of tree) {
count = 1
if (performAThoroughValidation(item.children)) {
// 找到后对比是否是期望的层级
if (count >= level) {
return true
}
}
}
return false
}
/**
* 获取节点的完整结构
* @param tree 树数据
* @param nodeId 节点 id
*/
export const treeToString = (tree: any[], nodeId) => {
if (typeof tree === 'undefined' || !Array.isArray(tree) || tree.length === 0) {
console.warn('tree must be an array')
return ''
}
// 校验是否是一级节点
const node = tree.find((item) => item.id === nodeId)
if (typeof node !== 'undefined') {
return node.name
}
let str = ''
function performAThoroughValidation(arr) {
for (const item of arr) {
if (item.id === nodeId) {
str += ` / ${item.name}`
return true
} else if (typeof item.children !== 'undefined' && item.children.length !== 0) {
str += ` / ${item.name}`
if (performAThoroughValidation(item.children)) {
return true
}
}
}
return false
}
for (const item of tree) {
str = `${item.name}`
if (performAThoroughValidation(item.children)) {
break
}
}
return str
}

View File

@@ -43,13 +43,11 @@ export default class SocketService {
console.log('您的浏览器不支持WebSocket')
return
}
console.log("🚀 ~ SocketService ~ connect ~ url:", url)
if (url === null || (typeof url === 'string' && url.includes('null'))) return;
setTimeout(() => {
// ws://192.168.1.69:10407/mgtt
// const url =
// (localStorage.getItem('WebSocketUrl') == 'null'
// ? 'ws://192.168.1.130:10405'
// : localStorage.getItem('WebSocketUrl')) + id
this.ws = new WebSocket(url)
this.ws.onopen = () => this.handleOpen()
@@ -58,7 +56,6 @@ export default class SocketService {
this.ws.onmessage = event => this.handleMessage(event)
}, 0)
}
// 处理连接成功事件
private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了')
@@ -90,7 +87,7 @@ export default class SocketService {
if (event.data == '连接成功') {
this.sendHeartbeat()
} else if (event.data == 'connect') {
} else if (event.data == 'over') {
} else if (event.data.length > 10) {
let message: MessageType
try {
@@ -104,7 +101,7 @@ export default class SocketService {
// 通过接受服务端发送的type字段来回调函数
if ((message.key || message.code) && this.callBackMapping['message']) {
if ((message.key || message.code || message.time) && this.callBackMapping['message']) {
this.callBackMapping['message']!(message)
} else {
console.log('抛弃====>')
@@ -112,6 +109,7 @@ export default class SocketService {
// 丢弃或继续写你的逻辑
}
} else {
this.callBackMapping['message']!({ Flag: false })
ElMessage.error(event.data)
}
}

View File

@@ -301,7 +301,7 @@ const options1 = [
const height = mainHeight(20)
const heightB = mainHeight(448)
const heightA = mainHeight(180)
const size = ref(23)
const size = ref(19)
const TableHeaderRef = ref()
const detailRef = ref()
const dotList: any = ref({})
@@ -786,7 +786,7 @@ onMounted(() => {
})
const handleNodeClick = (data: any, node: any) => {
console.log('🚀 ~ handleNodeClick ~ data:', data)
//console.log('🚀 ~ handleNodeClick ~ data:', data)
if (data.level == 6) {
dotList.value = data
// dotList.value.id = '6469e77fda42db12c7ca6620a092f03c1'

View File

@@ -321,7 +321,7 @@ const options1 = [
]
const height = mainHeight(20)
const heightB = mainHeight(445)
const size = ref(23)
const size = ref(19)
const TableHeaderRef = ref()
const detailRef = ref()
const dotList: any = ref({})
@@ -757,7 +757,7 @@ const timeClick = (row: any) => {
}
// 点击越限
const detailClick = (row: any, title: string, key: string) => {
console.log('🚀 ~ detailClick ~ row:', row)
// console.log('🚀 ~ detailClick ~ row:', row)
detailRef.value.open({
row: row,
title: title,
@@ -802,7 +802,7 @@ onMounted(() => {
})
const handleNodeClick = (data: any, node: any) => {
console.log('🚀 ~ handleNodeClick ~ data:', data)
// console.log('🚀 ~ handleNodeClick ~ data:', data)
if (data.level == 6) {
dotList.value = data
// dotList.value.id = '6469e77fda42db12c7ca6620a092f03c1'

View File

@@ -1,125 +1,125 @@
<template>
<div class="default-main">
<TableHeader ref="TableHeaderRef">
<template #select>
<el-form-item label="新能源场站名称">
<el-input v-model="tableStore.table.params.name" clearable placeholder="输入关键字筛选" />
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<!--弹框-->
<addForm ref="addFormRef" @onSubmit="tableStore.index()" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import addForm from './components/addForm.vue'
import { useDictData } from '@/stores/dictData'
import { useAdminInfo } from '@/stores/adminInfo'
import { delNewStation } from '@/api/device-boot/newEnergy'
defineOptions({
name: 'newEnergy/newEnergyLedger'
})
const dictData = useDictData()
//获取登陆用户姓名和部门
const adminInfo = useAdminInfo()
const newEnergy = dictData.getBasicData('new_station_type')
const scaleList = dictData.getBasicData('Dev_Voltage_Stand')
const tableRef = ref()
const TableHeaderRef = ref()
const addFormRef = ref()
const tableStore = new TableStore({
url: '/device-boot/newStation/queryPage',
method: 'POST',
column: [
{
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'name', title: '新能源场站名称' },
{
field: 'stationType',
title: '新能源场站类型',
formatter: (row: any) => newEnergy.filter(item => item.id == row.cellValue)[0]?.name
},
{
field: 'scale',
title: '电压等级',
formatter: (row: any) => scaleList.filter(item => item.id == row.cellValue)[0]?.name
},
{ field: 'ratedPower', title: '额定有功功率(kW)' },
{ field: 'longitude', title: '经度' },
{ field: 'latitude', title: '纬度' },
{
title: '操作',
align: 'center',
render: 'buttons',
fixed: 'right',
buttons: [
{
name: 'edit',
title: '修改',
type: 'primary',
icon: 'el-icon-edit',
render: 'basicButton',
click: row => {
addFormRef.value.open({
title: '修改',
row: row
})
}
},
{
name: 'delete',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定删除该数据吗?'
},
click: row => {
delNewStation({ ids: row.id }).then(() => {
ElMessage.success('删除成功')
tableStore.index()
})
}
}
]
}
],
beforeSearchFun: () => {
tableStore.table.params.currentPage = tableStore.table.params.pageNum
},
loadCallback: () => {}
})
tableStore.table.params.name = ''
const add = () => {
addFormRef.value.open({
title: '新增'
})
}
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
</script>
<style scoped lang="scss"></style>
<template>
<div class="default-main">
<TableHeader ref="TableHeaderRef">
<template #select>
<el-form-item label="新能源场站名称">
<el-input v-model="tableStore.table.params.name" clearable placeholder="输入关键字筛选" />
</el-form-item>
</template>
<template #operation>
<el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<!--弹框-->
<addForm ref="addFormRef" @onSubmit="tableStore.index()" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import addForm from './components/addForm.vue'
import { useDictData } from '@/stores/dictData'
import { useAdminInfo } from '@/stores/adminInfo'
import { delNewStation } from '@/api/device-boot/newEnergy'
defineOptions({
name: 'newEnergy/newEnergyLedger'
})
const dictData = useDictData()
//获取登陆用户姓名和部门
const adminInfo = useAdminInfo()
const newEnergy = dictData.getBasicData('new_station_type')
const scaleList = dictData.getBasicData('Dev_Voltage_Stand')
const tableRef = ref()
const TableHeaderRef = ref()
const addFormRef = ref()
const tableStore = new TableStore({
url: '/device-boot/newStation/queryPage',
method: 'POST',
column: [
{
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'name', title: '新能源场站名称' },
{
field: 'stationType',
title: '新能源场站类型',
formatter: (row: any) => newEnergy.filter(item => item.id == row.cellValue)[0]?.name
},
{
field: 'scale',
title: '电压等级',
formatter: (row: any) => scaleList.filter(item => item.id == row.cellValue)[0]?.name
},
{ field: 'ratedPower', title: '额定有功功率(kW)' },
{ field: 'longitude', title: '经度' },
{ field: 'latitude', title: '纬度' },
{
title: '操作',fixed: 'right',
align: 'center',
render: 'buttons',
buttons: [
{
name: 'edit',
title: '修改',
type: 'primary',
icon: 'el-icon-edit',
render: 'basicButton',
click: row => {
addFormRef.value.open({
title: '修改',
row: row
})
}
},
{
name: 'delete',
title: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定删除该数据吗?'
},
click: row => {
delNewStation({ ids: row.id }).then(() => {
ElMessage.success('删除成功')
tableStore.index()
})
}
}
]
}
],
beforeSearchFun: () => {
tableStore.table.params.currentPage = tableStore.table.params.pageNum
},
loadCallback: () => {}
})
tableStore.table.params.name = ''
const add = () => {
addFormRef.value.open({
title: '新增'
})
}
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
</script>
<style scoped lang="scss"></style>

View File

@@ -38,6 +38,7 @@ const tableStore = new TableStore({
echarts.value.Grade(tableStore.table.data.voltageStatistics)
echarts.value.Relation(tableStore.table.data.monthlyStatistics)
table.value.info(tableStore.table.data)
}
})
provide('tableStore', tableStore)

View File

@@ -90,7 +90,6 @@ const loading = ref(false)
const statistics = ref()
const flg = ref(true)
const showMqtt = ref(false)
const zoom = ref('') //图表焦点校验
const resultList = ref([

View File

@@ -3,7 +3,7 @@
<TableHeader datePicker :showReset="false" showExport ref="TableHeaderRef">
<template v-slot:select>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.loginName" placeholder="请输入"></el-input>
<el-input v-model="tableStore.table.params.loginName" placeholder="请输入" clearable maxlength="32" show-word-limit></el-input>
</el-form-item>
</template>
</TableHeader>

View File

@@ -288,18 +288,21 @@ const equipment = (row: any) => {}
// 承载能力评估
const assess = () => {
// vxeRef.value.getRadioRecord()
if (equipmentList.value.length == null) {
return ElMessage.warning('请选择用户')
if (equipmentList.value.length == 0) {
return ElMessage.warning('请选择有终端设备的用户')
}
loading.value = true
formRef.value.validate((valid: any) => {
if (valid) {
form.value.devList = equipmentList.value
carryCapacityEvaluate(form.value).then(res => {
rendering(res.data)
loading.value = false
})
}else{
loading.value = false
}
})
}
@@ -450,7 +453,7 @@ const selChange = async (e: any) => {
}
// 导出
const onExport = () => {
console.log("🚀 ~ onExport ~ document.getElementById('exportId'):", document.getElementById('exportId'))
// console.log("🚀 ~ onExport ~ document.getElementById('exportId'):", document.getElementById('exportId'))
// 转换成canvas
html2canvas(document.getElementById('exportId'), {
@@ -459,7 +462,7 @@ const onExport = () => {
logging: false, // 关闭日志
scale: 2 // 提高缩放比例以获得更清晰的截图
}).then(function (canvas) {
console.log('🚀 ~ onExport ~ canvas:', canvas)
// console.log('🚀 ~ onExport ~ canvas:', canvas)
// 创建a标签实现下载
let creatIMg = document.createElement('a')
creatIMg.download = '光伏电站承载能力评估结果.png' // 设置下载的文件名,

View File

@@ -183,7 +183,7 @@ import TableHeader from '@/components/table/header/index.vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import { useMonitoringPoint } from '@/stores/monitoringPoint'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { harmonicOptions } from '@/utils/dictionary'
import { harmonicOptions1 } from '@/utils/dictionary'
import { Select } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import {
@@ -202,10 +202,10 @@ import html2canvas from 'html2canvas'
import { yMethod } from '@/utils/echartMethod'
import { useDictData } from '@/stores/dictData'
const props = defineProps(['rowList'])
const harmonic = harmonicOptions.filter(item => item.value < 26)
const harmonic = harmonicOptions1.filter(item => item.value < 26)
const currentLod = ref(false)
const monitoringPoint = useMonitoringPoint()
const size = ref(23)
const size = ref(19)
const dictData = useDictData()
const datePickerRef = ref()
const height = mainHeight(80).height
@@ -734,6 +734,7 @@ const choose = (e: any) => {
uploadExcel(e.raw, form).then(res => {
ElMessage.success('导入成功')
onSubmit()
})
}
const tabChange = (e: any) => {
@@ -843,7 +844,7 @@ onMounted(() => {
}
.btnBox {
display: flex;
justify-content: end;
justify-content: flex-end;
}
:deep(.vxe-table--header thead tr:first-of-type th:first-of-type) {

View File

@@ -176,7 +176,7 @@ const info = () => {
})
})
})
console.log('🚀 ~ queyDetail ~ photovoltaicData.value:', photovoltaicData.value)
// console.log('🚀 ~ queyDetail ~ photovoltaicData.value:', photovoltaicData.value)
})
// 电弧炉
queyDetailDhl().then(res => {

View File

@@ -136,7 +136,7 @@ const tableStore: any = new TableStore({
{ field: 'evaluateDate', title: '评估日期' },
{
title: '操作',
title: '操作',fixed: 'right',
width: '180',
render: 'buttons',
buttons: [
@@ -157,7 +157,7 @@ const tableStore: any = new TableStore({
},
{
name: 'del',
text: '禁止接入',
text: '删除',
type: 'danger',
icon: 'el-icon-Delete',
render: 'confirmButton',
@@ -165,11 +165,11 @@ const tableStore: any = new TableStore({
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'danger',
title: '确定禁止接入'
title: '确定删除'
},
click: row => {
remove({ ids: row.id }).then(() => {
ElMessage.success('禁止接入成功')
ElMessage.success('删除成功')
tableStore.index()
})
}

View File

@@ -1,163 +1,163 @@
<template>
<el-dialog draggable class="cn-operate-dialog" v-model="dialogVisible" title="设备">
<div class="formBox mb10"><el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button></div>
<vxe-table v-bind="defaultAttribute" v-loading="loading" height="500px" ref="xTable" :data="userData">
<vxe-column field="devName" title="设备名称"></vxe-column>
<vxe-column field="devScale" title="电压等级" :formatter="formatter"></vxe-column>
<vxe-column field="protocolCapacity" title="设备容量(MVA)"></vxe-column>
<vxe-column title="操作" width="120px">
<template #default="{ row }">
<el-button type="primary" size="small" link @click="revise(row)">修改</el-button>
<el-popconfirm @confirm="deleteD(row)" title="确认删除设备?">
<template #reference>
<el-button type="danger" size="small" link>删除</el-button>
</template>
</el-popconfirm>
</template>
</vxe-column>
</vxe-table>
</el-dialog>
<el-dialog draggable v-model="addShow" width="400px" :title="title" :before-close="handleClose">
<el-form :model="form" ref="formRef" :rules="rules" label-width="auto">
<el-form-item label="设备名称" prop="devName">
<el-input
v-model.trim="form.devName"
placeholder="请输入设备名称"
maxlength="32"
show-word-limit
clearable
/>
</el-form-item>
<el-form-item label="电压等级" prop="devScale">
<el-select v-model="form.devScale" clearable placeholder="请选择电压等级">
<el-option v-for="item in levelList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="设备容量(MVA)" prop="protocolCapacity">
<el-input-number
v-model="form.protocolCapacity"
style="width: 100%"
:min="0"
:max="10000000"
placeholder="请选择设备容量"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { queyDeviceList, addDev, updateDev, removeDev } from '@/api/advance-boot/bearingCapacity'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { useDictData } from '@/stores/dictData'
import { ElMessage } from 'element-plus'
const dictData = useDictData()
const levelList = dictData.getBasicData('Dev_Voltage_Stand')
const dialogVisible = ref(false)
const addShow = ref(false)
const loading = ref(false)
const userData = ref([])
const rowList = ref([])
const title = ref('')
const formRef = ref()
const form: any = ref({
devName: '',
devScale: '',
protocolCapacity: 0,
userId: ''
})
const rules = {
devName: [{ required: true, message: '请输入设备名称', trigger: 'blur' }],
devScale: [{ required: true, message: '请输入设备名称', trigger: 'change' }],
protocolCapacity: [{ required: true, message: '请输入设备名称', trigger: 'blur' }]
}
const open = (row: any) => {
dialogVisible.value = true
loading.value = true
rowList.value = row
queyDeviceList({
userId: row.userId
}).then(res => {
loading.value = false
userData.value = res.data
})
}
// 新增
const add = () => {
addShow.value = true
title.value = '新增设备'
}
// 过滤数据
const formatter = (row: any) => {
if (row.column.field == 'devScale') {
return levelList.filter(item => item.id == row.cellValue)[0].name
} else {
return row.cellValue
}
}
// 修改
const revise = (row: any) => {
form.value = JSON.parse(JSON.stringify(row))
title.value = '修改设备'
addShow.value = true
}
// 关闭弹框
const handleClose = () => {
addShow.value = false
form.value = {
devName: '',
devScale: '',
protocolCapacity: 0,
userId: ''
}
formRef.value.resetFields()
}
// 新增设备
const submitForm = async () => {
await formRef.value.validate(valid => {
if (valid) {
if (title.value == '新增设备') {
form.value.userId = rowList.value.userId
addDev(form.value).then(res => {
ElMessage.success('新增成功!')
open(rowList.value)
handleClose()
})
} else {
updateDev(form.value).then(res => {
ElMessage.success('修改成功!')
open(rowList.value)
handleClose()
})
}
}
})
}
// 删除设备
const deleteD = row => {
removeDev({ devIds: row.devId }).then(res => {
ElMessage.success('删除设备成功!')
open(rowList.value)
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.formBox{
display: flex;
justify-content: end;
}
</style>
<template>
<el-dialog draggable class="cn-operate-dialog" v-model="dialogVisible" title="设备">
<div class="formBox mb10"><el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button></div>
<vxe-table v-bind="defaultAttribute" v-loading="loading" height="500px" ref="xTable" :data="userData">
<vxe-column field="devName" title="设备名称"></vxe-column>
<vxe-column field="devScale" title="电压等级" :formatter="formatter"></vxe-column>
<vxe-column field="protocolCapacity" title="设备容量(MVA)"></vxe-column>
<vxe-column title="操作" width="120px">
<template #default="{ row }">
<el-button type="primary" size="small" link @click="revise(row)">修改</el-button>
<el-popconfirm @confirm="deleteD(row)" title="确认删除设备?">
<template #reference>
<el-button type="danger" size="small" link>删除</el-button>
</template>
</el-popconfirm>
</template>
</vxe-column>
</vxe-table>
</el-dialog>
<el-dialog draggable v-model="addShow" width="400px" :title="title" :before-close="handleClose">
<el-form :model="form" ref="formRef" :rules="rules" label-width="auto">
<el-form-item label="设备名称" prop="devName">
<el-input
v-model.trim="form.devName"
placeholder="请输入设备名称"
maxlength="32"
show-word-limit
clearable
/>
</el-form-item>
<el-form-item label="电压等级" prop="devScale">
<el-select v-model="form.devScale" clearable placeholder="请选择电压等级">
<el-option v-for="item in levelList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="设备容量(MVA)" prop="protocolCapacity">
<el-input-number
v-model="form.protocolCapacity"
style="width: 100%"
:min="0"
:max="10000000"
placeholder="请选择设备容量"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { queyDeviceList, addDev, updateDev, removeDev } from '@/api/advance-boot/bearingCapacity'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { useDictData } from '@/stores/dictData'
import { ElMessage } from 'element-plus'
const dictData = useDictData()
const levelList = dictData.getBasicData('Dev_Voltage_Stand')
const dialogVisible = ref(false)
const addShow = ref(false)
const loading = ref(false)
const userData = ref([])
const rowList = ref([])
const title = ref('')
const formRef = ref()
const form: any = ref({
devName: '',
devScale: '',
protocolCapacity: 0,
userId: ''
})
const rules = {
devName: [{ required: true, message: '请输入设备名称', trigger: 'blur' }],
devScale: [{ required: true, message: '请输入设备名称', trigger: 'change' }],
protocolCapacity: [{ required: true, message: '请输入设备名称', trigger: 'blur' }]
}
const open = (row: any) => {
dialogVisible.value = true
loading.value = true
rowList.value = row
queyDeviceList({
userId: row.userId
}).then(res => {
loading.value = false
userData.value = res.data
})
}
// 新增
const add = () => {
addShow.value = true
title.value = '新增设备'
}
// 过滤数据
const formatter = (row: any) => {
if (row.column.field == 'devScale') {
return levelList.filter(item => item.id == row.cellValue)[0].name
} else {
return row.cellValue
}
}
// 修改
const revise = (row: any) => {
form.value = JSON.parse(JSON.stringify(row))
title.value = '修改设备'
addShow.value = true
}
// 关闭弹框
const handleClose = () => {
addShow.value = false
form.value = {
devName: '',
devScale: '',
protocolCapacity: 0,
userId: ''
}
formRef.value.resetFields()
}
// 新增设备
const submitForm = async () => {
await formRef.value.validate(valid => {
if (valid) {
if (title.value == '新增设备') {
form.value.userId = rowList.value.userId
addDev(form.value).then(res => {
ElMessage.success('新增成功!')
open(rowList.value)
handleClose()
})
} else {
updateDev(form.value).then(res => {
ElMessage.success('修改成功!')
open(rowList.value)
handleClose()
})
}
}
})
}
// 删除设备
const deleteD = row => {
removeDev({ devIds: row.devId }).then(res => {
ElMessage.success('删除设备成功!')
open(rowList.value)
})
}
defineExpose({ open })
</script>
<style lang="scss" scoped>
.formBox{
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -57,9 +57,15 @@
<el-form-item label="区域" prop="regionList">
<!-- <el-cascader v-model="form.regionList" style="width: 100%" :props="props" :options="areaList" /> -->
<el-cascader v-model="form.regionList" :props="props" :options="areaList" style="width: 100%" placeholder="请选择区域" />
<el-cascader
v-model="form.regionList"
:props="props"
:options="areaList"
style="width: 100%"
placeholder="请选择区域"
/>
</el-form-item>
<el-form-item label="详细地址:" prop="area">
<el-input
clearable
@@ -95,7 +101,7 @@ import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData'
import equipment from './equipment.vue'
import { addUse, updateUse, removeUse } from '@/api/advance-boot/bearingCapacity'
import { getAreaDept } from '@/api/harmonic-boot/area'
import { getAreaDept, getAreaDeptRemoveMode } from '@/api/harmonic-boot/area'
defineOptions({
name: 'estimate/photovoltaic'
@@ -108,8 +114,9 @@ const disabled = ref(false)
const TableHeaderRef = ref()
const equipmentRef = ref()
const title = ref('')
const VITE_FLAG = import.meta.env.VITE_NAME == 'removeMode'
//const areaList: any = dictData.areaSelect()
const areaList = ref([])
const areaList: any = ref([])
const userShow: any = ref('Power_Station_Users')
const form = ref({
@@ -188,6 +195,7 @@ const tableStore: any = new TableStore({
{ field: 'createTime', title: '创建日期' },
{
title: '操作',
fixed: 'right',
width: '180',
render: 'buttons',
buttons: [
@@ -258,9 +266,7 @@ const tableStore: any = new TableStore({
}
],
loadCallback: () => {
console.log(tableStore.table.data)
}
loadCallback: () => {}
})
tableStore.table.params.userType = ''
@@ -268,8 +274,6 @@ tableStore.table.params.userType = ''
provide('tableStore', tableStore)
onMounted(() => {
tableStore.index()
})
const useChange = (e: string) => {
userShow.value = uesrList.filter(item => item.id == e)[0].code
@@ -278,10 +282,14 @@ const useChange = (e: string) => {
const add = async () => {
disabled.value = false
title.value = '新增承载能力待评估用户'
if (VITE_FLAG) {
areaList.value = dictData.state.areaTree
} else {
await getAreaDept().then(res => {
areaList.value = JSON.parse(JSON.stringify(res.data))
})
}
await getAreaDept().then(res => {
areaList.value = JSON.parse(JSON.stringify(res.data))
})
dialogVisible.value = true
}
// 保存

View File

@@ -8,7 +8,7 @@
</el-select>
</el-form-item>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable />
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable maxlength="32" show-word-limit/>
</el-form-item>
</template>
<template #operation>

View File

@@ -4,13 +4,13 @@
<TableHeader datePicker showExport :showReset="false">
<template v-slot:select>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable />
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable maxlength="32" show-word-limit/>
</el-form-item>
</template>
</TableHeader>
<div :key="key">
<Table ref="tableRef" :height="'49vh'"></Table>
<Table ref="tableRef" :height="'calc(50vh - 100px)'"></Table>
</div>
</el-dialog>
</template>
@@ -31,10 +31,12 @@ const dialogVisible = ref(false)
const tableStore = new TableStore({
url: '/system-boot/frontLog/queryLogCHild',
method: 'POST',
filename: '前置交互日志详情',
column: [
{
field: 'index',
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1

View File

@@ -3,7 +3,7 @@
<TableHeader datePicker showExport>
<template v-slot:select>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable />
<el-input v-model="tableStore.table.params.searchValue" placeholder="请输入筛选数据" clearable maxlength="32" show-word-limit/>
</el-form-item>
</template>
</TableHeader>
@@ -77,7 +77,7 @@ const tableStore = new TableStore({
}
},
{
title: '操作',
title: '操作',fixed: 'right',
width: '180',
render: 'buttons',
buttons: [

View File

@@ -40,7 +40,14 @@
></Table>
</div>
<div class="pd10" style="width: 400px" v-loading="loading">
<el-input v-model="filterText" placeholder="请输入内容" clearable show-word-limit @input="change">
<el-input
v-model="filterText"
placeholder="请输入内容"
clearable
maxlength="32"
show-word-limit
@input="change"
>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
@@ -83,7 +90,7 @@
v-else
class="box-item"
title="确定重启吗?"
placement="bottom"
placement="left"
@confirm="restart(data)"
>
<template #actions="{ confirm, cancel }">
@@ -141,7 +148,7 @@
</el-form-item>
<el-form-item label="最大终端数:" prop="nodeDevNum" class="top">
<el-input
v-model="formData.nodeDevNum"
v-model.trim.number="formData.nodeDevNum"
onkeyup="value = value.replace(/[^0-9]/g,'')"
maxlength="5"
placeholder="请输入最大终端数"
@@ -149,7 +156,7 @@
</el-form-item>
<el-form-item label="最大进程数:" prop="maxProcessNum" class="top">
<el-input
v-model="formData.maxProcessNum"
v-model.trim.number="formData.maxProcessNum"
onkeyup="value = value.replace(/[^0-9]/g,'')"
maxlength="5"
placeholder="请根据监测点规模填写合适进程数1个进程最大可承载200个监测点"
@@ -209,7 +216,8 @@ import {
updateNode,
nodeDeviceTree,
updateDeviceProcess,
askRestartProcess
askRestartProcess,
allotTerminal
} from '@/api/device-boot/Business'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
@@ -240,6 +248,7 @@ const tableRef = ref()
const processNo = ref('')
const ruleFormRef = ref()
const dataSource: any = ref([])
const deviceInfoList: any = ref([])
const defaultProps = {
children: 'deviceInfoList',
label: 'name'
@@ -271,7 +280,7 @@ const tableStore = new TableStore({
method: 'POST',
column: [
{ title: '名称', field: 'name' },
{ title: 'IP', field: 'ip' ,width:'120px' },
{ title: 'IP', field: 'ip', width: '120px' },
{
title: '等级',
field: 'nodeGrade',
@@ -288,7 +297,7 @@ const tableStore = new TableStore({
}
},
{
title: '最大监测点数量',
title: '最大终端数量',
field: 'nodeDevNum'
},
{
@@ -316,6 +325,7 @@ const tableStore = new TableStore({
{
title: '操作',
fixed: 'right',
align: 'center',
width: '180',
render: 'buttons',
@@ -350,7 +360,7 @@ const tableStore = new TableStore({
},
click: row => {
askRestartProcess({
deviceRebootType: null,
deviceRebootType: 1,
nodeId: row.id,
processNo: 1
}).then(res => {
@@ -373,11 +383,41 @@ const tableStore = new TableStore({
title: '确定删除吗?'
},
click: row => {
if (hasDevices.value) {
ElMessage.warning('此前置机绑定了设备,无法删除!')
return
}
delNode(row.id).then(res => {
ElMessage.success('删除成功')
tableStore.index()
})
}
},
{
name: 'edit',
title: '分配终端',
type: 'primary',
icon: 'InfoFilled',
render: 'confirmButton',
popconfirm: {
confirmButtonText: '确认',
cancelButtonText: '取消',
confirmButtonType: 'primary',
title: '确定分配终端吗?'
},
click: row => {
// if (!hasDevices.value) {
// ElMessage.warning('此前置机下无设备,无法分配终端!')
// return
// }
allotTerminal({
nodeId: row.id
}).then(res => {
ElMessage.success(res.message)
tableStore.index()
})
}
}
]
}
@@ -395,12 +435,14 @@ const tableStore = new TableStore({
}
})
const nodeId = ref('')
// 点击行
const hasDevices = ref(false)
/// 点击行
const currentChangeEvent = () => {
// 确保 tableRef 和当前记录存在
if (!tableRef.value || !tableRef.value.getRef().getCurrentRecord()) {
loading.value = false
dataSource.value = []
hasDevices.value = false
return
}
@@ -413,15 +455,26 @@ const currentChangeEvent = () => {
nodeId.value = tableRef.value.getRef().getCurrentRecord().id
// 检查返回的数据是否存在且不为空
if (res.data && res.data.processDeviceList) {
dataSource.value = res.data.processDeviceList.filter(item => (item.name = item.processNo + ''))
// 检查是否有设备绑定
const hasAnyDevices = res.data.processDeviceList.some(
item => item.deviceInfoList && item.deviceInfoList.length > 0
)
hasDevices.value = hasAnyDevices
dataSource.value = res.data.processDeviceList.filter(item => {
item.name = item.processNo + ''
return true // 保持原有的过滤逻辑
})
} else {
dataSource.value = []
hasDevices.value = false
}
loading.value = false
})
.catch(() => {
// 添加错误处理,确保 loading 状态也能关闭
dataSource.value = []
hasDevices.value = false
loading.value = false
})
@@ -430,11 +483,11 @@ const currentChangeEvent = () => {
// 重启进程
const restart = (data: any) => {
console.log('🚀 ~ restart ~ data:', data)
// console.log('🚀 ~ restart ~ data:', data)
askRestartProcess({
deviceRebootType: data.processNo,
deviceRebootType: null,
nodeId: nodeId.value,
processNo: 2
processNo: data.processNo
}).then(res => {
ElMessage.success('重启成功')
currentChangeEvent()
@@ -472,7 +525,7 @@ const filterNode = (value: string, data: any, node: any) => {
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
if ((data.subName + data.name).indexOf(value) !== -1) {
return true
}
const level = node.level
@@ -583,7 +636,7 @@ const addMenu = () => {}
:deep(.default) {
display: flex;
.row--current {
// background-color: var(--el-color-primary-light-8) !important;
// background-color: var(--el-color-primary-light-8) !important;
}
}
.custom-tree-node {

View File

@@ -3,7 +3,7 @@
<TableHeader>
<template #select>
<el-form-item label="终端型号">
<el-select v-model="tableStore.table.params.teriminal" clearable placeholder="请选择终端型号">
<el-select v-model="tableStore.table.params.devType" clearable placeholder="请选择终端型号">
<el-option
v-for="item in teriminaloption"
:key="item.id"
@@ -13,7 +13,7 @@
</el-select>
</el-form-item>
<el-form-item label="终端状态">
<el-select v-model="tableStore.table.params.teriminalstatus" clearable placeholder="请选择终端状态">
<el-select v-model="tableStore.table.params.runFlag" clearable placeholder="请选择终端状态">
<el-option
v-for="item in teriminalstatusoption"
:key="item.id"
@@ -23,7 +23,7 @@
</el-select>
</el-form-item>
<el-form-item label="通讯状态">
<el-select v-model="tableStore.table.params.state" clearable placeholder="请选择通讯状态">
<el-select v-model="tableStore.table.params.comFlag" clearable placeholder="请选择通讯状态">
<el-option
v-for="item in stateoption"
:key="item.id"
@@ -32,7 +32,7 @@
></el-option>
</el-select>
</el-form-item>
<el-form-item label="程序版本">
<!-- <el-form-item label="程序版本">
<el-select v-model="tableStore.table.params.program" clearable placeholder="请选择程序版本">
<el-option
v-for="item in programoption"
@@ -41,19 +41,21 @@
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="筛选数据">
</el-form-item> -->
<!-- <el-form-item label="筛选数据">
<el-input
v-model="tableStore.table.params.filterName"
@keyup="searchEvent"
maxlength="32"
show-word-limit
placeholder="输入关键字筛选"
/>
</el-form-item>
</el-form-item> -->
</template>
<template #operation>
<!-- <template #operation>
<el-button icon="el-icon-Download" @click="add">导出</el-button>
<el-button icon="el-icon-Check" @click="add">批量升级</el-button>
</template>
</template> -->
</TableHeader>
<div :style="`height: calc(${tableStore.table.height} + 58px)`">
<vxe-table
@@ -104,7 +106,7 @@
<vxe-column field="updateTime" title="最新升级时间"></vxe-column>
<vxe-column title="操作" min-width="100">
<template #default="{ row }">
<el-button v-if="row.level == 4" size="small" link @click="updateprogram(row)">升级</el-button>
<!-- <el-button v-if="row.level == 4" size="small" link @click="updateprogram(row)">升级</el-button> -->
<el-button
v-if="row.level == 4"
:disabled="row.state == 1 ? true : false"
@@ -250,8 +252,9 @@ const tableStore = new TableStore({
}, 0)
}
})
tableStore.table.params.teriminal = ''
tableStore.table.params.state = ''
tableStore.table.params.devType = ''
tableStore.table.params.runFlag = ''
tableStore.table.params.comFlag = ''
tableStore.table.params.program = ''
tableStore.table.params.searchEvent = ''
tableStore.table.params.filterName = ''

View File

@@ -35,7 +35,7 @@ const dialogVisible = ref(false)
const tableData = ref([])
const open = (e: any) => {
console.log("🚀 ~ open ~ e:", e)
//console.log("🚀 ~ open ~ e:", e)
echartsXq.value = {
title: {
text: e.name + '性能详情'

Some files were not shown because too many files have changed in this diff Show More