28 Commits

Author SHA1 Message Date
caozehui
5caffc9cc9 微调 2026-07-02 18:36:26 +08:00
caozehui
15bef7b17f 微调 2026-07-02 15:33:16 +08:00
caozehui
4ac32753f1 微调 2026-07-02 15:21:31 +08:00
caozehui
131adc81a7 三项不平衡补充序分量 2026-07-02 15:00:19 +08:00
caozehui
3135f76a2f 归档 2026-07-01 16:12:33 +08:00
caozehui
08d81f724f 微调 2026-07-01 13:59:28 +08:00
caozehui
29ef22c9b7 闪变调整 2026-06-26 13:57:17 +08:00
caozehui
7738d7d153 源控程序优化 2026-06-26 10:31:52 +08:00
caozehui
20bc6e3ab5 正式检测-过载测试显示结果 2026-06-26 08:46:23 +08:00
caozehui
2ea0557f4e 程控源调整 2026-06-25 10:52:19 +08:00
caozehui
1a35510801 修改配置文件 2026-06-23 11:42:45 +08:00
caozehui
5ad3029e0b pqdif 2026-06-23 10:21:56 +08:00
caozehui
cd51cfb052 程控源调整 2026-06-18 10:01:39 +08:00
caozehui
4415eb30b2 微调 2026-06-17 15:51:02 +08:00
caozehui
78d094e4a2 icd导入按钮及权限控制 2026-06-17 13:20:36 +08:00
caozehui
8f5642d0b5 icd调整 2026-06-16 19:26:47 +08:00
caozehui
6c191aa96f 多影响量 2026-06-16 13:24:21 +08:00
caozehui
f2d7156b4f 移除文件 2026-06-15 10:11:51 +08:00
caozehui
d44c79f7b8 报告模版新增pattern字段 2026-06-12 13:30:07 +08:00
caozehui
964ba77f8a Revert "docs: add report template pattern design"
This reverts commit 7c1f135e99.
2026-06-12 09:50:21 +08:00
caozehui
7c1f135e99 docs: add report template pattern design 2026-06-12 09:49:30 +08:00
caozehui
1982ccd7ff 闪变支持配置Pst 2026-06-12 09:22:50 +08:00
caozehui
5abaa743c0 修改常量 2026-06-11 10:35:11 +08:00
caozehui
52a8095334 移除文件 2026-06-11 09:57:01 +08:00
caozehui
654c997607 移除文件 2026-06-11 09:43:59 +08:00
caozehui
b31efb9ede 闪变编辑框微调 2026-06-11 09:28:26 +08:00
caozehui
195b58d798 比对检测计划默认值 2026-06-09 19:22:54 +08:00
caozehui
0423de2683 新增小工具页面、SNTP对时功能集成到小工具页面 2026-06-08 08:46:29 +08:00
133 changed files with 3268 additions and 3750 deletions

View File

@@ -97,6 +97,8 @@ qr:
db:
type: mysql
icd:
txt-dir: ..\..\..\9100\DeviceControl\Config
# 比对录波需要的配置,晚点再做优化
# 系统配置
@@ -118,3 +120,5 @@ activate:
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnFMmIVanMxsW5S/qP8Wcxf/J3/i4631BP3UtWkRzO7jAw9HIAgK4Y7X53hXj6zMbfme1vMjQc0mq7m/KrH4WlTYpFexLO6Gnk8oH40F04tp+ABZIq93zNOydPEaVoZeTPH/LlkwrrxVGAMNNIKuebcqapp25JiWtlSFMv4kH/nDAj+2m8+P4zYVM1Ed6gO01eKDEYE3SBA1Ket2BfHTgviR/F8WKwlXh11enywsJnrHTM5dJQdlUxCjHy214TpheYOz/cv9elQnDfFAbmZW8mH5/hgMSTkm3h4uR7ITin6Erg+yc/t1kGaTWrzloyBRMSiFN/Pwr5yQjj+1wQqqUkwIDAQAB"
dataCheck:
enable: false

View File

@@ -1 +1 @@
116212
55936

Binary file not shown.

View File

@@ -16,3 +16,4 @@
.\binlog.000038
.\binlog.000039
.\binlog.000040
.\binlog.000041

View File

@@ -12,3 +12,10 @@ VITE_REPORT=false
# 浏览器是否显示vue的告警信息
VUE_APP_SILENCE_WARNINGS=true
VITE_COMPANY_WEBSITE=http://www.shining-electric.com/
VITE_COMPANY_NAME=南京灿能电力自动化股份有限公司
VITE_IS_SHOW_RAW_DATA=true
# 开启激活验证
VITE_ACTIVATE_OPEN=true

View File

@@ -22,7 +22,3 @@ VITE_API_URL=/api
VITE_PROXY=[["/api","http://127.0.0.1:18092/"]]
#VITE_PROXY=[["/api","http://192.168.1.124:18092/"]]
#VITE_PROXY=[["/api","http://192.168.2.125:18092/"]]
# VITE_PROXY=[["/api","http://192.168.1.138:8080/"]]张文
VITE_IS_SHOW_RAW_DATA=true
# 开启激活验证
VITE_ACTIVATE_OPEN=false

View File

@@ -24,6 +24,4 @@ VITE_PWA=true
# 线上环境接口地址
#VITE_API_URL="/api" # 打包时用
VITE_API_URL="http://127.0.0.1:18092/"
VITE_IS_SHOW_RAW_DATA=true
# 开启激活验证
VITE_ACTIVATE_OPEN=false

View File

@@ -1,269 +0,0 @@
const data = [
{
id: 'device1',
deviceName:"模拟装置1",
deviceType:"PQS882B4电能质量监测装置",
deviceChannels:"4",
planName: "沧州220kV留古等4座变电站电能质量检测",
deviceUn: "57.74",
deviceIn: "5",
deviceCompany: "南京灿能电力自动化股份有限公司",
deviceModel: "模拟式",
},
{
id: 'device2',
deviceName:"模拟装置2",
deviceType:"PQS882A电能质量监测装置",
deviceChannels:"1",
planName: "邯郸220kV团城站等4座站电能质量检测",
deviceUn: "57.74",
deviceIn: "5",
deviceCompany: "南京灿能电力自动化股份有限公司",
deviceModel: "模拟式",
},
{
id: 'device3',
deviceName:"模拟装置3",
deviceType:"PQS882A电能质量监测装置",
deviceChannels:"1",
planName: "衡水冀州光伏电站配套出口工程",
deviceUn: "57.74",
deviceIn: "1",
deviceCompany: "南京灿能电力自动化股份有限公司",
deviceModel: "模拟式",
},
{
id: 'device4',
deviceName:"模拟装置4",
deviceType:"PMC-680M-22-22-00-115ANBC电能质量监测装置",
deviceChannels:"4",
planName: "深圳市中电软件有限公司委托送检",
deviceUn: "57.74",
deviceIn: "5",
deviceCompany: "深圳中电电力技术股份有限公司",
deviceModel: "模拟式",
},
]
const plan_devicedata = [
{
id: '1', //装置序号ID
name: '240001', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '2', //装置序号ID
name: '240002', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '3', //装置序号ID
name: '240003', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '4', //装置序号ID
name: '240004', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '5', //装置序号ID
name: '240005', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '不符合', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '6', //装置序号ID
name: '240006', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '不符合', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '7', //装置序号ID
name: '240007', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '符合', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '8', //装置序号ID
name: '240008', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '符合', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '9', //装置序号ID
name: '240009', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '不符合', //检测结果
report_State: '已生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '10', //装置序号ID
name: '240010', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '符合', //检测结果
report_State: '已生成', //报告状态
document_State: '未归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 2, //复检次数
},
{
id: '11', //装置序号ID
name: '240011', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '符合', //检测结果
report_State: '已生成', //报告状态
document_State: '已归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 1, //复检次数
},
{
id: '12', //装置序号ID
name: '240012', //设备名称
dev_Type: 'PQS-882B4',//设备类型
dev_Chns: 4, //设备通道数
check_Result: '符合', //检测结果
report_State: '已生成', //报告状态
document_State: '已归档', //归档状态
check_State:'检测完成',//检测状态
reCheck_Num: 2, //复检次数
},
{
id: '13', //装置序号ID
name: '240013', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '14', //装置序号ID
name: '240014', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '15', //装置序号ID
name: '240015', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '16', //装置序号ID
name: '240016', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '17', //装置序号ID
name: '240017', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '18', //装置序号ID
name: '240018', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '19', //装置序号ID
name: '240019', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
{
id: '20', //装置序号ID
name: '240020', //设备名称
dev_Type: 'PQS-882A',//设备类型
dev_Chns: 1, //设备通道数
check_Result: '未检', //检测结果
report_State: '未生成', //报告状态
document_State: '未归档', //归档状态
check_State:'未检',//检测状态
reCheck_Num: 0, //复检次数
},
]
export default {data,plan_devicedata}

View File

@@ -4,34 +4,38 @@ import http from '@/api'
/**
* @name ICD管理模块
*/
//获取ICD分页
export const getICDList = (params: ICD.ReqICDParams) => {
return http.post(`/icd/list`,params)
return http.post<ICD.ResICDPage>(`/icd/list`, params)
}
//获取ICD
export const getICDAllList = (params: ICD.ResICD) => {
return http.get(`/icd/listAll`,params)
export const getICDAllList = () => {
return http.get<ICD.ResICD[]>(`/icd/listAll`)
}
//添加ICD
export const addICD = (params: ICD.ResICD) => {
export const getStandardICDList = () => {
return http.get<ICD.StandardOption[]>(`/icd/standard-list`)
}
export const getICDById = (id: string) => {
return http.get<ICD.ResICD>(`/icd/getById`, { id })
}
export const addICD = (params: FormData) => {
return http.upload(`/icd/add`, params)
}
}
//编辑ICD
export const updateICD = (params: ICD.ResICD) => {
export const updateICD = (params: FormData) => {
return http.upload(`/icd/update`, params)
}
}
//删除ICD
export const deleteICD = (params: string[]) => {
export const importICDJson = (params: FormData) => {
return http.upload(`/icd/import/json`, params, { loading: false })
}
export const deleteICD = (params: string[]) => {
return http.post(`/icd/delete`, params)
}
}
export const exportICD = (id: string) => {
return http.downloadGetWithHeaders(`/icd/export/${id}`)
}

View File

@@ -19,6 +19,7 @@ export namespace DevType {
id: string; //设备类型ID
name: string;//设备类型名称
icd: string| null;//设备关联的ICD
pqdif: string| null;//设备关联的PQDIF
power: string| null;//工作电源
devVolt: number; //额定电压V
devCurr: number; //额定电流A

View File

@@ -1,38 +1,36 @@
import type { ReqPage, ResPage } from '@/api/interface'
// ICD模块
export namespace ICD {
export interface ReqICDParams extends ReqPage {
name?: string
type?: number
}
/**
* ICD表格分页查询参数
*/
export interface ReqICDParams extends ReqPage {
id: string; // 装置序号id 必填
devType?: string; // 设备名称
createTime?: string; //创建时间
}
export interface StandardOption {
id: string
name: string
type?: number
}
/**
* ICD新增、修改、根据id查询返回的对象
*/
export interface ResICD {
id: string; //icdID
name: string;//icd名称
path: string;//icd存储地址
state: number;
createBy?: string| null; //创建用户
createTime?: string| null; //创建时间
updateBy?: string| null; //更新用户
updateTime?: string| null; //更新时间
angle: number; // 是否支持电压相角、电流相角指标
usePhaseIndex: number; // 角型接线时是否使用相别的指标来进行检测
mappingFile: string | null;//映射文件
}
export interface ResICD {
id: string
name: string
state: number
createBy?: string | null
createTime?: string | null
updateBy?: string | null
updateTime?: string | null
angle: number
usePhaseIndex: number
jsonStr: string
xmlStr: string
result: number
msg: string | null
type: number
referenceIcdId: string | null
referenceIcdName?: string | null
hasIcdFile?: boolean | null
}
/**
* ICD表格查询分页返回的对象
*/
export interface ResICDPage extends ResPage<ResICD> {
}
export interface ResICDPage extends ResPage<ResICD> {}
}

View File

@@ -0,0 +1,26 @@
import type { ReqPage, ResPage } from '@/api/interface'
export namespace PQDIF {
export interface ReqPQDIFParams extends ReqPage {
name?: string
result?: number
}
export interface ResPQDIF {
id: string
name: string
filePath?: string | null
recordCount?: number | null
observationCount?: number | null
sampleValueCount?: number | null
result?: number | null
msg?: string | null
state: number
createBy?: string | null
createTime?: string | null
updateBy?: string | null
updateTime?: string | null
}
export interface ResPQDIFPage extends ResPage<ResPQDIF> {}
}

View File

@@ -1,39 +1,34 @@
import type { ReqPage, ResPage } from '@/api/interface'
import type { UploadFile } from 'element-plus';
// 报告模版接口
export namespace PqReport {
/**
* 报告模版表格分页查询参数
*/
export interface ReqReportParams extends ReqPage {
id: string; // 装置序号id 必填
name?: string; // 设备名称
createTime?: string; //创建时间
id: string
name?: string
createTime?: string
pattern: string
}
/**
* 报告模版新增、修改、根据id查询返回的对象
*/
export interface ResReport {
id: string; //报告模板id
name: string;//报告模板名称
version:string;//版本号
baseFile?:string;//基础模板文件路径
detailFile?:string;//检测项模版文件路径
description:string;//描述信息
state:number;//状态:8-删除 1-正常
createBy?: string| null; //创建用户
createTime?: string| null; //创建时间
updateBy?: string| null; //更新用户
updateTime?: string| null; //更新时间
id: string
name: string
version: string
pattern: string
baseFile?: string
detailFile?: string
description: string
state: number
createBy?: string | null
createTime?: string | null
updateBy?: string | null
updateTime?: string | null
}
/**
* 报告模版表格查询分页返回的对象;
*/
export interface ResReportPage extends ResPage<ResReport> {
export interface ResReportOption {
id: string
name: string
version: string
displayName: string
}
export interface ResReportPage extends ResPage<ResReport> {}
}

View File

@@ -0,0 +1,14 @@
import type { PQDIF } from '@/api/device/interface/pqdif'
import http from '@/api'
export const getPQDIFList = (params: PQDIF.ReqPQDIFParams) => {
return http.post<PQDIF.ResPQDIFPage>('/pqdif/list', params)
}
export const getPQDIFAllList = () => {
return http.get<PQDIF.ResPQDIF[]>('/pqdif/listAll')
}
export const importPQDIFJson = (params: FormData) => {
return http.upload('/pqdif/import/json', params, { loading: false })
}

View File

@@ -1,51 +1,49 @@
import type {PqReport} from '@/api/device/interface/report'
import type { PqReport } from '@/api/device/interface/report'
import http from '@/api'
/**
* @name 报告模版模块
*/
//获取报告模版
export const getPqReportList = (params: PqReport.ReqReportParams) => {
return http.post(`/report/list`, params)
return http.post(`/report/list`, params)
}
//新增报告模版
export const addPqReport = (params: PqReport.ResReport) => {
return http.upload(`/report/add`, params)
return http.upload(`/report/add`, params)
}
//删除报告模版
export const deletePqReport = (params: string[]) => {
return http.post(`/report/delete`, params)
return http.post(`/report/delete`, params)
}
//查询报告模板详情
export const getPqReportById = (params: PqReport.ResReport) => {
return http.get(`/report/getById?id=${params.id}`)
return http.get(`/report/getById?id=${params.id}`)
}
//修改报告模板
export const updatePqReport = (params: PqReport.ResReport) => {
return http.upload(`/report/update`, params)
return http.upload(`/report/update`, params)
}
//查询所有报告模板名称
export const getPqReportAllName = () => {
return http.get(`/report/listAllName`)
export const getPqReportOptions = (params: { pattern: string }) => {
return http.get(`/report/listOptions?pattern=${params.pattern}`)
}
//根据名称查询指定报告模板的所有版本
export const getPqReportAllVersion = (params:any) => {
return http.get(`/report/listAllVersion?name=${params.name}`)
export const getPqReportAllVersion = (params: any) => {
return http.get(`/report/listAllVersion?name=${params.name}`)
}
//被检设备归档
export const documentedPqDev = (ids: string[]) => {
return http.post(`/report/documented`, ids)
return http.post(`/report/documented`, ids)
}
//上传报告到云端
export const uploadReportToCloud = (deviceIds: string[]) => {
return http.post(`/report/uploadReportToCloud`, deviceIds)
return http.post(`/report/uploadReportToCloud`, deviceIds)
}

View File

@@ -214,6 +214,10 @@ class RequestHttp {
return this.service.post(url, params, { ..._object, responseType: 'blob' })
}
downloadGetWithHeaders(url: string, _object = {}): Promise<AxiosResponse<Blob>> {
return this.service.get(url, { ..._object, responseType: 'blob' })
}
upload(url: string, params?: object, _object = {}): Promise<BlobPart> {
return this.service.post(url, params, {
..._object,

View File

@@ -1,5 +1,15 @@
import http from '@/api'
export interface SntpTimeMessage {
type: string
deviceIp?: string
computerTime?: string
deviceTime?: string
computerTimestampMs?: number
deviceTimestampMs?: number
errorMs?: number
}
export const startSntpService = () => {
return http.post('/sntp/start', {})
}

View File

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -0,0 +1,171 @@
<template>
<el-dialog
v-model="dialogVisible"
:title="title"
width="460px"
destroy-on-close
:close-on-click-modal="!loading"
:show-close="!loading"
>
<div v-loading="loading" :element-loading-text="loadingText" class="json-import-content">
<el-upload
ref="uploadRef"
action="#"
class="upload"
:auto-upload="false"
:limit="1"
accept=".json,application/json"
:on-exceed="handleExceed"
:on-change="handleChange"
:on-remove="handleRemove"
:disabled="loading"
>
<el-button type="primary" :icon="Upload" :disabled="loading">选择文件</el-button>
<template #tip>
<div class="el-upload__tip">{{ tip }}</div>
</template>
</el-upload>
<div v-if="loading" class="json-import-loading-text">{{ loadingText }}</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button :disabled="loading" @click="close">取消</el-button>
<el-button type="primary" :loading="loading" @click="submit">开始导入</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { Upload } from '@element-plus/icons-vue'
import {
ElMessage,
ElNotification,
genFileId,
type UploadFile,
type UploadInstance,
type UploadProps,
type UploadRawFile
} from 'element-plus'
const props = withDefaults(
defineProps<{
title: string
requestApi: (params: FormData) => Promise<unknown>
tip?: string
loadingText?: string
successMessage?: string
}>(),
{
tip: '请上传 .json 文件',
loadingText: '导入中,请稍候...',
successMessage: '导入成功'
}
)
const emit = defineEmits<{
(e: 'success'): void
}>()
const dialogVisible = ref(false)
const loading = ref(false)
const uploadRef = ref<UploadInstance | null>(null)
const selectedFile = ref<File | null>(null)
const open = () => {
dialogVisible.value = true
}
const close = () => {
if (loading.value) {
return
}
dialogVisible.value = false
selectedFile.value = null
uploadRef.value?.clearFiles()
}
const isJsonFile = (file: UploadRawFile | File) => {
return file.name.toLowerCase().endsWith('.json') || file.type === 'application/json'
}
const notifyInvalidFile = () => {
ElNotification({
title: '温馨提示',
message: '上传文件只能是 json 格式!',
type: 'warning'
})
}
const setSelectedFile = (file: UploadRawFile | File | undefined) => {
if (!file) {
selectedFile.value = null
return
}
if (!isJsonFile(file)) {
notifyInvalidFile()
selectedFile.value = null
uploadRef.value?.clearFiles()
return
}
selectedFile.value = file
}
const handleExceed: UploadProps['onExceed'] = files => {
uploadRef.value?.clearFiles()
const file = files[0] as UploadRawFile
file.uid = genFileId()
uploadRef.value?.handleStart(file)
setSelectedFile(file)
}
const handleChange = (uploadFile: UploadFile) => {
setSelectedFile(uploadFile.raw as File | undefined)
}
const handleRemove = () => {
selectedFile.value = null
}
const submit = async () => {
if (loading.value) {
return
}
if (!selectedFile.value) {
ElMessage.warning('请选择文件!')
return
}
const formData = new FormData()
formData.append('file', selectedFile.value)
loading.value = true
try {
await props.requestApi(formData)
ElMessage.success(props.successMessage)
dialogVisible.value = false
selectedFile.value = null
uploadRef.value?.clearFiles()
emit('success')
} finally {
loading.value = false
}
}
defineExpose({
open,
close
})
</script>
<style scoped>
.json-import-content {
min-height: 120px;
}
.json-import-loading-text {
margin-top: 12px;
color: var(--el-text-color-secondary);
font-size: 13px;
}
</style>

View File

@@ -4,7 +4,7 @@
<el-header>
<div class="logo flx-center">
<!-- <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> -->
<img class="logo-img" src="@/assets/images/cn_pms9100_logo.png" alt="logo" />
<img class="logo-img" src="@/assets/images/logo.png" alt="logo" />
<span class="logo-text">{{ title }}</span>
</div>
<el-menu v-if="showMenuFlag" trigger="click" mode="horizontal" :router="false" :default-active="activeMenu">

View File

@@ -20,10 +20,11 @@
</template>
</el-dropdown>
<p style="margin: 0">
<a href="http://www.shining-electric.com/" target="_blank">2024 © 南京灿能电力自动化股份有限公司</a>
<a :href="companyWebsite" target="_blank" rel="noopener noreferrer">{{new Date().getFullYear()}} ©{{companyName}}</a>
</p>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { useAuthStore } from '@/stores/modules/auth'
@@ -42,6 +43,10 @@ const title = computed(() => {
})
const activateInfo = authStore.activateInfo
const isActivateOpen = import.meta.env.VITE_ACTIVATE_OPEN
const companyWebsite = import.meta.env.VITE_COMPANY_WEBSITE
const companyName = import.meta.env.VITE_COMPANY_NAME
console.log(companyWebsite,companyName)
const modeList = [
{
name: '模拟式模块',
@@ -62,13 +67,14 @@ const modeList = [
activated: isActivateOpen === 'true' ? activateInfo.contrast.permanently === 1 : true
}
]
const handelOpen = async (item: string, key: string) => {
if (isActivateOpen === 'true' && activateInfo[key].permanently !== 1) {
ElMessage.warning(`${item}模块未激活`)
return
}
await authStore.setShowMenu()
modeStore.setCurrentMode(item) // 将模式code存入 store
modeStore.setCurrentMode(item) // 将模式 code 存入 store
// 强制刷新页面
await tabsStore.closeMultipleTab()
await initDynamicRouter()
@@ -80,11 +86,12 @@ const handelOpen = async (item: string, key: string) => {
// 如果已在目标页面,手动触发组件更新
window.location.reload() // 或者采用其他方式刷新数据
}
}
</script>
<style scoped lang="scss">
@use './index.scss';
.footer {
position: relative;
background-color: var(--el-color-primary);
@@ -101,30 +108,37 @@ const handelOpen = async (item: string, key: string) => {
height: 100%;
width: auto;
font-size: 14px;
.change_mode_down {
display: block;
}
.change_mode_up {
display: none;
}
}
.change_mode:hover {
.change_mode_down {
display: none;
}
.change_mode_up {
display: block;
}
}
.el-dropdown {
z-index: 1001;
}
p {
position: absolute;
width: 100%;
height: 100%;
text-align: right;
line-height: 40px;
a {
color: #fff;
margin-right: 25px; // 增加右边距

View File

@@ -56,7 +56,8 @@
</template>
</el-dropdown>
<div class="avatar">
<img src="@/assets/icons/out_login.svg" alt="avatar" @click="logout" />
<el-button type="text" style="font-size: 18px;color:#fff;" icon="SwitchButton" @click="logout"/>
<!-- <img src="@/assets/icons/out_login.svg" alt="avatar" @click="logout" />-->
</div>
<!-- infoDialog -->
<InfoDialog ref="infoRef"></InfoDialog>

View File

@@ -45,6 +45,7 @@ import { useTabsStore } from '@/stores/modules/tabs'
import { useGlobalStore } from '@/stores/modules/global'
import { useKeepAliveStore } from '@/stores/modules/keepAlive'
import { useRoute, useRouter } from 'vue-router'
import mittBus, { TAB_CLOSED_EVENT } from '@/utils/mittBus'
const route = useRoute()
const router = useRouter()
@@ -73,6 +74,7 @@ const maximize = () => {
// Close Current
const closeCurrentTab = () => {
if (route.meta.isAffix) return
mittBus.emit(TAB_CLOSED_EVENT, route.fullPath)
tabStore.removeTabs(route.fullPath)
}

View File

@@ -31,6 +31,7 @@ import { useTabsStore } from '@/stores/modules/tabs'
import { useAuthStore } from '@/stores/modules/auth'
import { TabPaneName, TabsPaneContext } from 'element-plus'
import MoreButton from './components/MoreButton.vue'
import mittBus, { TAB_CLOSED_EVENT } from '@/utils/mittBus'
const route = useRoute()
const router = useRouter()
@@ -110,6 +111,7 @@ const tabClick = (tabItem: TabsPaneContext) => {
// Remove Tab
const tabRemove = (fullPath: TabPaneName) => {
mittBus.emit(TAB_CLOSED_EVENT, fullPath as string)
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath || '/machine/testScriptAdd' == route.fullPath)
}
</script>

View File

@@ -7,75 +7,60 @@ import { useModeStore } from '@/stores/modules/mode'
import { getLicense } from '@/api/activate'
import type { Activate } from '@/api/activate/interface'
const CONTRAST_MODE_NAME = '比对式'
export const useAuthStore = defineStore(AUTH_STORE_KEY, {
state: (): AuthState => ({
// 按钮权限列表
authButtonList: {},
// 菜单权限列表
authMenuList: [],
// 当前页面的 router name用来做按钮权限筛选
routeName: '',
//登录不显示菜单栏和导航栏,点击进入测试的时候显示
showMenuFlag: JSON.parse(localStorage.getItem('showMenuFlag') as string),
activateInfo: {} as Activate.ActivationCodePlaintext
}),
getters: {
// 按钮权限列表
authButtonListGet: state => state.authButtonList,
// 菜单权限列表 ==> 这里的菜单没有经过任何处理
authMenuListGet: state => state.authMenuList,
// 菜单权限列表 ==> 左侧菜单栏渲染,需要剔除 isHide == true
showMenuListGet: state => getShowMenuList(state.authMenuList),
// 菜单权限列表 ==> 扁平化之后的一维数组菜单,主要用来添加动态路由
flatMenuListGet: state => getFlatMenuList(state.authMenuList),
// 递归处理后的所有面包屑导航列表
breadcrumbListGet: state => getAllBreadcrumbList(state.authMenuList),
//是否显示菜单和导航栏
showMenuFlagGet: state => state.showMenuFlag,
// 获取激活信息
activateInfoGet: state => state.activateInfo
},
actions: {
// Get AuthButtonList
async getAuthButtonList() {
const { data } = await getAuthButtonListApi()
this.authButtonList = data
},
// Get AuthMenuList
async getAuthMenuList() {
const modeStore = useModeStore()
const { data: menuData } = await getAuthMenuListApi()
// 根据不同模式过滤菜单
const filteredMenu =
modeStore.currentMode === '比对式'
? filterMenuByExcludedNames(menuData, ['testSource', 'testScript', 'controlSource'])
: filterMenuByExcludedNames(menuData, ['standardDevice'])
this.authMenuList = filteredMenu
const isContrastMode = modeStore.currentMode === CONTRAST_MODE_NAME
const filteredMenu = isContrastMode
? filterMenuByExcludedNames(menuData, ['testSource', 'testScript', 'controlSource'])
: filterMenuByExcludedNames(menuData, ['standardDevice'])
this.authMenuList = filterMenuByExcludedNames(filteredMenu, ['sntp'])
},
// Set RouteName
async setRouteName(name: string) {
this.routeName = name
},
//重置权限
async resetAuthStore() {
this.showMenuFlag = false
localStorage.removeItem('showMenuFlag')
},
//修改判断菜单栏/导航栏显示条件
async setShowMenu() {
this.showMenuFlag = true
localStorage.setItem('showMenuFlag', 'true')
},
//更改模式
changeModel() {
this.showMenuFlag = false
localStorage.removeItem('showMenuFlag')
},
async setActivateInfo() {
const license_result = await getLicense()
const licenseData = license_result.data as Activate.ActivationCodePlaintext
const licenseResult = await getLicense()
const licenseData = licenseResult.data as Activate.ActivationCodePlaintext
if (!licenseData.simulate) {
licenseData.simulate = {
permanently: 0
@@ -91,24 +76,18 @@ export const useAuthStore = defineStore(AUTH_STORE_KEY, {
permanently: 0
}
}
this.activateInfo = licenseData
}
}
})
/**
* 通用菜单过滤函数
* @param menuList 菜单列表
* @param excludedNames 需要排除的菜单名称数组
* @returns 过滤后的菜单列表
*/
function filterMenuByExcludedNames(menuList: any[], excludedNames: string[]): any[] {
function filterMenuByExcludedNames(menuList: Menu.MenuOptions[], excludedNames: string[]): Menu.MenuOptions[] {
return menuList.filter(menu => {
// 如果当前项有 children递归处理子项
if (menu.children && menu.children.length > 0) {
menu.children = filterMenuByExcludedNames(menu.children, excludedNames)
}
// 过滤掉在排除列表中的菜单项
return !excludedNames.includes(menu.name)
})
}

View File

@@ -27,7 +27,11 @@ declare interface ViteEnv {
VITE_PWA: boolean;
VITE_PUBLIC_PATH: string;
VITE_API_URL: string;
VITE_COMPANY_WEBSITE: string;
VITE_COMPANY_NAME:string;
VITE_PROXY: [string, string][];
VITE_IS_SHOW_RAW_DATA:boolean;
VITE_ACTIVATE_OPEN:boolean;
}
interface ImportMetaEnv extends ViteEnv {

View File

@@ -1,10 +1,12 @@
import mitt from "mitt";
export const STOP_DETECTION_TIMER_EVENT = "stopDetectionTimer";
export const TAB_CLOSED_EVENT = "tabClosed";
type MittBusEvents = {
openThemeDrawer: undefined;
[STOP_DETECTION_TIMER_EVENT]: undefined;
[TAB_CLOSED_EVENT]: string;
};
const mittBus = mitt<MittBusEvents>();

View File

@@ -192,8 +192,7 @@ export default class SocketService {
* WebSocket连接配置
*/
private config: SocketConfig = {
// url: 'ws://127.0.0.1:7778/hello',
url: 'ws://127.0.0.1:7778/hello',
url: `ws://127.0.0.1:7778/hello`,
heartbeatInterval: 9000, // 9秒心跳间隔
reconnectDelay: 5000, // 5秒重连延迟
maxReconnectAttempts: 5, // 最多重连5次

View File

@@ -6,9 +6,9 @@
style="width: 100%;">
<el-table-column type="index" label="序号" width="70" fixed="left"/>
<el-table-column prop="time" label="数据时间"/>
<el-table-column v-if="!isThreePhase && phaseA==1" prop="dataA" :label="'A相'+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseB==1" prop="dataB" :label="'B相'+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseC==1" prop="dataC" :label="'C相'+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseA==1" prop="dataA" :label="labelA+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseB==1" prop="dataB" :label="labelB+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseC==1" prop="dataC" :label="labelC+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="!isThreePhase && phaseT === 1" prop="dataT" :label="tableHeader+(unit==''?'':''+unit+'')"/>
<el-table-column v-if="isThreePhase" prop="dataB" :label="'负序不平衡度'+(unit==''?'':''+unit+'')"/>
</el-table>
@@ -20,13 +20,30 @@
import {CheckData} from "@/api/check/interface";
import {computed} from "vue";
const {tableData, currentScriptTypeName} = defineProps<{
const {tableData, currentCheckItem} = defineProps<{
tableData: CheckData.RawDataItem[]
currentScriptTypeName: string
currentCheckItem: string
}>()
const emit = defineEmits(['exportRawDataHandler'])
const labelA = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '正序分量'
}
return 'A相'
})
const labelB = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '负序分量'
}
return 'B相'
})
const labelC = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '零序分量'
}
return 'C相'
})
const unit = computed(() => {
return tableData.length > 0 ? tableData[0].unit : '';
})
@@ -46,15 +63,16 @@ const phaseT = computed(() => {
})
const tableHeader = computed(() => {
if (phaseT.value === 1) {
let index = currentScriptTypeName.indexOf('=');
return currentScriptTypeName.substring(0, index);
if(currentCheckItem.includes('三相电压负序不平衡度')){
return '三相电压不平衡度'
}
return currentScriptTypeName
if(currentCheckItem.includes('三相电流负序不平衡度')){
return '三相电流不平衡度'
}
return currentCheckItem
})
const isThreePhase = computed(() => {
return currentScriptTypeName.includes('三相电压不平衡度') || currentScriptTypeName.includes('三相电流不平衡度')
return currentCheckItem.includes('三相电压负序不平衡度') || currentCheckItem.includes('三相电流负序不平衡度')
})
const exportData = () => {

View File

@@ -12,10 +12,10 @@
<!-- {{ '通道' + row.chnNum }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="A" v-if="phaseA === 1">
<el-table-column :label="labelA" v-if="phaseA === 1">
<el-table-column prop="stdA" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataA" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataA" label="检测结果">
<el-table-column prop="isDataA" label="检测结果" width="90px">
<template #default="scope">
<template v-if="scope.row.isDataA === 4 || scope.row.isDataA === 5">
<el-tag type="warning" v-if="scope.row.isDataA === 4">/</el-tag>
@@ -33,10 +33,10 @@
</template>
</el-table-column>
</el-table-column>
<el-table-column label="B" v-if="phaseB === 1">
<el-table-column :label="labelB" v-if="phaseB === 1">
<el-table-column prop="stdB" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataB" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataB" label="检测结果">
<el-table-column prop="isDataB" label="检测结果" width="90px">
<template #default="scope">
<template v-if="scope.row.isDataB === 4 || scope.row.isDataB === 5">
<el-tag type="warning" v-if="scope.row.isDataB === 4">/</el-tag>
@@ -55,10 +55,10 @@
</template>
</el-table-column>
</el-table-column>
<el-table-column label="C" v-if="phaseC === 1">
<el-table-column :label="labelC" v-if="phaseC === 1">
<el-table-column prop="stdC" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataC" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataC" label="检测结果">
<el-table-column prop="isDataC" label="检测结果" width="90px">
<template #default="scope">
<template v-if="scope.row.isDataC === 4 || scope.row.isDataC === 5">
<el-tag type="warning" v-if="scope.row.isDataC === 4">/</el-tag>
@@ -107,9 +107,9 @@
import { computed } from 'vue'
import { CheckData } from '@/api/check/interface'
const { tableData, currentScriptTypeName } = defineProps<{
const { tableData, currentCheckItem } = defineProps<{
tableData: CheckData.CheckResult[]
currentScriptTypeName: string
currentCheckItem: string
}>()
const outerUnit = computed(() => {
@@ -129,6 +129,25 @@ const innerUnitT = computed(() => {
return tableData.length > 0 ? tableData[0].unitT : ''
})
const labelA = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '正序分量'
}
return 'A相'
})
const labelB = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '负序分量'
}
return 'B相'
})
const labelC = computed(() => {
if(currentCheckItem.includes('电压序分量')){
return '零序分量'
}
return 'C相'
})
const phaseA = computed(() => {
return tableData.length <= 0 || tableData[0].dataA == null || tableData[0].dataA == '/' ? 0 : 1
})
@@ -144,11 +163,13 @@ const phaseT = computed(() => {
})
const tableHeader = computed(() => {
if (phaseT.value === 1) {
let index = currentScriptTypeName.indexOf('=')
return currentScriptTypeName.substring(0, index)
}
return currentScriptTypeName
if(currentCheckItem.includes('三相电压负序不平衡度')){
return '三相电压不平衡度'
}
if(currentCheckItem.includes('三相电流负序不平衡度')){
return '三相电流不平衡度'
}
return currentCheckItem
})
// const maxErrorStr = computed((data) => {

View File

@@ -136,13 +136,13 @@
<el-tab-pane label="检测结果" name="resultTab">
<DataCheckResultTable
:tableData="checkResultData"
:currentScriptTypeName="currentScriptTypeName"
:currentCheckItem="currentCheckItem"
/>
</el-tab-pane>
<el-tab-pane label="原始数据" name="rawDataTab">
<DataCheckRawDataTable
:tableData="rawTableData"
:currentScriptTypeName="currentScriptTypeName"
:currentCheckItem="currentCheckItem"
@exportRawDataHandler="exportRawDataHandler"
/>
</el-tab-pane>

View File

@@ -47,7 +47,7 @@
:row.devices[index1].chnResult[index2].icon==='CircleCheckFilled'?'符合'
:row.devices[index1].chnResult[index2].icon==='Close'?'不符合'
:row.devices[index1].chnResult[index2].icon==='WarnTriangleFilled'?'数据异常'
:row.devices[index1].chnResult[index2].icon==='Loading'?'检测中':'连接中断'"
:row.devices[index1].chnResult[index2].icon==='Loading'?'检测中':'不参与误差比较'"
placement='right'>
<!-- 通道状态按钮 -->
<el-button
@@ -415,6 +415,39 @@ watch(webMsgSend, function(newValue, oldValue) {
} else {
// ========== 根据请求ID处理不同类型的消息 ==========
switch (newValue.requestId) {
// 源过载测试
case 'overloadTest':
if (newValue.code === 1) {
ElMessageBox.alert('电压过载!', '初始化失败', {
confirmButtonText: '确定',
type: 'error',
})
testLogList.push({ type: 'error', log: `${new Date().toLocaleString()}:电压过载!` })
emit('update:testStatus', 'test_init_fail')
count++
}
if (newValue.code === 2) {
ElMessageBox.alert('电流过载!', '初始化失败', {
confirmButtonText: '确定',
type: 'error',
})
testLogList.push({ type: 'error', log: `${new Date().toLocaleString()}:电流过载!` })
emit('update:testStatus', 'test_init_fail')
count++
}
if (newValue.code === 3) {
ElMessageBox.alert('电压和电流过载!', '初始化失败', {
confirmButtonText: '确定',
type: 'error',
})
testLogList.push({ type: 'error', log: `${new Date().toLocaleString()}:电压和电流过载!` })
emit('update:testStatus', 'test_init_fail')
count++
}
if (newValue.code === 4) {
testLogList.push({ type: 'info', log: `${new Date().toLocaleString()}:过载测试成功!` })
}
break;
// 服务端错误
case 'server_error':
if (newValue.operateCode === 'server_error' && count === 0) {

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