24 Commits

Author SHA1 Message Date
guanj
21ac0611cd 修改地图api 2026-06-29 14:41:12 +08:00
guanj
ff841cfa93 修改Socket路径问题 2026-06-26 10:17:43 +08:00
guanj
01cc29c8b2 修改电网一张图 2026-06-24 09:57:48 +08:00
guanj
a324f7afcf 修改算法库拖动问题 2026-06-23 21:36:43 +08:00
guanj
4272f7756e 修改配置 2026-06-23 21:28:35 +08:00
guanj
070e404bbb 修改辽宁反馈问题 2026-06-23 21:27:15 +08:00
ed60e2b7f3 台账新增修改添加objName 2026-06-23 16:09:41 +08:00
7785d4f708 台账新增修改添加objName 2026-06-23 15:12:58 +08:00
0c64711dd8 辽宁页面调整 2026-06-22 15:50:31 +08:00
guanj
d85dba8bf8 修改补召 2026-06-16 09:56:38 +08:00
guanj
56b8158f4a 优化波形 2026-06-16 08:36:22 +08:00
cdf
765507398e 辽宁单点登录 2026-06-15 17:57:14 +08:00
cdf
9224ea17b8 区域报告调整 2026-06-07 15:56:31 +08:00
cdf
dc08f7d1ac 辽宁统一认证登录 2026-06-03 17:41:37 +08:00
cdf
1652b5faf8 辽宁统一认证登录 2026-06-03 15:54:15 +08:00
guanj
fae2a7d735 修改辽宁嵌入 2026-06-02 16:33:08 +08:00
guanj
bf3a99cbf3 提交代码 2026-06-02 16:30:29 +08:00
guanj
2e7c0b7f44 修改辽宁免登录 2026-06-02 09:30:10 +08:00
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
104 changed files with 11128 additions and 9647 deletions

6
.env.LN Normal file
View File

@@ -0,0 +1,6 @@
# 辽宁嵌入
NODE_ENV = LN
VITE_NAME="LN"
# 电网一张图 地图图层
VITE_NARIMAP=null
VITE_NRGISCOMMON=null

6
.env.LNqr Normal file
View File

@@ -0,0 +1,6 @@
# 辽宁嵌入
NODE_ENV = LNqr
VITE_NAME="LNqr"
# 电网一张图 地图图层
VITE_NARIMAP=null
VITE_NRGISCOMMON=null

View File

@@ -18,7 +18,7 @@ pnpm i
#运行项目 #运行项目
npm run dev npm run dev
#冀北现场启动命令 区分是否加载现场电网一张图内网api #jb现场启动命令 区分是否加载现场电网一张图内网api
npm run dev:jibei npm run dev:jibei
#去除后台所有模块名 如除/xxxx-boot #去除后台所有模块名 如除/xxxx-boot
@@ -26,9 +26,9 @@ npm run dev:removeMode
#因海南和冀北技术监督不同 通过修改文件的方式来区分 #因海南和jb技术监督不同 通过修改文件的方式来区分
#海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb #海南打包 需要吧pqs目录下supervise_hn 文件夹改成supervise 原文件改成supervise_jb
#冀北打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn #jb打包 需要吧pqs目录下supervise_jb 文件夹改成supervise 原文件改成supervise_hn
``` ```
#### 页面编写-示例 #### 页面编写-示例

View File

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

View File

@@ -8,11 +8,15 @@
"dev:jibei": "vite --mode jibei", "dev:jibei": "vite --mode jibei",
"dev:hainan": "vite --mode hainan", "dev:hainan": "vite --mode hainan",
"dev:qujing": "vite --mode qujing", "dev:qujing": "vite --mode qujing",
"dev:LN": "vite --mode LN",
"dev:LNqr": "vite --mode LNqr",
"dev:removeMode": "vite --mode removeMode", "dev:removeMode": "vite --mode removeMode",
"build": "vite build --mode dev", "build": "vite build --mode dev",
"build:jibei": "vite build --mode jibei", "build:jibei": "vite build --mode jibei",
"build:hainan": "vite build --mode hainan", "build:hainan": "vite build --mode hainan",
"build:qujing": "vite build --mode qujing", "build:qujing": "vite build --mode qujing",
"build:LN": "vite build --mode LN",
"build:LNqr": "vite build --mode LNqr",
"build:removeMode": "vite build --mode removeMode", "build:removeMode": "vite build --mode removeMode",
"preview": "vite preview" "preview": "vite preview"
}, },

View File

@@ -4747,10 +4747,11 @@ window.BMAP_AUTHENTIC_KEY = ''
c.Nm c.Nm
? c.Nm.sa(b) ? c.Nm.sa(b)
: ((c.Nm = new U(b, { : ((c.Nm = new U(b, {
icon: new qc(G.qa + 'blank.gif', { // icon: new qc(G.qa + 'blank.gif', {
width: 1, // width: 1,
height: 1 // height: 1
}), // }),
icon: '',
offset: new O(0, 0), offset: new O(0, 0),
clickable: t clickable: t
})), })),
@@ -5886,7 +5887,7 @@ window.BMAP_AUTHENTIC_KEY = ''
Qc.prototype.co = function () { Qc.prototype.co = function () {
this.Gb.src = this.Gb.src =
0 < z.ca.ia && 6 >= z.ca.ia && this.GJ 0 < z.ca.ia && 6 >= z.ca.ia && this.GJ
? G.qa + 'blank.gif' ? '' //G.qa + 'blank.gif'
: '' !== this.src && this.Gb.src == this.src : '' !== this.src && this.Gb.src == this.src
? this.src + '&t = ' + Date.now() ? this.src + '&t = ' + Date.now()
: this.src : this.src

View File

@@ -9,14 +9,20 @@ import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import useSetTheme from '@/utils/setTheme' import useSetTheme from '@/utils/setTheme'
import { onMounted } from 'vue' import { onMounted } from 'vue'
useSetTheme() useSetTheme()
onMounted(async () => { const fetchMqttUrl = async () => {
const response = await fetch('/') const response = await fetch('/')
const WebSocketUrl:any = response.headers.get('X-WebSocket-Url') const WebSocketUrl: any = response.headers.get('X-WebSocket-Url')
const WebSocketUrl2:any = response.headers.get('X-WebSocket-Url2') const WebSocketUrl2: any = response.headers.get('X-WebSocket-Url2')
const MqttUrl:any = response.headers.get('X-MqttUrl-Url') const WebSocketUrl3: any = response.headers.get('X-WebSocket-Url3')
localStorage.setItem('WebSocketUrl2', WebSocketUrl2) const MqttUrl: any = response.headers.get('X-MqttUrl-Url')
localStorage.setItem('WebSocketUrl', WebSocketUrl) localStorage.setItem('WebSocketUrl', WebSocketUrl)
localStorage.setItem('WebSocketUrl2', WebSocketUrl2)
localStorage.setItem('WebSocketUrl3', WebSocketUrl3)
localStorage.setItem('MqttUrl', MqttUrl) localStorage.setItem('MqttUrl', MqttUrl)
}
onMounted(() => {
fetchMqttUrl()
}) })
</script> </script>

View File

@@ -4,6 +4,10 @@ import request from '@/utils/request'
export function getSubLineGiveAnAlarm(data: any) { export function getSubLineGiveAnAlarm(data: any) {
return request({ url: '/harmonic-boot/gridDiagram/getSubLineGiveAnAlarm', method: 'post', data }) return request({ url: '/harmonic-boot/gridDiagram/getSubLineGiveAnAlarm', method: 'post', data })
} }
export function getAreaObjAlarm(data: any) {
return request({ url: '/harmonic-boot/gridDiagram/getAreaObjAlarm', method: 'post', data })
}
// 变电站详细列表 // 变电站详细列表
export function getPollutionAlarmPageData(data: any) { export function getPollutionAlarmPageData(data: any) {
return request({ url: '/harmonic-boot/gridDiagram/getPollutionAlarmPageData', method: 'post', data }) return request({ url: '/harmonic-boot/gridDiagram/getPollutionAlarmPageData', method: 'post', data })

View File

@@ -43,6 +43,30 @@ export async function login(params: any) {
params params
}) })
} }
//辽宁嵌入登录获取token
export async function loginLNqr(data: any) {
return request({
url: '/pqs-auth/oauth/lnLogin',
method: 'get',
params: data
})
}
export async function lnRefreshToken(data: any) {
return request({
url: '/pqs-auth/oauth/lnRefreshToken',
method: 'get',
params: data
})
}
export async function logout() {
return request({
url: '/pqs-auth/oauth/logout',
method: 'DELETE',
})
}
//获取用户信息 //获取用户信息
export function getUserById() { export function getUserById() {
@@ -70,6 +94,17 @@ export function refreshToken(): Promise<any> {
}) })
} }
export function lnRefreshTokenTo(): Promise<any> {
// 调用useAdminInfo函数获取管理员信息并将其赋值给adminInfo变量
const adminInfo = useAdminInfo()
return lnRefreshToken({
refreshToken: adminInfo.refresh_token,
clientId: "njcn",
clientSecret:"njcnpqs"
})
}
/** /**
* 获取营销用户列表 * 获取营销用户列表
* @returns {AxiosPromise} * @returns {AxiosPromise}

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

View File

@@ -30,7 +30,7 @@ import { downloadFile } from '@/api/system-boot/file'
import { previewFile } from '@/utils/fileDownLoad' import { previewFile } from '@/utils/fileDownLoad'
const { push, options, currentRoute } = useRouter() const { push, options, currentRoute } = useRouter()
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei' const VITE_FLAG = false//import.meta.env.VITE_NAME == 'jibei'
// const url = 'http://192.168.1.22:9009/excelreport' + currentRoute.value.href?.split('?')[1] // const url = 'http://192.168.1.22:9009/excelreport' + currentRoute.value.href?.split('?')[1]
const url = ref('') const url = ref('')
const excelOptions = ref({}) const excelOptions = ref({})

View File

@@ -126,7 +126,8 @@ const prop = defineProps({
width: { type: [String, Number] }, width: { type: [String, Number] },
height: { type: [String, Number] }, height: { type: [String, Number] },
timeKey: { type: [String, Number] }, timeKey: { type: [String, Number] },
timeValue: { type: Object } timeValue: { type: Object },
searchKey: { type: [String, Number] }
}) })
const headerHeight = ref(57) const headerHeight = ref(57)
@@ -347,22 +348,22 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
watch( watch(
() => prop.timeKey, () => prop.searchKey,
val => { val => {
tableStore.index() tableStore.index()
} }
) )
watch( // watch(
() => prop.timeValue, // () => prop.timeValue,
val => { // val => {
tableStore.index() // tableStore.index()
}, // },
{ // {
deep: true // deep: true
} // }
) // )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/font/iconfont.css'; @import '@/assets/font/iconfont.css';

View File

@@ -122,7 +122,8 @@ const prop = defineProps({
width: { type: [String, Number] }, width: { type: [String, Number] },
height: { type: [String, Number] }, height: { type: [String, Number] },
timeKey: { type: [String, Number] }, timeKey: { type: [String, Number] },
timeValue: { type: Object } timeValue: { type: Object },
searchKey: { type: [String, Number] }
}) })
const headerHeight = ref(57) const headerHeight = ref(57)
@@ -183,7 +184,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0 return k.citTotalNum != 0
} else { } else {
return k.citName != '上送国网' && k.citName != '上送国网' return !k.citName.includes('上送')
} }
}) })
} }
@@ -329,22 +330,22 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
watch( watch(
() => prop.timeKey, () => prop.searchKey,
val => { val => {
tableStore.index() tableStore.index()
} }
) )
watch( // watch(
() => prop.timeValue, // () => prop.timeValue,
val => { // val => {
tableStore.index() // tableStore.index()
}, // },
{ // {
deep: true // deep: true
} // }
) // )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/font/iconfont.css'; @import '@/assets/font/iconfont.css';

View File

@@ -7,7 +7,8 @@
@selectChange="selectChange" @selectChange="selectChange"
datePicker datePicker
v-if="fullscreen" v-if="fullscreen"
></TableHeader> >
</TableHeader>
<div <div
class="monitoringPoints" class="monitoringPoints"
:style="{ :style="{
@@ -120,7 +121,8 @@ const prop = defineProps({
width: { type: [String, Number] }, width: { type: [String, Number] },
height: { type: [String, Number] }, height: { type: [String, Number] },
timeKey: { type: [String, Number] }, timeKey: { type: [String, Number] },
timeValue: { type: Object } timeValue: { type: Object },
searchKey: { type: [String, Number] }
}) })
const headerHeight = ref(57) const headerHeight = ref(57)
@@ -181,7 +183,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0 return k.citTotalNum != 0
} else { } else {
return k.citName != '上送国网' && k.citName != '上送国网' return !k.citName.includes('上送')
} }
}) })
@@ -328,22 +330,22 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
watch( watch(
() => prop.timeKey, () => prop.searchKey,
val => { val => {
tableStore.index() tableStore.index()
} }
) )
watch( // watch(
() => prop.timeValue, // () => prop.timeValue,
val => { // val => {
tableStore.index() // tableStore.index()
}, // },
{ // {
deep: true // deep: true
} // }
) // )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/font/iconfont.css'; @import '@/assets/font/iconfont.css';

View File

@@ -150,7 +150,8 @@ const prop = defineProps({
width: { type: [String, Number] }, width: { type: [String, Number] },
height: { type: [String, Number] }, height: { type: [String, Number] },
timeKey: { type: [String, Number] }, timeKey: { type: [String, Number] },
timeValue: { type: Object } timeValue: { type: Object },
searchKey: { type: [String, Number] }
}) })
const headerHeight = ref(57) const headerHeight = ref(57)
@@ -233,7 +234,7 @@ const tableStore: any = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.count != 0 return k.count != 0
} else { } else {
return k.name != '上送国网' && k.name != '上送国网' return !k.name.includes('上送')
} }
}) })
} }
@@ -246,22 +247,28 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
watch( watch(
() => prop.timeKey, () => prop.searchKey,
val => { val => {
tableStore.index() tableStore.index()
} }
) )
watch( // watch(
() => prop.timeValue, // () => prop.timeKey,
// val => {
// tableStore.index()
// }
// )
// watch(
// () => prop.timeValue,
val => { // val => {
tableStore.index() // tableStore.index()
}, // },
{ // {
deep: true // deep: true
} // }
) // )
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/font/iconfont.css'; @import '@/assets/font/iconfont.css';

View File

@@ -0,0 +1,322 @@
// 辅助函数
const getMax = (temp, tempA, tempB, tempC) => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
if (tempC !== undefined) {
temp = temp > tempC ? temp : tempC
}
return temp
}
const getMaxTwo = (temp, tempA, tempB) => {
temp = temp > tempA ? temp : tempA
temp = temp > tempB ? temp : tempB
return temp
}
const getMin = (temp, tempA, tempB, tempC) => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
if (tempC !== undefined) {
temp = temp < tempC ? temp : tempC
}
return temp
}
const getMinOpen = (temp, tempA, tempB) => {
temp = temp < tempA ? temp : tempA
temp = temp < tempB ? temp : tempB
return temp
}
// 数据处理函数
const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
const rmsData = wp.listRmsData
const pt = Number(wp.pt) / 1000
const ct = Number(wp.ct)
const titleList = wp.waveTitle
let xishu = pt
let aTitle = '',
bTitle = '',
cTitle = '',
unit = '电压'
let rmsvFirstX = 0,
rmsvFirstY = 0,
rmsvSecondX = 0,
rmsvSecondY = 0,
firstZhou = 'a',
secondeZhou = 'a'
let ifmax = 0,
ifmin = 0,
ismax = 0,
ismin = 0,
rfmax = 0,
rfmin = 0,
rsmax = 0,
rsmin = 0
const shunshiFA = []
const shunshiFB = []
const shunshiFC = []
const shunshiSA = []
const shunshiSB = []
const shunshiSC = []
const rmsFA = []
const rmsFB = []
const rmsFC = []
const rmsSA = []
const rmsSB = []
const rmsSC = []
if (titleList[iphasicValue * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct
unit = '电流'
}
for (let i = 1; i <= iphasicValue; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
case 2:
bTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
case 3:
cTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
break
}
}
if (rmsData[0] && rmsData[0][iphasicValue * step + 1] !== undefined) {
rfmax = rmsData[0][iphasicValue * step + 1] * xishu
rfmin = rmsData[0][iphasicValue * step + 1] * xishu
rmsvFirstY = rmsData[0][iphasicValue * step + 1] * xishu
rmsvFirstX = rmsData[0][0]
rsmax = rmsData[0][iphasicValue * step + 1]
rsmin = rmsData[0][iphasicValue * step + 1]
rmsvSecondY = rmsData[0][iphasicValue * step + 1]
rmsvSecondX = rmsData[0][0]
}
for (let rms = 0; rms < rmsData.length; rms++) {
if (!rmsData[rms] || rmsData[rms][iphasicValue * step + 1] === undefined) {
break
}
switch (iphasicValue) {
case 1:
const rmsFirstA = rmsData[rms][iphasicValue * step + 1] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA])
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
firstZhou = 'a'
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA = rmsData[rms][iphasicValue * step + 1]
rmsSA.push([rmsData[rms][0], rmsSecondA])
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
secondeZhou = 'a'
rmsvSecondX = rmsData[rms][0]
}
break
case 2:
const rmsFirstA2 = rmsData[rms][iphasicValue * step + 1] * xishu
const rmsFirstB2 = rmsData[rms][iphasicValue * step + 2] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA2])
rmsFB.push([rmsData[rms][0], rmsFirstB2])
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2)
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA2) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB2) {
firstZhou = 'b'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA2 = rmsData[rms][iphasicValue * step + 1]
const rmsSecondB2 = rmsData[rms][iphasicValue * step + 2]
rmsSA.push([rmsData[rms][0], rmsSecondA2])
rmsSB.push([rmsData[rms][0], rmsSecondB2])
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2)
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA2) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB2) {
secondeZhou = 'b'
}
rmsvSecondX = rmsData[rms][0]
}
break
case 3:
const rmsFirstA3 = rmsData[rms][iphasicValue * step + 1] * xishu
const rmsFirstB3 = rmsData[rms][iphasicValue * step + 2] * xishu
const rmsFirstC3 = rmsData[rms][iphasicValue * step + 3] * xishu
rmsFA.push([rmsData[rms][0], rmsFirstA3])
rmsFB.push([rmsData[rms][0], rmsFirstB3])
rmsFC.push([rmsData[rms][0], rmsFirstC3])
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3)
rfmin = isOpen
? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3)
: getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3)
if (rfmin < rmsvFirstY) {
rmsvFirstY = rfmin
if (rfmin === rmsFirstA3) {
firstZhou = 'a'
} else if (rfmin === rmsFirstB3) {
firstZhou = 'b'
} else {
firstZhou = 'c'
}
rmsvFirstX = rmsData[rms][0]
}
const rmsSecondA3 = rmsData[rms][iphasicValue * step + 1]
const rmsSecondB3 = rmsData[rms][iphasicValue * step + 2]
const rmsSecondC3 = rmsData[rms][iphasicValue * step + 3]
rmsSA.push([rmsData[rms][0], rmsSecondA3])
rmsSB.push([rmsData[rms][0], rmsSecondB3])
rmsSC.push([rmsData[rms][0], rmsSecondC3])
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3)
rsmin = isOpen
? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3)
: getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3)
if (rsmin < rmsvSecondY) {
rmsvSecondY = rsmin
if (rsmin === rmsSecondA3) {
secondeZhou = 'a'
} else if (rsmin === rmsSecondB3) {
secondeZhou = 'b'
} else {
secondeZhou = 'c'
}
rmsvSecondX = rmsData[rms][0]
}
break
}
}
const instantF = { max: ifmax, min: ifmin }
const instantS = { max: ismax, min: ismin }
const RMSF = { max: rfmax, min: rfmin }
const RMSS = { max: rsmax, min: rsmin }
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou }
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou }
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
const RMSFWave = { rmsFA, rmsFB, rmsFC }
const RMSSWave = { rmsSA, rmsSB, rmsSC }
const title = { aTitle, bTitle, cTitle, unit }
return {
instantF,
instantS,
RMSF,
RMSS,
RMSFMinDetail,
RMSSMinDetail,
shunshiF,
shunshiS,
RMSFWave,
RMSSWave,
title,
unit
}
}
// 监听消息
self.onmessage = function (e) {
const { wp, isOpen, value, boxoList, requestId } = e.data
try {
const iphasicValue = wp.iphasic || 1
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
const waveDatas = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i, iphasicValue, isOpen, boxoList)
waveDatas.push(data)
}
// 处理标题
let titles = ''
if (boxoList.systemType == 'pms') {
titles =
'变电站名称:' +
boxoList.powerStationName +
' 监测点名称:' +
boxoList.measurementPointName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'%  持续时间:' +
boxoList.duration +
's'
} else if (boxoList.systemType == 'ZL') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.equipmentName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
boxoList.evtParamVVaDepth +
'% 持续时间:' +
boxoList.evtParamTm +
's'
} else if (boxoList.systemType == 'YPT') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.persistTime +
's'
} else {
titles =
' 变电站名称:' +
boxoList.subName +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
}
// 发送处理结果回主线程
self.postMessage({
requestId,
titles: titles,
success: true,
waveDatas,
time: wp.time,
type: wp.waveType,
severity: wp.yzd,
iphasic: iphasicValue
})
} catch (error) {
self.postMessage({
requestId,
success: false,
error: error.message
})
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,207 @@
// waveData.worker.js
self.addEventListener('message', function (e) {
const { wp, value, iphasic, isOpen, boxoList, requestId } = e.data
// 处理波形数据的函数
const fliteWaveData = (wp, step) => {
// 将原有的fliteWaveData函数实现复制到这里
const shunData = wp.listWaveData
const pt = Number(wp.pt) / 1000
const ct = Number(wp.ct)
const titleList = wp.waveTitle
let xishu = pt
let aTitle = '',
bTitle = '',
cTitle = '',
unit = '电压'
let ifmax = 0,
ifmin = 0,
ismax = 0,
ismin = 0
const shunshiFA = []
const shunshiFB = []
const shunshiFC = []
const shunshiSA = []
const shunshiSB = []
const shunshiSC = []
if (shunData.length > 0) {
if (titleList[iphasic * step + 1]?.substring(0, 1) !== 'U') {
xishu = ct
unit = '电流'
}
for (let i = 1; i <= iphasic; i++) {
switch (i) {
case 1:
aTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
case 2:
bTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
case 3:
cTitle = titleList[iphasic * step + i]?.substring(1) || ''
break
}
}
if (shunData[0][iphasic * step + 1] !== undefined) {
ifmax = shunData[0][iphasic * step + 1] * xishu
ifmin = shunData[0][iphasic * step + 1] * xishu
ismax = shunData[0][iphasic * step + 1]
ismin = shunData[0][iphasic * step + 1]
}
for (let shun = 0; shun < shunData.length; shun++) {
if (shunData[shun][iphasic * step + 1] === undefined) {
break
}
switch (iphasic) {
case 1:
const shunFirstA = shunData[shun][iphasic * step + 1] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA])
ifmax = Math.max(ifmax, shunFirstA)
ifmin = Math.min(ifmin, shunFirstA)
const shunSecondA = shunData[shun][iphasic * step + 1]
shunshiSA.push([shunData[shun][0], shunSecondA])
ismax = Math.max(ismax, shunSecondA)
ismin = Math.min(ismin, shunSecondA)
break
case 2:
const shunFirstA2 = shunData[shun][iphasic * step + 1] * xishu
const shunFirstB2 = shunData[shun][iphasic * step + 2] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA2])
shunshiFB.push([shunData[shun][0], shunFirstB2])
ifmax = Math.max(ifmax, shunFirstA2, shunFirstB2)
ifmin = Math.min(ifmin, shunFirstA2, shunFirstB2)
const shunSecondA2 = shunData[shun][iphasic * step + 1]
const shunSecondB2 = shunData[shun][iphasic * step + 2]
shunshiSA.push([shunData[shun][0], shunSecondA2])
shunshiSB.push([shunData[shun][0], shunSecondB2])
ismax = Math.max(ismax, shunSecondA2, shunSecondB2)
ismin = Math.min(ismin, shunSecondA2, shunSecondB2)
break
case 3:
const shunFirstA3 = shunData[shun][iphasic * step + 1] * xishu
const shunFirstB3 = shunData[shun][iphasic * step + 2] * xishu
const shunFirstC3 = shunData[shun][iphasic * step + 3] * xishu
shunshiFA.push([shunData[shun][0], shunFirstA3])
shunshiFB.push([shunData[shun][0], shunFirstB3])
shunshiFC.push([shunData[shun][0], shunFirstC3])
ifmax = Math.max(ifmax, shunFirstA3, shunFirstB3, shunFirstC3)
ifmin = isOpen
? Math.min(ifmin, shunFirstA3, shunFirstC3)
: Math.min(ifmin, shunFirstA3, shunFirstB3, shunFirstC3)
const shunSecondA3 = shunData[shun][iphasic * step + 1]
const shunSecondB3 = shunData[shun][iphasic * step + 2]
const shunSecondC3 = shunData[shun][iphasic * step + 3]
shunshiSA.push([shunData[shun][0], shunSecondA3])
shunshiSB.push([shunData[shun][0], shunSecondB3])
shunshiSC.push([shunData[shun][0], shunSecondC3])
ismax = Math.max(ismax, shunSecondA3, shunSecondB3, shunSecondC3)
ismin = isOpen
? Math.min(ismin, shunSecondA3, shunSecondC3)
: Math.min(ismin, shunSecondA3, shunSecondB3, shunSecondC3)
break
}
}
}
const instantF = { max: ifmax, min: ifmin }
const instantS = { max: ismax, min: ismin }
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
const title = { aTitle, bTitle, cTitle, unit }
return { instantF, instantS, shunshiF, shunshiS, title, unit }
}
// 处理标题
let titles = ''
if (boxoList.systemType == 'pms') {
titles =
'变电站名称:' +
boxoList.powerStationName +
' 监测点名称:' +
boxoList.measurementPointName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
} else if (boxoList.systemType == 'ZL') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.equipmentName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
boxoList.evtParamVVaDepth +
'% 持续时间:' +
boxoList.evtParamTm +
's'
} else if (boxoList.systemType == 'YPT') {
titles =
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.persistTime +
's'
} else {
titles =
'变电站名称:' +
boxoList.subName +
' 监测点名称:' +
boxoList.lineName +
' 发生时刻:' +
boxoList.startTime +
' 暂降(骤升)幅值:' +
(boxoList.featureAmplitude * 100).toFixed(2) +
'% 持续时间:' +
boxoList.duration +
's'
}
const iphasicValue = wp.iphasic || 1
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
const waveDatas = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(wp, i)
waveDatas.push(data)
}
const time = wp.time
const type = wp.waveType
let severity = wp.yzd
if (severity < 0) {
severity = '/'
type = '/'
}
// 将处理结果发送回主线程
self.postMessage({
requestId,
success: true,
waveDatas,
time,
type,
severity,
titles,
iphasic: iphasicValue
})
})

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
<div v-if="view2"> <div v-if="view2">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<span style="font-size: 14px; line-height: 30px">值类型选择:</span> <!-- <span style="font-size: 14px; line-height: 30px">值类型选择:</span>
<el-select <el-select
style="min-width: 200px; width: 200px" style="min-width: 200px; width: 200px"
@change="changeView" @change="changeView"
@@ -15,7 +15,11 @@
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
></el-option> ></el-option>
</el-select> </el-select> -->
<el-radio-group v-model.trim="value" @change="changeView">
<el-radio-button label="一次值" :value="1" />
<el-radio-button label="二次值" :value="2" />
</el-radio-group>
<!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics"> <!-- <el-button v-if="view2 && senior" class="ml10" type="primary" @click="AdvancedAnalytics">
高级分析 高级分析
</el-button> --> </el-button> -->
@@ -24,37 +28,18 @@
<el-button @click="backbxlb" 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-col>
</el-row> </el-row>
<div v-loading="loading" style="height: calc(100vh - 190px)"> <div v-loading="loading" style="height: calc(100vh - 190px)" class="mt10">
<el-tabs v-if="view4" class="default-main" v-model="bxactiveName" @tab-click="bxhandleClick"> <el-tabs v-if="view4" type="border-card" v-model="bxactiveName"
<el-tab-pane @tab-click="bxhandleClick">
label="瞬时波形" <el-tab-pane label="瞬时波形" name="ssbx" class="boxbx pt10 pb10"
name="ssbx" :style="'height:' + bxecharts + ';overflow-y: scroll;'">
class="boxbx pt10 pb10" <shushiboxi ref="shushiboxiRef" v-if="bxactiveName == 'ssbx' && showBoxi" :value="value"
:style="'height:' + bxecharts + ';overflow-y: scroll;'" :parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></shushiboxi>
>
<shushiboxi
ref="shushiboxiRef"
v-if="bxactiveName == 'ssbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></shushiboxi>
</el-tab-pane> </el-tab-pane>
<el-tab-pane <el-tab-pane label="RMS波形" class="boxbx pt10 pb10" name="rmsbx"
label="RMS波形" :style="'height:' + bxecharts + ';overflow-y: scroll;'">
class="boxbx pt10 pb10" <rmsboxi ref="rmsboxiRef" v-if="bxactiveName == 'rmsbx' && showBoxi" :value="value"
name="rmsbx" :parentHeight="parentHeight" :boxoList="boxoList" :wp="wp"></rmsboxi>
:style="'height:' + bxecharts + ';overflow-y: scroll;'"
>
<rmsboxi
ref="rmsboxiRef"
v-if="bxactiveName == 'rmsbx' && showBoxi"
:value="value"
:parentHeight="parentHeight"
:boxoList="boxoList"
:wp="wp"
></rmsboxi>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" /> <el-empty v-else description="暂无数据" style="height: calc(100vh - 190px)" />
@@ -100,7 +85,7 @@ const options = ref([
} }
]) ])
const shushiboxiRef = ref() const shushiboxiRef = ref()
const bxecharts = ref(mainHeight(95).height as any) const bxecharts = ref(mainHeight(145).height as any)
const view2 = ref(true) const view2 = ref(true)
const boxoList: any = ref(null) const boxoList: any = ref(null)
const wp = ref(null) const wp = ref(null)
@@ -128,9 +113,6 @@ const open = async (row: any) => {
}) })
} }
const bxhandleClick = (tab: any) => { const bxhandleClick = (tab: any) => {
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
loading.value = true loading.value = true
if (tab.name == 'ssbx') { if (tab.name == 'ssbx') {
bxactiveName.value = 'ssbx' bxactiveName.value = 'ssbx'
@@ -145,8 +127,7 @@ const bxhandleClick = (tab: any) => {
const backbxlb = () => { const backbxlb = () => {
boxoList.value = null boxoList.value = null
wp.value = null wp.value = null
if (shushiboxiRef.value) shushiboxiRef.value.backbxlb()
if (rmsboxiRef.value) rmsboxiRef.value.backbxlb()
emit('backbxlb') emit('backbxlb')
} }

View File

@@ -1,22 +1,22 @@
<template> <template>
<div style="width: 540px"> <div :style="{ width: isMinuteData ? '750px' : '610px' }">
<el-select v-model="interval" style="min-width: 90px; width: 90px; margin-right: 10px" @change="timeChange"> <el-select v-model="interval" style="min-width: 90px; width: 90px; margin-right: 10px" @change="timeChange">
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
<el-date-picker <el-date-picker
v-model="timeValue" v-model="timeValue"
type="daterange" :type="pickerType"
:disabled="disabledPicker" :disabled="disabledPicker"
:disabled-date="isFutureDate" :disabled-date="isFutureDate"
style="width: 220px; margin-right: 10px" :style="{ width: isMinuteData ? '360px' : '220px', marginRight: '10px' }"
unlink-panels unlink-panels
:clearable="false" :clearable="false"
range-separator="" range-separator=""
start-placeholder="开始日期" :start-placeholder="isMinuteData ? '开始时间' : '开始日期'"
end-placeholder="结束日期" :end-placeholder="isMinuteData ? '结束时间' : '结束日期'"
value-format="YYYY-MM-DD" :value-format="pickerValueFormat"
:shortcuts="shortcuts" :shortcuts="isMinuteData ? undefined : shortcuts"
/> />
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button> <el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button> <el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
@@ -26,18 +26,41 @@
<script lang="ts" setup> <script lang="ts" setup>
import { DArrowLeft, VideoPause, DArrowRight } from '@element-plus/icons-vue' import { DArrowLeft, VideoPause, DArrowRight } from '@element-plus/icons-vue'
import { ref, onMounted, nextTick, watch } from 'vue' import { ref, onMounted, computed, watch } from 'vue'
interface Props { interface Props {
nextFlag?: boolean nextFlag?: boolean
theCurrentTime?: boolean theCurrentTime?: boolean
isStatisticData?: number | string
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
nextFlag: false, nextFlag: false,
theCurrentTime: false theCurrentTime: false,
isStatisticData: 1
}) })
const isMinuteData = computed(() => Number(props.isStatisticData) === 0)
const pickerType = computed(() => (isMinuteData.value ? 'datetimerange' : 'daterange'))
const pickerValueFormat = computed(() => (isMinuteData.value ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD'))
const toDatePart = (value: string) => (value?.includes(' ') ? value.split(' ')[0] : value)
const toMinuteStart = (date: string) => `${toDatePart(date)} 00:00:00`
const toMinuteEnd = (date: string) => `${toDatePart(date)} 23:59:59`
const normalizeRange = (start: string, end: string) => {
if (!isMinuteData.value) {
return [toDatePart(start), toDatePart(end)]
}
return [toMinuteStart(start), toMinuteEnd(end)]
}
const setRangeValue = (start: string, end: string) => {
timeValue.value = normalizeRange(start, end)
}
const interval = ref(3) const interval = ref(3)
const timeFlag = ref(1) const timeFlag = ref(1)
const count = ref(0) const count = ref(0)
@@ -95,13 +118,13 @@ const timeChange = (e: number) => {
if (e == 1) { if (e == 1) {
disabledPicker.value = true disabledPicker.value = true
timeValue.value = [setTime(1), setTime()] setRangeValue(setTime(1), setTime())
} else if (e == 2) { } else if (e == 2) {
disabledPicker.value = true disabledPicker.value = true
timeValue.value = [setTime(2), setTime()] setRangeValue(setTime(2), setTime())
} else if (e == 3) { } else if (e == 3) {
disabledPicker.value = true disabledPicker.value = true
timeValue.value = [setTime(3), setTime()] setRangeValue(setTime(3), setTime())
} else if (e == 4) { } else if (e == 4) {
let year = parseInt(setTime().substring(0, 4)) let year = parseInt(setTime().substring(0, 4))
let month = parseInt(setTime().substring(5, 7)) let month = parseInt(setTime().substring(5, 7))
@@ -111,12 +134,12 @@ const timeChange = (e: number) => {
var dayOfWeek = start.getDay() == 0 ? 7 : start.getDay() - 1 // 如果为周日则置为7天 var dayOfWeek = start.getDay() == 0 ? 7 : start.getDay() - 1 // 如果为周日则置为7天
disabledPicker.value = true disabledPicker.value = true
timeValue.value = [setTime(0, dayOfWeek), setTime(0, -6 + dayOfWeek)] setRangeValue(setTime(0, dayOfWeek), setTime(0, -6 + dayOfWeek))
} else if (e == 5) { } else if (e == 5) {
disabledPicker.value = false disabledPicker.value = false
backDisabled.value = true backDisabled.value = true
preDisabled.value = props.nextFlag ? false : true preDisabled.value = props.nextFlag ? false : true
timeValue.value = [setTime(), setTime()] setRangeValue(setTime(), setTime())
} }
if (e == 1 || e == 2) { if (e == 1 || e == 2) {
timeFlag.value = 0 timeFlag.value = 0
@@ -186,7 +209,7 @@ const preClick = () => {
startTime = year + '-01-01' startTime = year + '-01-01'
endTime = year + '-12-31' endTime = year + '-12-31'
} }
timeValue.value = [startTime, endTime] setRangeValue(startTime, endTime)
// 判断向后键的状态 // 判断向后键的状态
// var temp = NowgetEndTime() // var temp = NowgetEndTime()
@@ -415,16 +438,27 @@ const next = () => {
} }
if (!props.nextFlag) { if (!props.nextFlag) {
if ( if (
new Date(endTime + ' 00:00:00').getTime() >= new Date(toDatePart(endTime) + ' 00:00:00').getTime() >=
new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime() new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()
) { ) {
preDisabled.value = props.nextFlag ? false : true preDisabled.value = props.nextFlag ? false : true
} }
} }
timeValue.value = [startTime, endTime] setRangeValue(startTime, endTime)
} }
watch(
() => props.isStatisticData,
() => {
if (timeValue.value?.length === 2) {
setRangeValue(timeValue.value[0], timeValue.value[1])
} else {
timeChange(interval.value)
}
}
)
const setTime = (flag = 0, e = 0) => { const setTime = (flag = 0, e = 0) => {
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd') let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')

View File

@@ -1,29 +1,21 @@
<template> <template>
<div ref="tableHeader" class="cn-table-header"> <div ref="tableHeader" class="cn-table-header">
<div class="table-header ba-scroll-style"> <div class="table-header ba-scroll-style">
<el-form <el-form style="flex: 1; height: 32px; display: flex; flex-wrap: wrap" ref="headerForm" @submit.prevent=""
style="flex: 1; height: 32px; display: flex; flex-wrap: wrap" @keyup.enter="onComSearch" label-position="left" :inline="true">
ref="headerForm" <el-form-item v-if="datePicker" style="grid-column: span 2; "
@submit.prevent="" :style="{ maxWidth: isStatisticData == 0 ? '750px' : '610px' }">
@keyup.enter="onComSearch"
label-position="left"
:inline="true"
>
<el-form-item v-if="datePicker" style="grid-column: span 2; max-width: 630px">
<template #label> <template #label>
<el-checkbox v-if="showTimeAll" v-model="timeAll" label="统计时间" /> <el-checkbox v-if="showTimeAll" v-model="timeAll" label="统计时间" />
<span v-else>{{ dateLabel }}</span> <span v-else>{{ dateLabel }}</span>
</template> </template>
<DatePicker <DatePicker ref="datePickerRef" v-if="timeAll" :nextFlag="nextFlag" :theCurrentTime="theCurrentTime"
ref="datePickerRef" :isStatisticData="isStatisticData"></DatePicker>
v-if="timeAll"
:nextFlag="nextFlag"
:theCurrentTime="theCurrentTime"
></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="区域" v-if="area"> <el-form-item label="区域" v-if="area">
<Area ref="areaRef" v-model="tableStore.table.params.deptIndex" @change-value="onAreaChange" /> <Area ref="areaRef" v-model="tableStore.table.params.deptIndex" @change-value="onAreaChange"
style="width: 200px;" />
</el-form-item> </el-form-item>
<slot name="select"></slot> <slot name="select"></slot>
</el-form> </el-form>
@@ -32,43 +24,24 @@
<Icon size="14" name="el-icon-ArrowUp" style="color: #fff" v-if="showSelect" /> <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 /> <Icon size="14" name="el-icon-ArrowDown" style="color: #fff" v-else />
</el-button> </el-button>
<el-button <el-button @click="onComSearch" v-if="showSearch" :loading="tableStore.table.loading" type="primary"
@click="onComSearch" :icon="Search">
v-if="showSearch"
:loading="tableStore.table.loading"
type="primary"
:icon="Search"
>
查询 查询
</el-button> </el-button>
<el-button <el-button @click="onResetForm" v-if="showSearch && showReset" :loading="tableStore.table.loading"
@click="onResetForm" :icon="RefreshLeft">
v-if="showSearch && showReset"
:loading="tableStore.table.loading"
:icon="RefreshLeft"
>
重置 重置
</el-button> </el-button>
<el-button <el-button @click="onExport" v-if="showExport" :loading="tableStore.table.exportLoading" type="primary"
@click="onExport" icon="el-icon-Download">
v-if="showExport"
:loading="tableStore.table.exportLoading"
type="primary"
icon="el-icon-Download"
>
导出 导出
</el-button> </el-button>
</template> </template>
<slot name="operation"></slot> <slot name="operation"></slot>
</div> </div>
<el-form <el-form :style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose"
:style="showSelect && showUnfoldButton ? headerFormSecondStyleOpen : headerFormSecondStyleClose" ref="headerFormSecond" @submit.prevent="" @keyup.enter="onComSearch" label-position="left"
ref="headerFormSecond" :inline="true"></el-form>
@submit.prevent=""
@keyup.enter="onComSearch"
label-position="left"
:inline="true"
></el-form>
</div> </div>
</template> </template>
@@ -81,7 +54,7 @@ import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { Search, RefreshLeft } from '@element-plus/icons-vue' import { Search, RefreshLeft } from '@element-plus/icons-vue'
import { defineProps } from 'vue' import { defineProps } from 'vue'
const emit = defineEmits(['selectChange','areaChange']) const emit = defineEmits(['selectChange', 'areaChange'])
const tableStore = inject('tableStore') as TableStore const tableStore = inject('tableStore') as TableStore
const tableHeader = ref() const tableHeader = ref()
const datePickerRef = ref() const datePickerRef = ref()
@@ -100,6 +73,7 @@ interface Props {
showExport?: boolean //导出控制 showExport?: boolean //导出控制
showTimeAll?: boolean //控制时间是否显示 showTimeAll?: boolean //控制时间是否显示
dateLabel?: string //设置时间名称 dateLabel?: string //设置时间名称
isStatisticData?: number | string // 0分钟数据 1统计数据
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -111,7 +85,8 @@ const props = withDefaults(defineProps<Props>(), {
showReset: true, showReset: true,
showExport: false, showExport: false,
showTimeAll: false, showTimeAll: false,
dateLabel: '统计日期' dateLabel: '统计日期',
isStatisticData: 1
}) })
// 动态计算table高度 // 动态计算table高度
const resizeObserver = new ResizeObserver(entries => { const resizeObserver = new ResizeObserver(entries => {
@@ -132,9 +107,8 @@ const headerFormSecondStyleClose = {
padding: '0' padding: '0'
} }
const onAreaChange = (data) => { const onAreaChange = data => {
emit('areaChange', { label: data.label })
emit('areaChange', {label: data.label})
} }
watch( watch(
@@ -142,7 +116,6 @@ watch(
newVal => { newVal => {
setTimeout(() => { setTimeout(() => {
areaRef.value && areaRef.value.change() areaRef.value && areaRef.value.change()
}, 0) }, 0)
} }
) )
@@ -238,14 +211,14 @@ const onResetForm = () => {
//时间重置成默认值 //时间重置成默认值
datePickerRef.value?.setTheDate(3) datePickerRef.value?.setTheDate(3)
if(props.showTimeAll){ if (props.showTimeAll) {
timeAll.value = false timeAll.value = false
delete tableStore.table.params.searchBeginTime delete tableStore.table.params.searchBeginTime
delete tableStore.table.params.searchEndTime delete tableStore.table.params.searchEndTime
delete tableStore.table.params.startTime delete tableStore.table.params.startTime
delete tableStore.table.params.endTime delete tableStore.table.params.endTime
delete tableStore.table.params.timeFlag delete tableStore.table.params.timeFlag
delete tableStore.table.params.interval delete tableStore.table.params.interval
} }
if (props.datePicker && timeAll.value) { if (props.datePicker && timeAll.value) {
@@ -264,7 +237,6 @@ const setTheDate = (val: any) => {
} }
// 导出 // 导出
const onExport = () => { const onExport = () => {
tableStore.onTableAction('export', { showAllFlag: true }) tableStore.onTableAction('export', { showAllFlag: true })
} }
@@ -300,6 +272,7 @@ defineExpose({
padding: 13px 15px; padding: 13px 15px;
font-size: 14px; font-size: 14px;
overflow: hidden; overflow: hidden;
.table-header-operate-text { .table-header-operate-text {
margin-left: 6px; margin-left: 6px;
} }
@@ -327,7 +300,7 @@ defineExpose({
margin-left: 12px; margin-left: 12px;
} }
.mlr-12 + .el-button { .mlr-12+.el-button {
margin-left: 12px; margin-left: 12px;
} }
@@ -362,7 +335,7 @@ defineExpose({
border-radius: 0; border-radius: 0;
} }
.el-button + .el-button { .el-button+.el-button {
margin: 0; margin: 0;
} }
@@ -373,6 +346,7 @@ defineExpose({
html.dark { html.dark {
.table-search-button-group { .table-search-button-group {
button:focus, button:focus,
button:active { button:active {
background-color: var(--el-color-info-dark-2); background-color: var(--el-color-info-dark-2);

View File

@@ -1,24 +1,44 @@
<template> <template>
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }"> <div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
<vxe-table ref="tableRef" height="auto" :key="key" :data="tableStore.table.data" <vxe-table
v-loading="tableStore.table.loading" v-bind="Object.assign({}, defaultAttribute, $attrs)" ref="tableRef"
@checkbox-all="selectChangeEvent" @checkbox-change="selectChangeEvent" :showOverflow="showOverflow" height="auto"
@sort-change="handleSortChange"> :key="key"
:data="tableStore.table.data"
v-loading="tableStore.table.loading"
v-bind="Object.assign({}, defaultAttribute, $attrs)"
@checkbox-all="selectChangeEvent"
@checkbox-change="selectChangeEvent"
:showOverflow="showOverflow"
>
<!-- @sort-change="handleSortChange" -->
<!-- Column 组件内部是 el-table-column --> <!-- Column 组件内部是 el-table-column -->
<template v-if="isGroup"> <template v-if="isGroup">
<GroupColumn :column="tableStore.table.column" /> <GroupColumn :column="tableStore.table.column" />
</template> </template>
<template v-else> <template v-else>
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column" <Column
:tree-node="item.treeNode"> :attr="item"
:key="key + '-column'"
v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode"
>
<!-- tableStore 预设的列 render 方案 --> <!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope"> <template v-if="item.render" #default="scope">
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key + <FieldRender
'-' + :field="item"
item.render + :row="scope.row"
'-' + :column="scope.column"
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '') :index="scope.rowIndex"
" /> :key="
key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/>
</template> </template>
</Column> </Column>
</template> </template>
@@ -27,11 +47,16 @@
</div> </div>
<div v-if="tableStore.showPage" class="table-pagination"> <div v-if="tableStore.showPage" class="table-pagination">
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize" <el-pagination
:page-sizes="pageSizes" background :currentPage="tableStore.table.params!.pageNum"
:page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes"
background
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'" :layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
:total="tableStore.table.total" @size-change="onTableSizeChange" :total="tableStore.table.total"
@current-change="onTableCurrentChange"></el-pagination> @size-change="onTableSizeChange"
@current-change="onTableCurrentChange"
></el-pagination>
</div> </div>
<slot name="footer"></slot> <slot name="footer"></slot>
</template> </template>

View File

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

View File

@@ -11,25 +11,25 @@
:data="eventList.slice((pageNum - 1) * pageSize, pageNum * pageSize)" :data="eventList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
> >
<!-- <vxe-column type="seq" width="70px" title="序号"></vxe-column> --> <!-- <vxe-column type="seq" width="70px" title="序号"></vxe-column> -->
<vxe-column field="time" width="180px" sortable title="发生时刻"></vxe-column> <vxe-column field="time" width="180px" sortable title="暂降发生时刻"></vxe-column>
<vxe-column field="lineName" title="监测点"></vxe-column>
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
<template #default="{ row }">
{{ Math.floor(row.persistTime * 1000) / 1000 }}
</template>
</vxe-column>
<vxe-column field="eventValue" width="160px" sortable title="暂降(骤升)幅值(%)"> <vxe-column field="eventValue" width="160px" sortable title="暂降(骤升)幅值(%)">
<template #default="{ row }"> <template #default="{ row }">
{{ Math.floor(row.eventValue * 10000) / 100 }} {{ Math.floor(row.eventValue * 10000) / 100 }}
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="persistTime" width="120px" sortable title="持续时间(s)">
<template #default="{ row }">
{{ Math.floor(row.persistTime * 1000) / 1000 }}
</template>
</vxe-column>
<vxe-column field="eventType" width="100px" title="触发类型"> <vxe-column field="eventType" width="100px" title="触发类型">
<template #default="{ row }"> <template #default="{ row }">
{{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }} {{ event.filter(item => item.id == row.eventType)[0]?.name || '/' }}
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="powerCompany" title="变电站" width="100px"></vxe-column>
<vxe-column field="powerCompany" title="供电公司" width="100px"></vxe-column>
<vxe-column field="lineName" title="监测点"></vxe-column>
</vxe-table> </vxe-table>
<div class="table-pagination mt10"> <div class="table-pagination mt10">
<el-pagination <el-pagination
@@ -50,7 +50,8 @@ import { ref, reactive, onMounted } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import MQTT from '@/utils/mqtt' // import MQTT from '@/utils/mqtt'
import socketClient from '@/utils/webSocketClient'
const dictData = useDictData() const dictData = useDictData()
const event = dictData.getBasicData('Event_Statis') const event = dictData.getBasicData('Event_Statis')
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
@@ -68,37 +69,71 @@ const handleClose = (done: any) => {
drawer.value = false drawer.value = false
done() done()
} }
const init = async () => { const dataSocket = reactive({
const mqttClient = new MQTT('/sendEvent') socketServe: socketClient.Instance
// 设置消息接收回调 })
try { // const init = async () => {
await mqttClient.init() // const mqttClient = new MQTT('/sendEvent')
// // 设置消息接收回调
// try {
// await mqttClient.init()
// 订阅主题 // // 订阅主题
await mqttClient.subscribe() // await mqttClient.subscribe()
// 设置消息接收回调 // // 设置消息接收回调
mqttClient.onMessage((topic, message) => { // mqttClient.onMessage((topic, message) => {
const msg = JSON.parse(message.toString()) // const msg = JSON.parse(message.toString())
// console.log('🚀 ~ init ~ msg:', msg) // // console.log('🚀 ~ init ~ msg:', msg)
if (msg.deptList.includes(adminInfo.$state.deptId)) { // if (msg.deptList.includes(adminInfo.$state.deptId)) {
drawer.value = true // drawer.value = true
isLoading.value = true // isLoading.value = true
eventList.value.unshift(msg) // eventList.value.unshift(msg)
setTimeout(() => { // setTimeout(() => {
isLoading.value = false // isLoading.value = false
}, 500) // }, 500)
} // }
}) // })
} catch (error) { // } catch (error) {
// console.error('MQTT 初始化失败:', 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(() => { onMounted(() => {
// startMqtt('/sendEvent', (topic, message) => { // startMqtt('/sendEvent', (topic, message) => {
// const msg = JSON.parse(message.toString()) // const msg = JSON.parse(message.toString())
// console.log(msg) // console.log(msg)
// }) // })
init()
setTimeout(() => {
socket()
}, 3000)
}) })
defineExpose({ defineExpose({
open, open,

View File

@@ -8,41 +8,14 @@
name="el-icon-BellFilled" name="el-icon-BellFilled"
size="18" size="18"
/> />
<span class="nav-menu-text" v-if="globalPopUpRef?.eventList.length != 0"> <span class="nav-menu-text" v-if="globalPopUpRef?.eventList?.length > 0">
{{ (globalPopUpRef?.eventList.length>99? '99+':globalPopUpRef?.eventList.length) || 0 }} {{ globalPopUpRef.eventList.length > 99 ? '99+' : globalPopUpRef.eventList.length }}
</span> </span>
</div> </div>
</el-tooltip> </el-tooltip>
<!-- <el-tooltip effect="dark" content="截图" placement="bottom">
<div @click="savePng" class="nav-menu-item">
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
class="nav-menu-icon"
name="el-icon-Camera"
size="18"
/>
</div>
</el-tooltip>
<el-tooltip effect="dark" :content="state.isFullScreen ? '缩小' : '放大'" placement="bottom">
<div @click="onFullScreen" class="nav-menu-item" :class="state.isFullScreen ? 'hover' : ''">
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
class="nav-menu-icon"
v-if="state.isFullScreen"
name="fa-solid fa-compress"
size="18"
/>
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
class="nav-menu-icon"
v-else
name="fa-solid fa-expand"
size="18"
/>
</div>
</el-tooltip> -->
<el-dropdown style="height: 100%" @command="handleCommand"> <el-dropdown style="height: 100%" @command="handleCommand">
<div class="admin-info" :class="state.currentNavMenu == 'adminInfo' ? 'hover' : ''"> <div class="admin-info" :class="state.currentNavMenu === 'adminInfo' ? 'hover' : ''">
<el-avatar :size="25" fit="fill"> <el-avatar :size="25" fit="fill">
<img src="@/assets/avatar.png" alt="" /> <img src="@/assets/avatar.png" alt="" />
</el-avatar> </el-avatar>
@@ -51,105 +24,114 @@
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item command="adminInfo">个人资料</el-dropdown-item> <el-dropdown-item command="adminInfo">个人资料</el-dropdown-item>
<el-dropdown-item command="changePwd">修改密码</el-dropdown-item> <el-dropdown-item command="changePwd" v-if="!IS_LNQR">修改密码</el-dropdown-item>
<el-dropdown-item command="layout">退出登录</el-dropdown-item> <el-dropdown-item command="logout">退出登录</el-dropdown-item>
</el-dropdown-menu> </el-dropdown-menu>
</template> </template>
</el-dropdown> </el-dropdown>
<!-- <div @click="configStore.setLayout('showDrawer', true)" class="nav-menu-item">
<Icon
:color="configStore.getColorVal('headerBarTabColor')"
class="nav-menu-icon"
name="fa fa-cogs"
size="18"
/>
</div> -->
<Config /> <Config />
<PopupPwd ref="popupPwd" /> <PopupPwd ref="popupPwd" />
<AdminInfo ref="popupAdminInfo" /> <AdminInfo ref="popupAdminInfo" />
<!-- <TerminalVue /> -->
<!-- 全局暂降事件 -->
<globalPopUp ref="globalPopUpRef" /> <globalPopUp ref="globalPopUpRef" />
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { reactive, ref } from 'vue' import { reactive, ref } from 'vue'
import screenfull from 'screenfull'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { ElMessage } from 'element-plus'
import Config from './config.vue'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import router from '@/router' import { useNavTabs } from '@/stores/navTabs'
import globalPopUp from './globalPopUp.vue' import { logout } from '@/api/user-boot/user'
import { routePush } from '@/utils/router' import Config from './config.vue'
import html2canvas from 'html2canvas'
import PopupPwd from './popup/password.vue' import PopupPwd from './popup/password.vue'
import AdminInfo from './popup/adminInfo.vue' import AdminInfo from './popup/adminInfo.vue'
import { useNavTabs } from '@/stores/navTabs' const { replace } = useRouter()
// 环境标识
const IS_LNQR = import.meta.env.VITE_NAME === 'LNqr'
const adminInfo = useAdminInfo() const adminInfo = useAdminInfo()
const navTabs = useNavTabs() const navTabs = useNavTabs()
const configStore = useConfig() const configStore = useConfig()
// 引用
const popupPwd = ref() const popupPwd = ref()
const popupAdminInfo = ref() const popupAdminInfo = ref()
const state = reactive({
isFullScreen: false,
currentNavMenu: '',
showLayoutDrawer: false,
showAdminInfoPopover: false
})
const globalPopUpRef = ref() const globalPopUpRef = ref()
const savePng = () => {
html2canvas(document.body, { // 状态
scale: 1, const state = reactive({
useCORS: true currentNavMenu: ''
}).then(function (canvas) { })
var link = document.createElement('a')
link.href = canvas.toDataURL('image/png') // 打开暂降事件
link.download = 'screenshot.png' const temporaryLandingEvent = () => {
link.click() if (globalPopUpRef.value) {
}) globalPopUpRef.value.open()
}
const onFullScreen = () => {
if (!screenfull.isEnabled) {
ElMessage.warning('layouts.Full screen is not supported')
return false
} }
screenfull.toggle()
screenfull.onchange(() => {
state.isFullScreen = screenfull.isFullscreen
})
} }
const handleCommand = async(key: string) => { // 下拉菜单命令
console.log(key) const handleCommand = async (key: string) => {
switch (key) { switch (key) {
case 'adminInfo': case 'adminInfo':
popupAdminInfo.value.open() popupAdminInfo.value?.open()
break break
case 'changePwd': case 'changePwd':
popupPwd.value.open() popupPwd.value?.open()
break break
case 'layout': case 'logout':
await window.location.reload() await handleLogout()
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 break
} }
} }
const temporaryLandingEvent = () => {
globalPopUpRef.value.open() // 统一登出逻辑
const handleLogout = async () => {
try {
// 1. 调用后端登出接口
await logout()
console.log('✅ 后端登出成功')
} catch (err) {
console.error('❌ 登出接口异常', err)
} finally {
// 2. 清理本地所有数据
clearLocalData()
// 3. LNqr 环境跳 CAS 登出
if (IS_LNQR) {
redirectToCasLogout()
} else {
// 普通环境直接跳登录页
replace('/login')
}
}
}
// 清理本地数据
const clearLocalData = () => {
// 清空 localStorage
window.localStorage.clear()
// 清空用户状态
adminInfo.reset()
// 清空标签页
navTabs.closeTabs()
console.log('✅ 本地数据已全部清空')
}
// CAS 登出跳转
const redirectToCasLogout = () => {
const casLogoutUrl =
'http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/logout?service=http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/login?service=http://PQMonitoring.dcloud.ln.dc.sgcc.com.cn'
window.location.href = casLogoutUrl
// 清 Cookie
document.cookie.split(';').forEach(cookie => {
const name = cookie.split('=')[0].trim()
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`
})
} }
</script> </script>
@@ -163,7 +145,6 @@ const temporaryLandingEvent = () => {
height: 60px; height: 60px;
display: flex; display: flex;
align-items: center; align-items: center;
// height: 100%;
margin-left: auto; margin-left: auto;
background-color: v-bind('configStore.getColorVal("headerBarBackground")'); background-color: v-bind('configStore.getColorVal("headerBarBackground")');
@@ -219,37 +200,15 @@ const temporaryLandingEvent = () => {
} }
} }
.dropdown-menu-box :deep(.el-dropdown-menu__item) { .nav-menu-text {
justify-content: center; position: absolute;
} top: 13px;
left: 20px;
.admin-info-base { font-size: 12px;
display: flex; background: #ff0000;
justify-content: center; color: #fff;
flex-wrap: wrap; border-radius: 5px;
padding-top: 10px; padding: 0 3px;
.admin-info-other {
display: block;
width: 100%;
text-align: center;
padding: 10px 0;
.admin-info-name {
font-size: var(--el-font-size-large);
}
}
}
.admin-info-footer {
padding: 10px 0;
margin: 0 -12px -12px -12px;
display: flex;
justify-content: space-around;
}
.pt2 {
padding-top: 2px;
} }
@keyframes twinkle { @keyframes twinkle {
@@ -263,15 +222,4 @@ const temporaryLandingEvent = () => {
transform: scale(1); transform: scale(1);
} }
} }
.nav-menu-text {
position: absolute;
top: 13px;
left: 20px;
font-size: 12px;
display: inline-block;
background-color: #ff0000;
color: #fff;
border-radius: 5px;
padding: 0 3px;
}
</style> </style>

View File

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

View File

@@ -0,0 +1,59 @@
const AXIS_DECIMALS = 2
export function roundAxisValue(val: number, decimals = AXIS_DECIMALS): number {
if (!Number.isFinite(val)) return 0
const factor = 10 ** decimals
return Math.round(val * factor) / factor
}
/** Y 轴刻度:最多 2 位小数,末尾 0 去掉(如 1.00 → 10.10 → 0.1 */
export function formatAxisLabel(value: number): string {
if (!Number.isFinite(value)) return '0'
return String(Number(roundAxisValue(value).toFixed(AXIS_DECIMALS)))
}
/** 瞬间波形 Y 轴范围 */
export function calcShuYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
const min = Number(dataMin)
const max = Number(dataMax)
if (!Number.isFinite(min) || !Number.isFinite(max)) {
return { min: 0, max: 1 }
}
let axisMax = max * 1.1
let axisMin = min > 0 ? min - min * 0.1 : min * 1.1
if (axisMax <= axisMin) {
const pad = Math.abs(max) * 0.1 || 0.01
axisMax = max + pad
axisMin = min - pad
}
return {
min: roundAxisValue(axisMin),
max: roundAxisValue(axisMax)
}
}
/** RMS 波形 Y 轴范围 */
export function calcRmsYAxisRange(dataMin: number, dataMax: number): { min: number; max: number } {
const min = Number(dataMin)
const max = Number(dataMax)
if (!Number.isFinite(min) || !Number.isFinite(max)) {
return { min: 0, max: 1 }
}
let axisMax = max * 1.06 * 1.1
let axisMin = min - min * 0.2
if (axisMax <= axisMin) {
const pad = Math.abs(max - min) * 0.1 || Math.abs(max) * 0.1 || 0.01
axisMax = max + pad
axisMin = min - pad
}
return {
min: roundAxisValue(axisMin),
max: roundAxisValue(axisMax)
}
}

View File

@@ -7,7 +7,7 @@ export const PROCESS_BOOT = '/process-boot'
//工作流模块 //工作流模块
export const BPM_BOOT = '/bpm-boot' export const BPM_BOOT = '/bpm-boot'
//冀北技术监督 //网公司技术监督
export const SUPERVISION_BOOT = '/supervision-boot' export const SUPERVISION_BOOT = '/supervision-boot'
//终端模块 //终端模块

View File

@@ -11,6 +11,7 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (value > -1 && value < 0 && isMin == false) { } else if (value > -1 && value < 0 && isMin == false) {
return 0 return 0
} }
let base let base
if (Math.abs(o) >= 100) { if (Math.abs(o) >= 100) {
base = 100 base = 100
@@ -19,8 +20,11 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
} else if (Math.abs(o) >= 1) { } else if (Math.abs(o) >= 1) {
base = 1 base = 1
} else { } else {
base = 0.1 const multiple = 1 / 0.1
base = Math.ceil(Math.abs(o) * multiple) / multiple
} }
let calculatedValue let calculatedValue
if (isMin) { if (isMin) {
if (value < 0) { if (value < 0) {
@@ -35,98 +39,37 @@ const calculateValue = (o: number, value: number, num: number, isMin: boolean) =
calculatedValue = value + num * value calculatedValue = value + num * value
} }
} }
if (base === 0.1) { if (base === 0.1) {
return parseFloat(calculatedValue.toFixed(1)) // return parseFloat(calculatedValue.toFixed(1))
return Math.ceil(calculatedValue * 10) / 10
} else if (isMin) { } else if (isMin) {
return Math.floor(calculatedValue / base) * base return Math.floor(calculatedValue / base) * base
} else { } else {
return Math.ceil(calculatedValue / base) * base return Math.ceil(calculatedValue / base) * base
} }
} }
// 处理y轴最大最小值 // 处理y轴最大最小值
export const yMethod = (arr: any) => { export const yMethod = (arr: any) => {
let num = 0.1 let num = 0.2
let numList = dataProcessing(arr) let numList = dataProcessing(arr)
let maxValue = 0 if (numList.length === 0) {
let minValue = 0 return [0, 0]
let max = 0
let min = 0
maxValue = Math.max(...numList)
minValue = Math.min(...numList)
const o = maxValue - minValue
if (Math.abs(o) >= 300) {
num = 0.02
} }
const maxValue = Math.max(...numList)
const minValue = Math.min(...numList)
let min = 0
let max = 0
min = calculateValue(o, minValue, num, true) // 一正一负时各自按绝对值范围计算,不用 max - min 作为跨度
max = calculateValue(o, maxValue, num, false) if (maxValue > 0 && minValue < 0) {
// if (-100 >= minValue) { min = calculateValue(Math.abs(minValue), minValue, num, true)
// min = Math.floor((minValue + num * minValue) / 100) * 100 max = calculateValue(Math.abs(maxValue), maxValue, num, false)
// } else if (-10 >= minValue && minValue > -100) { } else {
// min = Math.floor((minValue + num * minValue) / 10) * 10 const o = maxValue - minValue === 0 ? maxValue : maxValue - minValue
// } else if (-1 >= minValue && minValue > -10) { min = calculateValue(o, minValue, num, true)
// min = Math.floor(minValue + num * minValue) max = calculateValue(o, maxValue, num, false)
// } else if (0 > minValue && minValue > -1) { }
// min = parseFloat((minValue + num * minValue).toFixed(1))
// } else if (minValue == 0) {
// min = 0
// } else if (0 < minValue && minValue < 1) {
// min = parseFloat((minValue - num * minValue).toFixed(1))
// } else if (1 <= minValue && minValue < 10) {
// min = Math.floor(minValue - num * minValue)
// } else if (10 <= minValue && minValue < 100) {
// min = Math.floor((minValue - num * minValue) / 10) * 10
// } else if (100 <= minValue) {
// min = Math.floor((minValue - num * minValue) / 100) * 100
// }
// if (-100 >= maxValue) {
// max = Math.ceil((maxValue - num * maxValue) / 100) * 100
// } else if (-10 >= maxValue && maxValue > -100) {
// max = Math.ceil((maxValue - num * maxValue) / 10) * 10
// } else if (-1 >= maxValue && maxValue > -10) {
// max = Math.ceil(maxValue - num * maxValue)
// } else if (0 > maxValue && maxValue > -1) {
// max = parseFloat((maxValue - num * maxValue).toFixed(1))
// } else if (maxValue == 0) {
// max = 0
// } else if (0 < maxValue && maxValue < 1) {
// max = parseFloat((maxValue + num * maxValue).toFixed(1))
// } else if (1 <= maxValue && maxValue < 10) {
// max = Math.ceil(maxValue + num * maxValue)
// } else if (10 <= maxValue && maxValue < 100) {
// max = Math.ceil((maxValue + num * maxValue) / 10) * 10
// } else if (100 <= maxValue) {
// max = Math.ceil((maxValue + num * maxValue) / 100) * 100
// }
// if (maxValue > 1000 || minValue < -1000) {
// max = Math.ceil(maxValue / 100) * 100
// if (minValue == 0) {
// min = 0
// } else {
// min = Math.floor(minValue / 100) * 100
// }
// } else if (maxValue < 60 && minValue > 40) {
// max = 60
// min = 40
// } else if (maxValue == minValue && maxValue < 10 && minValue > 0) {
// max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10
// } else if (maxValue == minValue && maxValue != 0 && minValue != 0) {
// max = Math.ceil(maxValue / 10 + 1) * 10
// min = Math.floor(minValue / 10 - 1) * 10
// } else {
// max = Math.ceil(maxValue / 10) * 10
// min = Math.floor(minValue / 10) * 10
// }
// if (maxValue > 0 && maxValue < 1) {
// max = 1
// } else if (max == 0 && minValue > -1 && minValue < 0) {
// min = -1
// }
return [min, max] return [min, max]
} }
@@ -158,8 +101,6 @@ export const exportCSV = (title: object, data: any, filename: string) => {
URL.revokeObjectURL(link.href) URL.revokeObjectURL(link.href)
} }
/** /**
* 补全时间序列数据中缺失的条目 * 补全时间序列数据中缺失的条目
* @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...] * @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...]

View File

@@ -27,8 +27,8 @@ class MQTT {
clean: true, clean: true,
connectTimeout: 30 * 1000, connectTimeout: 30 * 1000,
clientId: `mqttjs_${Math.random().toString(16).substr(2, 8)}`, clientId: `mqttjs_${Math.random().toString(16).substr(2, 8)}`,
username: 't_user', username: '',
password: 'njcnpqs', password: '',
reconnectPeriod: 1000, // 默认1秒重试一次 reconnectPeriod: 1000, // 默认1秒重试一次
maxReconnectTimes: 3 // 默认最大重连5次 maxReconnectTimes: 3 // 默认最大重连5次
} }

View File

@@ -1,10 +1,11 @@
import type { AxiosRequestConfig, Method } from 'axios' import type { AxiosRequestConfig, Method } from 'axios'
import axios from 'axios' import axios from 'axios'
import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus' import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus'
import { refreshToken } from '@/api/user-boot/user' import { lnRefreshToken, lnRefreshTokenTo, refreshToken } from '@/api/user-boot/user'
import router from '@/router/index' import router from '@/router/index'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import { debounce } from 'lodash-es' import { debounce } from 'lodash-es'
const IS_LN_VERSION = import.meta.env.VITE_NAME === 'LNqr'
let loginExpireTimer: any = null let loginExpireTimer: any = null
window.requests = [] window.requests = []
window.tokenRefreshing = false window.tokenRefreshing = false
@@ -107,7 +108,12 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
config.headers.Authorization = 'Basic bmpjbjpuamNucHFz' config.headers.Authorization = 'Basic bmpjbjpuamNucHFz'
} }
} }
if (config.url == '/user-boot/user/generateSm2Key' || config.url == '/pqs-auth/oauth/token') { if (
config.url == '/user-boot/user/generateSm2Key' ||
config.url == '/pqs-auth/oauth/token' ||
config.url == '/pqs-auth/oauth/lnLogin' ||
config.url == '/pqs-auth/oauth/lnRefreshToken'
) {
config.headers.Authorization = 'Basic bmpjbjpuamNucHFz' config.headers.Authorization = 'Basic bmpjbjpuamNucHFz'
} }
@@ -142,24 +148,46 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
if (!window.tokenRefreshing) { if (!window.tokenRefreshing) {
window.tokenRefreshing = true window.tokenRefreshing = true
return refreshToken() if (IS_LN_VERSION) {
.then(res => { //辽宁版本
adminInfo.setToken(res.data.access_token, 'auth') return lnRefreshTokenTo()
adminInfo.setToken(res.data.refresh_token, 'refresh') .then(res => {
window.requests.forEach(cb => cb(res.data.access_token)) adminInfo.setToken(res.data.access_token, 'auth')
window.requests = [] adminInfo.setToken(res.data.refresh_token, 'refresh')
window.requests.forEach(cb => cb(res.data.access_token))
window.requests = []
return Axios(response.config) return Axios(response.config)
}) })
.catch(err => { .catch(err => {
window.location.reload() // refresh_token + CAS 都过期 → 重新走CAS登录
adminInfo.removeToken() window.location.href = '/api/pqs-auth/oauth/lnCheck'
router.push({ name: 'login' }) return Promise.reject(err)
return Promise.reject(err) })
}) .finally(() => {
.finally(() => { window.tokenRefreshing = false
window.tokenRefreshing = false })
}) } else {
//通用版本
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)
})
.finally(() => {
window.tokenRefreshing = false
})
}
} else { } else {
return new Promise(resolve => { return new Promise(resolve => {
// 用函数形式将 resolve 存入,等待刷新后再执行 // 用函数形式将 resolve 存入,等待刷新后再执行
@@ -184,6 +212,13 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
router.push({ name: 'login' }) router.push({ name: 'login' })
loginExpireTimer = null // 执行后清空定时器 loginExpireTimer = null // 执行后清空定时器
}, 100) // 可根据实际情况调整延迟时间 }, 100) // 可根据实际情况调整延迟时间
return Promise.reject(response.data)
} else if (response.data.code == 'A0121') {
//统一认证过期
const casLogoutUrl =
'http://privilege-epri.dcloud.ln.dc.sgcc.com.cn/cas/login?service=http://PQMonitoring.dcloud.ln.dc.sgcc.com.cn'
window.location.href = casLogoutUrl
return Promise.reject(response.data) return Promise.reject(response.data)
} else { } else {
if (options.showCodeMessage) { if (options.showCodeMessage) {

View File

@@ -147,7 +147,39 @@ export const filter = <T = any>(
return listFilter(tree) 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>( export const forEach = <T = any>(
tree: T[], tree: T[],
func: (n: T) => any, func: (n: T) => any,

42
src/utils/waveCache.ts Normal file
View File

@@ -0,0 +1,42 @@
const MAX_CACHE_SIZE = 30
const cache = new Map<string, unknown>()
function dataFingerprint(data: unknown[][] | undefined): string {
if (!data?.length) return '0'
const first = data[0]
const last = data[data.length - 1]
return `${data.length}:${first?.[0]}:${last?.[0]}`
}
export function buildWaveCacheKey(
type: 'shu' | 'rms',
wp: Record<string, any> | undefined,
value: number,
isOpen: boolean,
boxoList: Record<string, any>
): string {
if (!wp) return ''
const waveFp =
type === 'shu' ? dataFingerprint(wp.listWaveData) : dataFingerprint(wp.listRmsData)
const boxoFp = boxoList?.startTime ?? boxoList?.lineName ?? boxoList?.equipmentName ?? ''
return `${type}|${wp.time}|${wp.waveType}|${wp.iphasic}|${value}|${isOpen}|${waveFp}|${boxoFp}`
}
export function getWaveCache<T>(key: string): T | null {
if (!key || !cache.has(key)) return null
const value = cache.get(key) as T
cache.delete(key)
cache.set(key, value)
return value
}
export function setWaveCache(key: string, value: unknown): void {
if (!key) return
if (cache.has(key)) cache.delete(key)
cache.set(key, value)
while (cache.size > MAX_CACHE_SIZE) {
const oldest = cache.keys().next().value
if (oldest !== undefined) cache.delete(oldest)
}
}

View File

@@ -0,0 +1,96 @@
import { toRaw } from 'vue'
type WorkerMessageHandler = (data: any) => void
let shuWorker: Worker | null = null
let rmsWorker: Worker | null = null
/** 递归剥离 Vue 响应式代理,得到可 structuredClone 的纯对象 */
export function toPlainDeep<T>(value: T): T {
const raw = toRaw(value as object) as T
if (Array.isArray(raw)) {
return raw.map(item => toPlainDeep(item)) as T
}
if (raw !== null && typeof raw === 'object') {
const out: Record<string, unknown> = {}
for (const [key, val] of Object.entries(raw)) {
out[key] = toPlainDeep(val)
}
return out as T
}
return raw
}
const BOXO_LIST_KEYS = [
'systemType',
'powerStationName',
'measurementPointName',
'startTime',
'featureAmplitude',
'duration',
'engineeringName',
'equipmentName',
'evtParamVVaDepth',
'evtParamTm',
'lineName',
'persistTime',
'subName'
] as const
export function buildWorkerPayload(
type: 'shu' | 'rms',
wp: Record<string, any>,
boxoList: Record<string, any>,
extras: { requestId: number; value: number; isOpen: boolean; iphasic?: number }
) {
const plainWp = toPlainDeep(wp)
const wpPayload: Record<string, unknown> = {
pt: plainWp.pt,
ct: plainWp.ct,
waveTitle: plainWp.waveTitle,
iphasic: plainWp.iphasic,
time: plainWp.time,
waveType: plainWp.waveType,
yzd: plainWp.yzd
}
if (type === 'shu') {
wpPayload.listWaveData = plainWp.listWaveData
} else {
wpPayload.listRmsData = plainWp.listRmsData
}
const plainBoxo: Record<string, unknown> = {}
const rawBoxo = toPlainDeep(boxoList)
for (const key of BOXO_LIST_KEYS) {
if (rawBoxo[key] !== undefined) {
plainBoxo[key] = rawBoxo[key]
}
}
return {
requestId: extras.requestId,
value: extras.value,
isOpen: extras.isOpen,
iphasic: extras.iphasic,
wp: wpPayload,
boxoList: plainBoxo
}
}
export function getShuWorker(onMessage: WorkerMessageHandler): Worker {
if (!shuWorker) {
shuWorker = new Worker(new URL('../components/echarts/shuWorker.js', import.meta.url))
}
shuWorker.onmessage = e => onMessage(e.data)
shuWorker.onerror = error => console.error('Shu worker error:', error)
return shuWorker
}
export function getRmsWorker(onMessage: WorkerMessageHandler): Worker {
if (!rmsWorker) {
rmsWorker = new Worker(new URL('../components/echarts/rmsWorker.js', import.meta.url))
}
rmsWorker.onmessage = e => onMessage(e.data)
rmsWorker.onerror = error => console.error('Rms worker error:', error)
return rmsWorker
}

View File

@@ -44,12 +44,10 @@ export default class SocketService {
return return
} }
console.log("🚀 ~ SocketService ~ connect ~ url:", url)
if (url === null || (typeof url === 'string' && url.includes('null'))) return;
setTimeout(() => { 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 = new WebSocket(url)
this.ws.onopen = () => this.handleOpen() this.ws.onopen = () => this.handleOpen()
@@ -58,10 +56,9 @@ export default class SocketService {
this.ws.onmessage = event => this.handleMessage(event) this.ws.onmessage = event => this.handleMessage(event)
}, 0) }, 0)
} }
// 处理连接成功事件 // 处理连接成功事件
private handleOpen(): void { private handleOpen(): void {
ElMessage.success('webSocket连接服务端成功了') // ElMessage.success('webSocket连接服务端成功了')
console.log('连接服务端成功了') console.log('连接服务端成功了')
this.connected = true this.connected = true
this.connectRetryCount = 0 this.connectRetryCount = 0
@@ -90,7 +87,7 @@ export default class SocketService {
if (event.data == '连接成功') { if (event.data == '连接成功') {
this.sendHeartbeat() this.sendHeartbeat()
} else if (event.data == 'connect') { } else if (event.data == 'over') {
} else if (event.data.length > 10) { } else if (event.data.length > 10) {
let message: MessageType let message: MessageType
try { try {
@@ -104,7 +101,7 @@ export default class SocketService {
// 通过接受服务端发送的type字段来回调函数 // 通过接受服务端发送的type字段来回调函数
if ((message.key || message.code) && this.callBackMapping['message']) { if ((message.key || message.code || message.time) && this.callBackMapping['message']) {
this.callBackMapping['message']!(message) this.callBackMapping['message']!(message)
} else { } else {
console.log('抛弃====>') console.log('抛弃====>')
@@ -112,6 +109,8 @@ export default class SocketService {
// 丢弃或继续写你的逻辑 // 丢弃或继续写你的逻辑
} }
} else { } else {
this.callBackMapping['message']!({ Flag: false })
if(event.data == 'connect')return
ElMessage.error(event.data) ElMessage.error(event.data)
} }
} }

View File

@@ -50,12 +50,12 @@
min-width="150px" min-width="150px"
show-overflow-tooltip show-overflow-tooltip
></vxe-column> ></vxe-column>
<vxe-column field="startTime" title="暂降发生时刻" min-width="150px"></vxe-column> <vxe-column field="startTime" title="暂降发生时刻" min-width="180px" sortable></vxe-column>
<vxe-column <vxe-column
field="featureAmplitude" field="featureAmplitude"
title="暂降(骤升)幅值(%)" title="暂降(骤升)幅值(%)"
sortable sortable
min-width="150px" min-width="160px"
></vxe-column> ></vxe-column>
<vxe-column <vxe-column
field="advanceReason" field="advanceReason"

View File

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

View File

@@ -1107,7 +1107,7 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
class="form-item" class="form-item"
label="测量点性质:" label="电网标志:"
:prop=" :prop="
'deviceParam.' + 'deviceParam.' +
[deviceIndex] + [deviceIndex] +
@@ -1119,14 +1119,14 @@
" "
:rules="{ :rules="{
required: true, required: true,
message: '请选择测量点性质', message: '请选择电网标志',
trigger: 'blur' trigger: 'blur'
}" }"
> >
<el-select <el-select
filterable filterable
v-model="lineItem.powerFlag" v-model="lineItem.powerFlag"
placeholder="请选择测量点性质" placeholder="请选择电网标志"
:disabled="pageStatus == 1" :disabled="pageStatus == 1"
@change="lineItem.objId = ''" @change="lineItem.objId = ''"
> >
@@ -1140,14 +1140,15 @@
</el-form-item> </el-form-item>
<el-form-item <el-form-item
class="form-item" class="form-item"
label="用户名称:" label="监测对象名称:"
v-if="lineItem.powerFlag == 1" v-if="lineItem.powerFlag == 1"
> >
<el-select <el-select
filterable filterable
v-model="lineItem.objId" v-model="lineItem.objId"
placeholder="请选择用户名称" placeholder="请选择对象名称"
:disabled="pageStatus == 1" :disabled="pageStatus == 1"
@change="(val) => handleSelect(lineItem, val)"
clearable clearable
> >
<el-option <el-option
@@ -1355,7 +1356,7 @@
lIndex + lIndex +
'.bigObjType' '.bigObjType'
" "
:rules="{ required: true, message: '请选择对象大类', trigger: 'blur' }"
> >
<el-select <el-select
filterable filterable
@@ -1384,7 +1385,7 @@
lIndex + lIndex +
'.smallObjType' '.smallObjType'
" "
:rules="{ required: true, message: '请选择对象小类', trigger: 'blur' }"
> >
<el-select <el-select
filterable filterable
@@ -2202,6 +2203,22 @@ const category = () => {
bigList.value = convertToTree(res.data) bigList.value = convertToTree(res.data)
}) })
} }
//用户对象chage事件
const handleSelect = (item, selectedId) => {
// 清空选择
if (!selectedId) {
item.projectName = ''
return
}
// 过滤当前下拉数据源
const options = newStationIdArr.value.find(i => i.id === selectedId)
if (options) {
item.objName = options.projectName
}
}
// 组装用户大小类 // 组装用户大小类
const convertToTree = (data: any) => { const convertToTree = (data: any) => {
const nodeMap: any = {} const nodeMap: any = {}
@@ -2911,7 +2928,7 @@ const selectChanged = async (value: any) => {
capacity = 750 capacity = 750
break break
case '35': case '35':
capacity = 259 capacity = 250
break break
case '10': case '10':
capacity = 100 capacity = 100
@@ -2931,9 +2948,9 @@ const selectChanged = async (value: any) => {
case '750': case '750':
capacity = 7000 capacity = 7000
break break
case '800': // case '800':
capacity = 7000 // capacity = 7000
break // break
case '1000': case '1000':
capacity = 9000 capacity = 9000
break break

View File

@@ -2,7 +2,7 @@
<div class="default-main"> <div class="default-main">
<TableHeader :showReset="false" showExport> <TableHeader :showReset="false" showExport>
<template #select> <template #select>
<el-form-item label="关键字筛选"> <el-form-item label="筛选数据">
<el-input <el-input
maxlength="32" maxlength="32"
show-word-limit show-word-limit

View File

@@ -504,14 +504,16 @@ const maintenance = (val: any) => {
id: val.tfIndex, id: val.tfIndex,
subId: val.subIndex subId: val.subIndex
}).then(res => { }).then(res => {
bind.value = res.data.bind bind.value = res.data.bind
treeMenuLeftData.value = res.data.upNode treeMenuLeftData.value = res.data.upNode
treeMenuRightData.value = res.data.downNode treeMenuRightData.value = res.data.downNode
setDisabled(treeMenuRightData.value) setDisabled(treeMenuRightData.value)
setDisabled(treeMenuLeftData.value) setDisabled(treeMenuLeftData.value)
isLoading3.value = false isLoading3.value = false
if (treeMenuLeftData.value && treeMenuLeftData.value.length > 0) { if (treeMenuLeftData.value && treeMenuLeftData.value.length > 0) {
treeMenuLeftData.value[0].children?.forEach(item => { /* treeMenuLeftData.value[0].children?.forEach(item => {
item.children?.forEach(item1 => { item.children?.forEach(item1 => {
item1.children?.forEach(item2 => { item1.children?.forEach(item2 => {
item2.children?.forEach(item3 => { item2.children?.forEach(item3 => {
@@ -523,21 +525,25 @@ const maintenance = (val: any) => {
}) })
}) })
}) })
}) })*/
menuTreeLeft.value?.setCheckedKeys([bind.value[0]])
maintenanceData.upNode = bind.value[0]
bindLevel.value = 5
} }
if (treeMenuRightData.value && treeMenuRightData.value.length > 0) { if (treeMenuRightData.value && treeMenuRightData.value.length > 0) {
treeMenuRightData.value[0].children?.forEach(item => { /* treeMenuRightData.value[0].children?.forEach(item => {
item.children?.forEach(item1 => { item.children?.forEach(item1 => {
item1.children?.forEach(item2 => { item1.children?.forEach(item2 => {
item2.children?.forEach(item3 => { item2.children?.forEach(item3 => {
if (item3.level != null) { if (item3.level != null) {
menuTreeRight.value?.setCheckedKeys([item3.id])
maintenanceData.downNode = item3.id
} }
}) })
}) })
}) })
}) })*/
menuTreeRight.value?.setCheckedKeys([bind.value[1]])
maintenanceData.downNode = bind.value[1]
} }
nodemaintenanceInformation.value = true nodemaintenanceInformation.value = true
}) })

View File

@@ -694,7 +694,7 @@ const rules = ref({
reporter: [{ required: true, message: '请输入填报人', trigger: 'blur' }], reporter: [{ required: true, message: '请输入填报人', trigger: 'blur' }],
reportDate: [{ required: true, message: '请选择填报日期', trigger: 'change' }], reportDate: [{ required: true, message: '请选择填报日期', trigger: 'change' }],
orgId: [{ required: true, message: '请选择填报部门', trigger: 'change' }], orgId: [{ required: true, message: '请选择填报部门', trigger: 'change' }],
stationId: [{ required: true, message: '请选择所属电站', trigger: 'change' }], //stationId: [{ required: true, message: '请选择所属电站', trigger: 'change' }],
expectedProductionDate: [{ required: true, message: '请选择工程预期投产日期', trigger: 'change' }], expectedProductionDate: [{ required: true, message: '请选择工程预期投产日期', trigger: 'change' }],
userType: [{ required: true, message: '清选择用户性质', trigger: 'change' }], userType: [{ required: true, message: '清选择用户性质', trigger: 'change' }],
city: [{ required: true, message: '请选择所在地市', trigger: 'change' }], city: [{ required: true, message: '请选择所在地市', trigger: 'change' }],

View File

@@ -89,7 +89,7 @@ const tableStore = new TableStore({
} }
}, },
{ field: 'city', title: '所在地市', minWidth: 80 }, { field: 'city', title: '所在地市', minWidth: 80 },
{ field: 'substation', title: '厂站名称', minWidth: 100 }, /* { field: 'substation', title: '厂站名称', minWidth: 100 },*/
{ field: 'projectName', title: '项目名称', minWidth: 170 }, { field: 'projectName', title: '项目名称', minWidth: 170 },
{ {
field: 'userType', field: 'userType',
@@ -103,6 +103,7 @@ const tableStore = new TableStore({
// { field: 'responsibleDepartment', title: '归口管理部门', minWidth: 130 }, // { field: 'responsibleDepartment', title: '归口管理部门', minWidth: 130 },
{ field: 'ratePower', title: '装机容量(MW)', minWidth: 130 }, { field: 'ratePower', title: '装机容量(MW)', minWidth: 130 },
{ field: 'stationId', title: '所属电站', minWidth: 130 },
{ {
field: 'createBy', field: 'createBy',
title: '创建人', title: '创建人',

View File

@@ -12,7 +12,7 @@
</div> </div>
<el-collapse v-model="activeName" accordion> <el-collapse v-model="activeName" accordion>
<!-- <el-collapse-item title="典型电能质量干扰源" name="1"></el-collapse-item> --> <!-- <el-collapse-item title="典型电能质量干扰源" name="1"></el-collapse-item> -->
<el-collapse-item title="国家电网有限公司企业标准" name="2"> <el-collapse-item title="电网有限公司企业标准" name="2">
<!-- <el-empty description="暂无数据" class="custom-empty iframe" /> --> <!-- <el-empty description="暂无数据" class="custom-empty iframe" /> -->
<div :style="`overflow: auto;`" class="iframe"> <div :style="`overflow: auto;`" class="iframe">
<vue-office-docx v-if="urlKey.includes('.doc') || urlKey.includes('.docx')" :src="url" /> <vue-office-docx v-if="urlKey.includes('.doc') || urlKey.includes('.docx')" :src="url" />

View File

@@ -3,7 +3,7 @@
<!-- 案例库 --> <!-- 案例库 -->
<TableHeader ref="TableHeaderRef"> <TableHeader ref="TableHeaderRef">
<template #select> <template #select>
<el-form-item label="名称"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入搜索名称" maxlength="32" show-word-limit/> <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入搜索名称" maxlength="32" show-word-limit/>
</el-form-item> </el-form-item>

View File

@@ -2,32 +2,39 @@
<div class="default-main" :style="height"> <div class="default-main" :style="height">
<!-- 标准库 --> <!-- 标准库 -->
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes"> <splitpanes
style="height: 100%"
class="default-theme"
id="navigation-splitpanes"
@resize="onPaneResize"
@resized="onPaneResized"
>
<pane :size="size"> <pane :size="size">
<standardTree ref="treeRef" <standardTree ref="treeRef"
:default-expanded-keys="monitoringPoint.state.lineId ? [monitoringPoint.state.lineId] : []" :default-expanded-keys="monitoringPoint.state.lineId ? [monitoringPoint.state.lineId] : []"
:current-node-key="monitoringPoint.state.lineId" @node-click="handleNodeClick" :current-node-key="monitoringPoint.state.lineId" @node-click="handleNodeClick"
@init="handleNodeClick"></standardTree> @init="handleNodeClick"></standardTree>
</pane> </pane>
<pane style="background: #fff" :style="height"> <pane style="background: #fff" class="standard-pane">
<div class="pd10" style="display: flex; justify-content: end"> <div class="pd10 standard-pane__toolbar" style="display: flex; justify-content: end">
<el-button icon="el-icon-Plus" type="primary" @click="addUser" v-if="information">新增</el-button> <el-button icon="el-icon-Plus" type="primary" @click="addUser" v-if="information">新增</el-button>
<el-button icon="el-icon-Edit" type="primary" @click="editUser" v-if="information">修改</el-button> <el-button icon="el-icon-Edit" type="primary" @click="editUser" v-if="information">修改</el-button>
<el-button icon="el-icon-Delete" type="primary" @click="deleteEven" <el-button icon="el-icon-Delete" type="primary" @click="deleteEven"
v-if="information">删除</el-button> v-if="information">删除</el-button>
<el-button icon="el-icon-Download" type="primary" @click="download" v-if="flag">下载</el-button> <el-button icon="el-icon-Download" type="primary" @click="download" v-if="flag">下载</el-button>
</div> </div>
<el-empty v-if="url.length == 0" description="暂无数据" class="custom-empty" <el-empty v-if="url.length == 0" description="暂无数据" class="custom-empty standard-pane__content" />
:style="`height: calc(${height.height} - 60px);`" /> <div v-else class="standard-pane__content">
<div :style="`height: calc(${height.height} - 60px);overflow: auto;`" v-else> <div v-show="!isPaneResizing" class="standard-preview">
<vue-office-docx v-if="urlKey.includes('.doc') || urlKey.includes('.docx')" :src="url" /> <vue-office-docx v-if="urlKey.includes('.doc') || urlKey.includes('.docx')" :src="url" />
<vue-office-excel v-if="urlKey.includes('.xls') || urlKey.includes('.xlsx')" :src="url" <vue-office-excel v-if="urlKey.includes('.xls') || urlKey.includes('.xlsx')" :src="url"
:options="excelOptions" /> :options="excelOptions" />
<!-- <vue-office-pdf v-if="url.includes('.pdf')" :src="url"/> --> <!-- <vue-office-pdf v-if="url.includes('.pdf')" :src="url"/> -->
<iframe v-if="urlKey.includes('.pdf')" :src="url" style="width: 100%; height: 99%"></iframe> <iframe v-if="urlKey.includes('.pdf')" :src="url" style="width: 100%; height: 100%"></iframe>
<img v-if=" <img v-if="
urlKey.includes('.png') || urlKey.includes('.jpg') || urlKey.includes('.gif') || urlKey.includes('.bmp') urlKey.includes('.png') || urlKey.includes('.jpg') || urlKey.includes('.gif') || urlKey.includes('.bmp')
" :src="url" /> " :src="url" />
</div>
</div> </div>
</pane> </pane>
</splitpanes> </splitpanes>
@@ -70,7 +77,16 @@ const addTreeRef = ref()
const url = ref('') const url = ref('')
const dotList: any = ref({}) const dotList: any = ref({})
const flag: any = ref(false) const flag: any = ref(false)
const isPaneResizing = ref(false)
const information = adminInfo.roleCode.includes('information_info') const information = adminInfo.roleCode.includes('information_info')
const onPaneResize = () => {
isPaneResizing.value = true
}
const onPaneResized = () => {
requestAnimationFrame(() => {
isPaneResizing.value = false
})
}
onMounted(() => { onMounted(() => {
const dom = document.getElementById('navigation-splitpanes') const dom = document.getElementById('navigation-splitpanes')
if (dom) { if (dom) {
@@ -79,7 +95,7 @@ onMounted(() => {
}) })
const urlKey=ref('') const urlKey=ref('')
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei' const VITE_FLAG = false//import.meta.env.VITE_NAME == 'jibei'
const handleNodeClick = (data: any, node: any) => { const handleNodeClick = (data: any, node: any) => {
// console.log("🚀 ~ handleNodeClick ~ data:", data) // console.log("🚀 ~ handleNodeClick ~ data:", data)
dotList.value = data dotList.value = data
@@ -166,6 +182,36 @@ const download = () => {
background: #eaeef1; background: #eaeef1;
} }
:deep(.splitpanes__pane) {
overflow: hidden;
}
.standard-pane {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.standard-pane__toolbar {
flex-shrink: 0;
}
.standard-pane__content {
flex: 1;
min-height: 0;
overflow: auto;
}
.standard-preview {
height: 99%;
min-height: 99%;
}
:deep(.splitpanes--dragging) .standard-preview {
visibility: hidden;
}
.grid-content { .grid-content {
text-align: center; text-align: center;
} }

View File

@@ -3,7 +3,7 @@
<!-- 模版 --> <!-- 模版 -->
<TableHeader ref="TableHeaderRef" > <TableHeader ref="TableHeaderRef" >
<template #select> <template #select>
<el-form-item label="名称"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable <el-input v-model="tableStore.table.params.searchValue" clearable
placeholder="请输入搜索名称" maxlength="32" show-word-limit/> placeholder="请输入搜索名称" maxlength="32" show-word-limit/>
</el-form-item> </el-form-item>

View File

@@ -3,7 +3,7 @@
<div class="online_header"> <div class="online_header">
<TableHeader date-picker area ref="tableHeaderRef"> <TableHeader date-picker area ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -19,7 +19,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
multiple multiple
@@ -38,21 +38,21 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电网标识"> <el-form-item label="电网标识">
<el-select <el-select
v-model="tableStore.table.params.powerFlag" v-model="tableStore.table.params.powerFlag"
clearable clearable
style="width: 100%" style="width: 100%"
placeholder="请选择电网标识" placeholder="请选择电网标识"
> >
<el-option <el-option
v-for="item in powerFlagList" v-for="item in powerFlagList"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.algoDescribe" :value="item.algoDescribe"
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -88,6 +88,14 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据">
<el-input
v-model.trim="tableStore.table.params.searchValue"
clearable
style="width: 200px"
placeholder="请输入关键字筛选"
/>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -96,7 +104,7 @@
<el-tab-pane :name="0" :lazy="true" label="稳态指标符合性占比表格"> <el-tab-pane :name="0" :lazy="true" label="稳态指标符合性占比表格">
<Table <Table
ref="tableRef" ref="tableRef"
:tree-config="{ transform: true, parentField: 'uPid', rowField: 'uId' }" :tree-config="{ transform: true, parentField: 'uPid', rowField: 'uId' }"
:scroll-y="{ enabled: true }" :scroll-y="{ enabled: true }"
v-if="activeName == 0" v-if="activeName == 0"
/> />
@@ -117,6 +125,7 @@ import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import charts from './components/charts.vue' import charts from './components/charts.vue'
import { filterTree } from '@/utils/tree'
defineOptions({ defineOptions({
name: 'harmonic-boot/area/SteadyState' name: 'harmonic-boot/area/SteadyState'
}) })
@@ -214,7 +223,12 @@ const tableStore = new TableStore({
], ],
loadCallback: () => { loadCallback: () => {
tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000) tableStore.table.data = tree2List(
filterTree(tableStore.table.data, node => {
return node.name.includes(tableStore.table.params.searchValue)
}),
Math.random() * 1000
)
tableStore.table.column[0].title = tableStore.table.params.statisticalType.name tableStore.table.column[0].title = tableStore.table.params.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
@@ -230,6 +244,7 @@ tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
tableStore.table.params.powerFlag = 2 tableStore.table.params.powerFlag = 2
tableStore.table.params.serverName = 'harmonicBoot' tableStore.table.params.serverName = 'harmonicBoot'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => { const tree2List = (list: any, id?: string) => {
//存储结果的数组 //存储结果的数组

View File

@@ -4,9 +4,15 @@
<TableHeader datePicker area showExport> <TableHeader datePicker area showExport>
<template #select> <template #select>
<el-form-item label="筛选数据"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" placeholder="输入关键字筛选" clearable maxlength="32" show-word-limit/> <el-input
v-model="tableStore.table.params.searchValue"
placeholder="输入关键字筛选"
clearable
maxlength="32"
show-word-limit
/>
</el-form-item> </el-form-item>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
value-key="id" value-key="id"
@@ -21,7 +27,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
multiple multiple
@@ -38,7 +44,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -55,7 +61,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
multiple multiple
@@ -127,7 +133,7 @@ const tableStore = new TableStore({
{ field: 'lineName', title: '监测点名称', minWidth: '180' }, { field: 'lineName', title: '监测点名称', minWidth: '180' },
{ field: 'gdName', title: '供电公司', minWidth: '120' }, { field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '150' }, { field: 'subName', title: '变电站', minWidth: '150' },
{ field: 'ip', title: '网络参数' ,width:'120px' }, { field: 'ip', title: '网络参数', width: '120px' },
{ field: 'scale', title: '电压等级', minWidth: '110' }, { field: 'scale', title: '电压等级', minWidth: '110' },
{ {
field: 'advanceType', field: 'advanceType',
@@ -137,7 +143,7 @@ const tableStore = new TableStore({
return row.cellValue || '其他' return row.cellValue || '其他'
} }
}, },
{ {
field: 'eventType', field: 'eventType',
title: '触发类型', title: '触发类型',
minWidth: '120', minWidth: '120',
@@ -180,7 +186,8 @@ const tableStore = new TableStore({
{ field: 'duration', title: '持续时间(s)', minWidth: '100' }, { field: 'duration', title: '持续时间(s)', minWidth: '100' },
{ {
title: '操作',fixed: 'right', title: '操作',
fixed: 'right',
width: '120', width: '120',
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
@@ -278,6 +285,7 @@ const download = () => {
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
}) })
} }
</script> </script>

View File

@@ -1,16 +1,17 @@
<template> <template>
<div class="default-main online"> <div class="default-main online">
<div class="online_header"> <div class="online_header">
<TableHeader date-picker ref="tableHeaderRef"> <TableHeader date-picker ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select v-model="formData.statisticalType" placeholder="请选择统计类型" value-key="id" <el-select v-model="formData.statisticalType" placeholder="请选择统计类型" value-key="id"
style="width: 100%"> style="width: 100%">
<el-option v-for="item in classificationData" :key="item.id" :label="item.name" <el-option v-for="item in classificationData" :key="item.id" :label="item.name"
:value="item"></el-option> :value="item"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="区域选择:"> <el-form-item label="区域选择">
<!-- <el-select ref="select1" v-model="deptName" placeholder="请选择所属部门区域" style="width: 100%"> <!-- <el-select ref="select1" v-model="deptName" placeholder="请选择所属部门区域" style="width: 100%">
<el-option :value="formData.deptIndex" style="height: auto"> --> <el-option :value="formData.deptIndex" style="height: auto"> -->
<!-- {{ formData.deptIndex }} --> <!-- {{ formData.deptIndex }} -->
@@ -33,29 +34,38 @@
<!-- </el-option> <!-- </el-option>
</el-select> --> </el-select> -->
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select v-model="formData.scale" multiple collapse-tags clearable placeholder="请选择电压等级" <el-select v-model="formData.scale" multiple collapse-tags clearable placeholder="请选择电压等级"
style="width: 100%" value-key="id"> style="width: 100%" value-key="id">
<el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" <el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name"
:value="item"></el-option> :value="item"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="formData.manufacturer" multiple collapse-tags clearable <el-select v-model="formData.manufacturer" multiple collapse-tags clearable
placeholder="请选择终端厂家" style="width: 100%" value-key="id"> placeholder="请选择终端厂家" style="width: 100%" value-key="id">
<el-option v-for="(item, index) in terminaloption" :key="index" :label="item.name" <el-option v-for="(item, index) in terminaloption" :key="index" :label="item.name"
:value="item"></el-option> :value="item"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select v-model="formData.loadType" multiple collapse-tags clearable placeholder="请选择干扰源类型" <el-select v-model="formData.loadType" multiple collapse-tags clearable placeholder="请选择干扰源类型"
style="width: 100%" value-key="id"> style="width: 100%" value-key="id">
<el-option v-for="(item, index) in interfereoption" :key="index" :label="item.name" <el-option v-for="(item, index) in interfereoption" :key="index" :label="item.name"
:value="item"></el-option> :value="item"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="关键字筛选:"> <el-form-item label="通讯状态">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字"></el-input> <el-select v-model="tableStore.table.params.comFlagStatus" clearable placeholder="请选择通讯状态"
style="width: 100%">
<el-option label="正常" value="1" />
<el-option label="中断" value="0" />
</el-select>
</el-form-item>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable
placeholder="请输入关键字"></el-input>
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
@@ -77,9 +87,10 @@
</div> </div>
<el-dialog v-model="timePopUp" draggable title="补招" width="500"> <el-dialog v-model="timePopUp" draggable title="补招" width="500">
补招时间: 补招时间:
<el-date-picker v-model="timeData" type="datetimerange" format="YYYY-MM-DD HH:mm:00" <el-date-picker v-model="timeData" type="datetimerange" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:00" range-separator="" date-format="YYYY-MM-DD" time-format="HH:mm:00" value-format="YYYY-MM-DD HH:mm:ss" range-separator="" date-format="YYYY-MM-DD" time-format="HH:mm:ss"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 400px" :disabledDate="disabledDate" /> start-placeholder="开始日期" end-placeholder="结束日期" style="width: 400px" :disabledDate="disabledDate"
:default-time="defaultTimeRange" />
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="timePopUp = false">取消</el-button> <el-button @click="timePopUp = false">取消</el-button>
@@ -139,6 +150,10 @@ const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Ty
const treeData = ref([]) const treeData = ref([])
const idArr = ref([]) const idArr = ref([])
const timeData = ref([]) const timeData = ref([])
const defaultTimeRange: [Date, Date] = [
new Date(2000, 0, 1, 0, 0, 0),
new Date(2000, 0, 1, 23, 59, 59)
]
const logList: any = ref([]) const logList: any = ref([])
const activeName = ref(0) const activeName = ref(0)
const getTreeData = async () => { const getTreeData = async () => {
@@ -198,7 +213,7 @@ const tableStore = new TableStore({
{ {
title: '网络参数', title: '网络参数',
field: 'ip', field: 'ip',
align: 'center',width:'120px', align: 'center', width: '120px',
formatter: function (row) { formatter: function (row) {
return row.cellValue ? row.cellValue : '/' return row.cellValue ? row.cellValue : '/'
} }
@@ -288,7 +303,7 @@ const tableStore = new TableStore({
// tableStore.table.params.searchEndTime = tableHeaderRef.value.datePickerRef.timeValue[1] // tableStore.table.params.searchEndTime = tableHeaderRef.value.datePickerRef.timeValue[1]
}, },
loadCallback: () => { loadCallback: () => {
tableStore.table.data = tree2List(filterTreeByKeyword( tableStore.table.data,tableStore.table.params.searchValue), Math.random() * 1000) tableStore.table.data = tree2List(filterTreeByKeyword(tableStore.table.data, tableStore.table.params.searchValue), Math.random() * 1000)
tableStore.table.column[0].title = formData.value.statisticalType.name tableStore.table.column[0].title = formData.value.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
@@ -313,6 +328,7 @@ tableStore.table.params.statisticalType = []
tableStore.table.params.scale = [] tableStore.table.params.scale = []
tableStore.table.params.manufacturer = [] tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
tableStore.table.params.comFlagStatus = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => { const tree2List = (list: any, id?: string) => {
//存储结果的数组 //存储结果的数组
@@ -353,65 +369,65 @@ const tree2List = (list: any, id?: string) => {
* @returns {Array} 筛选后的嵌套树形数据,保持原层级 * @returns {Array} 筛选后的嵌套树形数据,保持原层级
*/ */
function filterTreeByKeyword(treeData, keyword) { function filterTreeByKeyword(treeData, keyword) {
// 关键词为空,直接返回原树(深拷贝,避免修改原数据) // 关键词为空,直接返回原树(深拷贝,避免修改原数据)
if (!keyword || keyword.trim() === '') { if (!keyword || keyword.trim() === '') {
return JSON.parse(JSON.stringify(treeData)); return JSON.parse(JSON.stringify(treeData));
} }
const targetKey = keyword.trim(); const targetKey = keyword.trim();
// 存储需要保留的节点ID匹配节点+所有上级+所有下级) // 存储需要保留的节点ID匹配节点+所有上级+所有下级)
const keepIdSet = new Set(); const keepIdSet = new Set();
// 第一步递归遍历树形标记所有需要保留的节点ID // 第一步递归遍历树形标记所有需要保留的节点ID
const markKeepNodes = (node, parentNodes = []) => { const markKeepNodes = (node, parentNodes = []) => {
// 1. 若当前节点名称包含关键词,标记自身+所有上级+所有下级 // 1. 若当前节点名称包含关键词,标记自身+所有上级+所有下级
const isMatch = node.name && node.name.includes(targetKey); const isMatch = node.name && node.name.includes(targetKey);
if (isMatch) { if (isMatch) {
// 标记自身 // 标记自身
keepIdSet.add(node.id); keepIdSet.add(node.id);
// 标记所有上级父节点 // 标记所有上级父节点
parentNodes.forEach(pNode => keepIdSet.add(pNode.id)); parentNodes.forEach(pNode => keepIdSet.add(pNode.id));
// 标记所有下级子节点(递归) // 标记所有下级子节点(递归)
const markChildren = (childNode) => { const markChildren = (childNode) => {
keepIdSet.add(childNode.id); keepIdSet.add(childNode.id);
if (childNode.children && childNode.children.length) { if (childNode.children && childNode.children.length) {
childNode.children.forEach(markChildren); childNode.children.forEach(markChildren);
}
};
if (node.children && node.children.length) {
node.children.forEach(markChildren);
}
} }
};
if (node.children && node.children.length) {
node.children.forEach(markChildren);
}
}
// 2. 递归遍历子节点传递当前节点的上级链parentNodes + 当前节点) // 2. 递归遍历子节点传递当前节点的上级链parentNodes + 当前节点)
if (node.children && node.children.length) { if (node.children && node.children.length) {
node.children.forEach(child => markKeepNodes(child, [...parentNodes, node])); node.children.forEach(child => markKeepNodes(child, [...parentNodes, node]));
} }
}; };
// 遍历根节点,开始标记 // 遍历根节点,开始标记
treeData.forEach(rootNode => markKeepNodes(rootNode)); treeData.forEach(rootNode => markKeepNodes(rootNode));
// 第二步:递归重构树形,只保留标记过的节点,保持层级 // 第二步:递归重构树形,只保留标记过的节点,保持层级
const rebuildTree = (node) => { const rebuildTree = (node) => {
// 若当前节点无需保留直接返回null // 若当前节点无需保留直接返回null
if (!keepIdSet.has(node.id)) { if (!keepIdSet.has(node.id)) {
return null; return null;
} }
// 深拷贝当前节点,避免修改原数据 // 深拷贝当前节点,避免修改原数据
const newNode = { ...node }; const newNode = { ...node };
// 递归处理子节点,过滤掉无需保留的,只保留有效子节点 // 递归处理子节点,过滤掉无需保留的,只保留有效子节点
if (newNode.children && newNode.children.length) { if (newNode.children && newNode.children.length) {
const newChildren = newNode.children.map(child => rebuildTree(child)).filter(Boolean); const newChildren = newNode.children.map(child => rebuildTree(child)).filter(Boolean);
newNode.children = newChildren; newNode.children = newChildren;
} else { } else {
newNode.children = []; newNode.children = [];
} }
return newNode; return newNode;
}; };
// 重构根节点过滤掉null的根节点 // 重构根节点过滤掉null的根节点
const filteredTree = treeData.map(rootNode => rebuildTree(rootNode)).filter(Boolean); const filteredTree = treeData.map(rootNode => rebuildTree(rootNode)).filter(Boolean);
return filteredTree; return filteredTree;
} }
@@ -468,24 +484,29 @@ const makeUpSubmit = () => {
reCallStartTime: timeData.value[0] reCallStartTime: timeData.value[0]
} }
socket(form) setTimeout(() => {
timePopUp.value = false socket(form)
logPopUp.value = true timePopUp.value = false
logPopUp.value = true
}, 500)
} }
const socket = async (form: any) => { const socket = async (form: any) => {
const url = (localStorage.getItem('WebSocketUrl2') || 'ws://192.168.1.67:10405/api/recell/') const url = (localStorage.getItem('WebSocketUrl2') || 'null')//'ws://192.168.1.68:10405/api/recell/')
logList.value = [] logList.value = []
await dataSocket.socketServe.connect(`${url}${adminInfo.id}`) await dataSocket.socketServe.connect(`${url}${adminInfo.id}`)
await dataSocket.socketServe.send(form) setTimeout(() => {
dataSocket.socketServe.send(form)
}, 500)
logList.value.push({ logList.value.push({
type: '', type: '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'), time: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'),
name: '开始补召,请稍等...', name: '开始补召,请稍等...',
}) })
await dataSocket.socketServe.registerCallBack('message', (res: any) => { await dataSocket.socketServe.registerCallBack('message', (res: any) => {
if (res.code == undefined) return
logList.value.push({ logList.value.push({
type: res.code == 500 ? 'error' : '', type: res.code == 500 ? 'error' : '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'), time: formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss'),
name: res.message name: res.message
}) })

View File

@@ -3,7 +3,7 @@
<div class="online_header"> <div class="online_header">
<TableHeader date-picker area ref="tableHeaderRef"> <TableHeader date-picker area ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -19,7 +19,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
multiple multiple
@@ -37,7 +37,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -55,7 +55,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
multiple multiple
@@ -83,6 +83,14 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据">
<el-input
v-model.trim="tableStore.table.params.searchValue"
clearable
style="width: 200px"
placeholder="请输入关键字筛选"
/>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -112,6 +120,7 @@ import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import charts from './components/charts.vue' import charts from './components/charts.vue'
import { filterTree } from '@/utils/tree'
defineOptions({ defineOptions({
name: 'harmonic-boot/area/harmonicDistortionRate' name: 'harmonic-boot/area/harmonicDistortionRate'
}) })
@@ -200,7 +209,13 @@ const tableStore = new TableStore({
], ],
loadCallback: () => { loadCallback: () => {
tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000) tableStore.table.data = tree2List(
filterTree(tableStore.table.data, node => {
// 筛选条件name 包含关键词
return node.name.includes(tableStore.table.params.searchValue)
}),
Math.random() * 1000
)
tableStore.table.column[0].title = tableStore.table.params.statisticalType.name tableStore.table.column[0].title = tableStore.table.params.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
setTimeout(() => { setTimeout(() => {
@@ -215,6 +230,7 @@ tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
tableStore.table.params.powerFlag = sign[0]?.algoDescribe || 0 tableStore.table.params.powerFlag = sign[0]?.algoDescribe || 0
tableStore.table.params.serverName = 'harmonicBoot' tableStore.table.params.serverName = 'harmonicBoot'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => { const tree2List = (list: any, id?: string) => {
//存储结果的数组 //存储结果的数组

View File

@@ -2,7 +2,7 @@
<div class="default-main"> <div class="default-main">
<TableHeader date-picker area showExport> <TableHeader date-picker area showExport>
<template #select> <template #select>
<el-form-item label="统计类型:" v-if="false"> <el-form-item label="统计类型" v-if="false">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -18,7 +18,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:" v-if="false"> <el-form-item label="电压等级" v-if="false">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
multiple multiple
@@ -36,7 +36,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:" v-if="false"> <el-form-item label="终端厂家" v-if="false">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -55,7 +55,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
multiple multiple

View File

@@ -3,7 +3,7 @@
<div class="online_header"> <div class="online_header">
<TableHeader date-picker ref="tableHeaderRef"> <TableHeader date-picker ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="formData.statisticalType" v-model="formData.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -18,7 +18,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="区域选择:"> <el-form-item label="区域选择">
<!-- <el-select ref="select1" v-model="deptName" placeholder="请选择所属部门区域" style="width: 100%"> <!-- <el-select ref="select1" v-model="deptName" placeholder="请选择所属部门区域" style="width: 100%">
<el-option :value="formData.deptIndex" style="height: auto"> --> <el-option :value="formData.deptIndex" style="height: auto"> -->
<!-- {{ formData.deptIndex }} --> <!-- {{ formData.deptIndex }} -->
@@ -48,7 +48,7 @@
<!-- </el-option> <!-- </el-option>
</el-select> --> </el-select> -->
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="formData.scale" v-model="formData.scale"
multiple multiple
@@ -66,7 +66,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="formData.manufacturer" v-model="formData.manufacturer"
multiple multiple
@@ -84,7 +84,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="formData.loadType" v-model="formData.loadType"
multiple multiple
@@ -102,7 +102,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="关键字筛选:"> <el-form-item label="筛选数据">
<el-input <el-input
v-model="tableStore.table.params.searchValue" v-model="tableStore.table.params.searchValue"
clearable clearable

View File

@@ -11,7 +11,7 @@
margin-top: 2px; margin-top: 2px;
" "
></el-tag> ></el-tag>
<span style="color: #A52a2a; font-weight: 400; float: left">&nbsp&nbsp在线<60% &nbsp&nbsp</span> <span style="color: #A52a2a; font-weight: 400; float: left">&nbsp&nbsp合格<60% &nbsp&nbsp</span>
<el-tag <el-tag
size="small" size="small"
style=" style="
@@ -23,7 +23,7 @@
margin-top: 2px; margin-top: 2px;
" "
></el-tag> ></el-tag>
<span style="color: #ffcc33; font-weight: 400; float: left">&nbsp&nbsp60%在线<90% &nbsp&nbsp</span> <span style="color: #ffcc33; font-weight: 400; float: left">&nbsp&nbsp60%合格<90% &nbsp&nbsp</span>
<el-tag <el-tag
style=" style="
background: #339966; background: #339966;
@@ -34,7 +34,7 @@
margin-top: 2px; margin-top: 2px;
" "
></el-tag> ></el-tag>
<span style="color: #339966; font-weight: 400; float: left">&nbsp&nbsp在线90%</span> <span style="color: #339966; font-weight: 400; float: left">&nbsp&nbsp合格90%</span>
</div> </div>
<my-echart <my-echart
v-loading="loading" v-loading="loading"

View File

@@ -3,7 +3,7 @@
<div class="online_header"> <div class="online_header">
<TableHeader date-picker area ref="tableHeaderRef"> <TableHeader date-picker area ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -19,7 +19,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
multiple multiple
@@ -37,7 +37,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -55,7 +55,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
multiple multiple
@@ -83,6 +83,14 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据">
<el-input
v-model.trim="tableStore.table.params.searchValue"
clearable
style="width: 200px"
placeholder="请输入关键字筛选"
/>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -113,6 +121,7 @@ import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import charts from './components/charts.vue' import charts from './components/charts.vue'
import { filterTree } from '@/utils/tree'
defineOptions({ defineOptions({
name: 'harmonic-boot/area/qualifiedRate' name: 'harmonic-boot/area/qualifiedRate'
}) })
@@ -272,7 +281,13 @@ const tableStore = new TableStore({
], ],
loadCallback: () => { loadCallback: () => {
tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000) tableStore.table.data = tree2List(
filterTree(tableStore.table.data, node => {
// 筛选条件name 包含关键词
return node.name.includes(tableStore.table.params.searchValue)
}),
Math.random() * 1000
)
tableStore.table.column[0].title = tableStore.table.params.statisticalType.name tableStore.table.column[0].title = tableStore.table.params.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
@@ -288,6 +303,7 @@ tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
tableStore.table.params.serverName = 'harmonicBoot' tableStore.table.params.serverName = 'harmonicBoot'
tableStore.table.params.powerFlag = sign[0]?.algoDescribe || 0 tableStore.table.params.powerFlag = sign[0]?.algoDescribe || 0
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
// const tree2List = (list: any, pid?: string) => { // const tree2List = (list: any, pid?: string) => {
// //存储结果的数组 // //存储结果的数组

View File

@@ -3,7 +3,7 @@
<div class="online_header"> <div class="online_header">
<TableHeader date-picker area ref="tableHeaderRef"> <TableHeader date-picker area ref="tableHeaderRef">
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -19,7 +19,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
multiple multiple
@@ -37,6 +37,14 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据">
<el-input
v-model.trim="tableStore.table.params.searchValue"
clearable
style="width: 200px"
placeholder="请输入关键字筛选"
/>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
</div> </div>
@@ -88,7 +96,7 @@
<span style="color: #ffcc33">检修状态</span> <span style="color: #ffcc33">检修状态</span>
</li> </li>
<li> <li>
<p style="background: #A52a2a"> <p style="background: #a52a2a">
<svg <svg
t="1722910570852" t="1722910570852"
class="icon" class="icon"
@@ -106,7 +114,7 @@
></path> ></path>
</svg> </svg>
</p> </p>
<span style="color: #A52a2a">停运状态</span> <span style="color: #a52a2a">停运状态</span>
</li> </li>
</ul> </ul>
</div> </div>
@@ -133,6 +141,7 @@ import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import charts from './components/charts.vue' import charts from './components/charts.vue'
import { filterTree } from '@/utils/tree'
defineOptions({ defineOptions({
name: 'harmonic-boot/area/terminalonlinerate' name: 'harmonic-boot/area/terminalonlinerate'
}) })
@@ -279,7 +288,12 @@ const tableStore = new TableStore({
// // tableStore.table.params.searchEndTime = tableHeaderRef.value.datePickerRef.timeValue[1] // // tableStore.table.params.searchEndTime = tableHeaderRef.value.datePickerRef.timeValue[1]
// }, // },
loadCallback: () => { loadCallback: () => {
tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000) tableStore.table.data = tree2List(
filterTree(tableStore.table.data, node => {
return node.name.includes(tableStore.table.params.searchValue)
}),
Math.random() * 1000
)
tableStore.table.column[0].title = formData.value.statisticalType.name tableStore.table.column[0].title = formData.value.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params) chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
@@ -294,7 +308,7 @@ tableStore.table.params.scale = voltageleveloption
tableStore.table.params.manufacturer = terminaloption tableStore.table.params.manufacturer = terminaloption
tableStore.table.params.loadType = interfereoption tableStore.table.params.loadType = interfereoption
tableStore.table.params.serverName = 'harmonicBoot' tableStore.table.params.serverName = 'harmonicBoot'
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => { const tree2List = (list: any, id?: string) => {

View File

@@ -9,21 +9,21 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> --> </el-form-item> -->
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable
placeholder="请选择电压等级" value-key="id"> placeholder="请选择电压等级" value-key="id">
<el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags <el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags
clearable placeholder="请选择终端厂家" value-key="id"> clearable placeholder="请选择终端厂家" value-key="id">
<el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable
placeholder="请选择干扰源类型" value-key="id"> placeholder="请选择干扰源类型" value-key="id">
<el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item">

View File

@@ -7,7 +7,7 @@
</div> </div>
<TableHeader :showReset="false" ref="TableHeaderRef"> <TableHeader :showReset="false" ref="TableHeaderRef">
<template #select> <template #select>
<el-form-item label="关键字"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" maxlength="32" show-word-limit/> <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" maxlength="32" show-word-limit/>
</el-form-item> </el-form-item>
</template> </template>

View File

@@ -2,7 +2,7 @@
<el-dialog v-model="dialogVisible" draggable title="完整性不足详情" width="1000"> <el-dialog v-model="dialogVisible" draggable title="完整性不足详情" width="1000">
<TableHeader :showReset="false" ref="TableHeaderRef"> <TableHeader :showReset="false" ref="TableHeaderRef">
<template #select> <template #select>
<el-form-item label="关键字"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" /> <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" />
</el-form-item> </el-form-item>
</template> </template>

View File

@@ -3,7 +3,7 @@
<!-- 模版 --> <!-- 模版 -->
<TableHeader datePicker showExport :showReset="false" ref="TableHeaderRef"> <TableHeader datePicker showExport :showReset="false" ref="TableHeaderRef">
<template #select> <template #select>
<!-- <el-form-item label="关键字"> <!-- <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" /> <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入关键字" />
</el-form-item> --> </el-form-item> -->
</template> </template>

View File

@@ -9,26 +9,31 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> --> </el-form-item> -->
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable
placeholder="请选择电压等级" value-key="id"> placeholder="请选择电压等级" value-key="id">
<el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags <el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags
clearable placeholder="请选择终端厂家" value-key="id"> clearable placeholder="请选择终端厂家" value-key="id">
<el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable
placeholder="请选择干扰源类型" value-key="id"> placeholder="请选择干扰源类型" value-key="id">
<el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item>
<el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable style="width: 240px;"
placeholder="请输入变电站、监测点、监测对象" />
</el-form-item> </el-form-item>
</template> </template>
@@ -68,14 +73,14 @@ const tableStore = new TableStore({
{ field: 'lineScale', title: '电压等级', minWidth: "120px", }, { field: 'lineScale', title: '电压等级', minWidth: "120px", },
{ field: 'lineName', title: '监测点名称', minWidth: "150px", }, { field: 'lineName', title: '监测点名称', minWidth: "150px", },
{ field: 'loadType', title: '干扰源类型', minWidth: "150px", }, { field: 'loadType', title: '干扰源类型', minWidth: "150px", },
{ field: 'lineObjectName', title: '监测点对象名称', minWidth: "150px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, { field: 'lineObjectName', title: '监测点对象名称', minWidth: "180px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } },
{ field: 'overDay', title: '超标天数', minWidth: "80px", }, { field: 'overDay', title: '超标天数', minWidth: "80px", },
{ field: 'freqOverDay', title: '频率偏差超标天数', minWidth: "100px", }, { field: 'freqOverDay', title: '频率偏差', minWidth: "100px", },
{ field: 'volDevOverDay', title: '电压偏差超标天数', minWidth: "100px", }, { field: 'volDevOverDay', title: '电压偏差', minWidth: "100px", },
{ field: 'volDisOverDay', title: '电压总畸变率超标天数', minWidth: "100px", }, { field: 'volDisOverDay', title: '电压总畸变率', minWidth: "100px", },
{ field: 'volContainOverDay', title: '谐波电压含有率超标天数', minWidth: "110px", }, { field: 'volContainOverDay', title: '谐波电压含有率', minWidth: "100px", },
{ field: 'harmVolOverDay', title: '谐波电压超标天数', minWidth: "100px", }, { field: 'harmVolOverDay', title: '谐波电压', minWidth: "100px", },
{ field: 'harmCurOverDay', title: '谐波电流超标天数', minWidth: "100px", }, { field: 'harmCurOverDay', title: '谐波电流', minWidth: "100px", },
{ {
title: '各次谐波电压含有率超标天数', title: '各次谐波电压含有率超标天数',
children: [ children: [
@@ -104,10 +109,11 @@ const tableStore = new TableStore({
], ],
}, },
{ field: 'threeUnbalance', title: '三相电压不平衡度超标天数', minWidth: "110px", }, { field: 'intHarmOverDay', title: '间谐波电压含有率', minWidth: "100px", },
{ field: 'negativeOverDay', title: '负序电流超标天数', minWidth: "100px", }, { field: 'threeUnbalance', title: '三相电压不平衡度', minWidth: "100px", },
{ field: 'flickerOverDay', title: '闪变超标天数', minWidth: "100px", }, { field: 'negativeOverDay', title: '负序电流', minWidth: "100px", },
{ field: 'monitorNumber', title: '监测点编号', minWidth: "180px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } }, { field: 'flickerOverDay', title: '闪变', minWidth: "100px", },
{ field: 'monitorNumber', title: '监测点编号', minWidth: "100px", formatter: (row: any) => { return row.cellValue == null ? '/' : row.cellValue } },
@@ -125,6 +131,7 @@ tableStore.table.params.monitorFlag = 2
tableStore.table.params.scale = [] tableStore.table.params.scale = []
tableStore.table.params.manufacturer = [] tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
tableStore.table.params.searchValue = ''
const wp = ref({}) const wp = ref({})
provide('tableStore', tableStore) provide('tableStore', tableStore)

View File

@@ -2,7 +2,7 @@
<div class="default-main"> <div class="default-main">
<TableHeader datePicker area showExport> <TableHeader datePicker area showExport>
<template #select> <template #select>
<el-form-item label="统计类型:"> <el-form-item label="统计类型">
<el-select <el-select
v-model="tableStore.table.params.statisticalType" v-model="tableStore.table.params.statisticalType"
placeholder="请选择统计类型" placeholder="请选择统计类型"
@@ -16,7 +16,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
filterable filterable
@@ -34,7 +34,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
filterable filterable
@@ -52,7 +52,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
filterable filterable

View File

@@ -12,6 +12,7 @@
</el-form-item> </el-form-item>
</template> </template>
<template v-slot:operation> <template v-slot:operation>
<el-button type="primary" icon="el-icon-Search" @click="Search">查询</el-button>
<el-button type="primary" icon="el-icon-Download" @click="exportTemplate">导出</el-button> <el-button type="primary" icon="el-icon-Download" @click="exportTemplate">导出</el-button>
</template> </template>
</TableHeader> </TableHeader>
@@ -51,6 +52,7 @@
:interval="datePickerRef?.interval" :interval="datePickerRef?.interval"
:w="item.w" :w="item.w"
:h="item.h" :h="item.h"
:searchKey="searchKey"
/> />
<div v-else class="pd10">组件加载失败...</div> <div v-else class="pd10">组件加载失败...</div>
</div> </div>
@@ -114,6 +116,7 @@ const layout: any = ref([
// path: '/src/views/pqs/runManage/assessment/components/uese/index.vue' // path: '/src/views/pqs/runManage/assessment/components/uese/index.vue'
// }, // },
]) ])
const searchKey = ref(0)
const layoutCopy: any = ref([]) const layoutCopy: any = ref([])
const flag = ref(true) const flag = ref(true)
// 组件映射 // 组件映射
@@ -293,6 +296,10 @@ const fetchLayoutData = async () => {
// 可以添加错误提示逻辑 // 可以添加错误提示逻辑
} }
} }
const Search = () => {
searchKey.value += 1
}
// 导出 // 导出
const exportTemplate = () => { const exportTemplate = () => {
console.log(123) console.log(123)

View File

@@ -13,7 +13,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输入监测点名称" /> <el-input v-model="tableStore.table.params.searchValue" clearable style="width: 240px;" placeholder="请输入变电站、监测点、监测对象" />
</el-form-item> </el-form-item>
</template> </template>
@@ -162,14 +162,15 @@
<vxe-column field="company" title="供电公司" minWidth="110px"></vxe-column> <vxe-column field="company" title="供电公司" minWidth="110px"></vxe-column>
<vxe-column field="subStation" title="变电站" minWidth="110px"></vxe-column> <vxe-column field="subStation" title="变电站" minWidth="110px"></vxe-column>
<vxe-column field="manufacturer" title="终端厂家" minWidth="110px"></vxe-column> <vxe-column field="manufacturer" title="终端厂家" minWidth="110px"></vxe-column>
<vxe-column field="deviceName" title="终端名称" minWidth="110px"></vxe-column> <vxe-column field="deviceName" title="终端名称" minWidth="130px"></vxe-column>
<vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column> <vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column>
<vxe-column <vxe-column
field="lineName" field="lineName"
title="监测点名称" title="监测点名称"
:formatter="formatter" :formatter="formatter"
minWidth="110px" minWidth="130px"
></vxe-column> ></vxe-column>
<vxe-column v-if="VITE_FLAG" field="objName" title="监测对象" minWidth="130px"></vxe-column>
<vxe-column field="runFlag" title="运行状态" width="90px"> <vxe-column field="runFlag" title="运行状态" width="90px">
<template #default="{ row }"> <template #default="{ row }">
<el-tag <el-tag
@@ -222,6 +223,7 @@ defineOptions({
name: 'harmonic-boot/harmonic/getIntegrityData' name: 'harmonic-boot/harmonic/getIntegrityData'
}) })
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const VITE_FLAG = import.meta.env.VITE_NAME != 'jibei'
const route = useRoute() const route = useRoute()
const dictData = useDictData() const dictData = useDictData()
//字典获取监督对象类型 //字典获取监督对象类型
@@ -275,7 +277,7 @@ const tableStore = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0 return k.citTotalNum != 0
} else { } else {
return k.citName != '上送国网' && k.citName != '上送国网' return !k.citName.includes('上送')
} }
}) })
// 合并子集数据 并去重 // 合并子集数据 并去重

View File

@@ -160,8 +160,9 @@
<vxe-column field="company" title="供电公司" minWidth="110px"></vxe-column> <vxe-column field="company" title="供电公司" minWidth="110px"></vxe-column>
<vxe-column field="subStation" title="变电站" minWidth="110px"></vxe-column> <vxe-column field="subStation" title="变电站" minWidth="110px"></vxe-column>
<vxe-column field="manufacturer" title="终端厂家" minWidth="110px"></vxe-column> <vxe-column field="manufacturer" title="终端厂家" minWidth="110px"></vxe-column>
<vxe-column field="deviceName" title="终端名称" minWidth="110px"></vxe-column> <vxe-column field="deviceName" title="终端名称" minWidth="130px"></vxe-column>
<vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column> <vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column>
<vxe-column field="runFlag" title="运行状态" width="90px"> <vxe-column field="runFlag" title="运行状态" width="90px">
<template #default="{ row }"> <template #default="{ row }">
<el-tag <el-tag
@@ -214,6 +215,7 @@ defineOptions({
name: 'harmonic-boot/harmonic/getIntegrityData' name: 'harmonic-boot/harmonic/getIntegrityData'
}) })
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const VITE_FLAG = import.meta.env.VITE_NAME != 'jibei'
const route = useRoute() const route = useRoute()
const dictData = useDictData() const dictData = useDictData()
//字典获取监督对象类型 //字典获取监督对象类型
@@ -268,7 +270,7 @@ const tableStore = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.citTotalNum != 0 return k.citTotalNum != 0
} else { } else {
return k.citName != '上送国网' && k.citName != '上送国网' return !k.citName.includes('上送')
} }
}) })
// console.log(123, tableStore.table.params.statisticalType.name) // console.log(123, tableStore.table.params.statisticalType.name)

View File

@@ -29,7 +29,7 @@
<el-tab-pane label="稳态指标合格率" name="2" lazy v-if="!isReload"> <el-tab-pane label="稳态指标合格率" name="2" lazy v-if="!isReload">
<Wentaizhibiaohegelv v-if="activeName == '2'" /> <Wentaizhibiaohegelv v-if="activeName == '2'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="稳态数据分析" name="3" lazy v-if="!isReload"> <el-tab-pane label="稳态数据分析" name="3" lazy v-if="!isReload && !IS_LNQR">
<Wentaishujufenxi v-if="activeName == '3'" /> <Wentaishujufenxi v-if="activeName == '3'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="谐波频谱" name="4" lazy v-if="!isReload"> <el-tab-pane label="谐波频谱" name="4" lazy v-if="!isReload">
@@ -41,7 +41,7 @@
<el-tab-pane label="监测点运行状态" name="6" lazy v-if="!isReload"> <el-tab-pane label="监测点运行状态" name="6" lazy v-if="!isReload">
<Yunxingzhuangtai v-if="activeName == '6'" /> <Yunxingzhuangtai v-if="activeName == '6'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="实时数据" name="7" lazy v-if="!isReload && !VITE_FLAG && !VITE_FLAG1"> <el-tab-pane label="实时数据" name="7" lazy v-if="!isReload && !VITE_FLAG1 && !IS_LNQR">
<Shishishuju v-if="activeName == '7'" /> <Shishishuju v-if="activeName == '7'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="统计报表" name="8" lazy v-if="!isReload && VITE_FLAG"> <el-tab-pane label="统计报表" name="8" lazy v-if="!isReload && VITE_FLAG">
@@ -77,6 +77,8 @@ import { useRoute } from 'vue-router'
import StatisticalReport from './statisticalReport/index.vue' import StatisticalReport from './statisticalReport/index.vue'
const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei' const VITE_FLAG = import.meta.env.VITE_NAME == 'jibei'
const VITE_FLAG1 = import.meta.env.VITE_NAME == 'hainan' const VITE_FLAG1 = import.meta.env.VITE_NAME == 'hainan'
// 环境标识
const IS_LNQR = import.meta.env.VITE_NAME === 'LNqr'
import router from '@/router' import router from '@/router'
import { useMonitoringPoint } from '@/stores/monitoringPoint' import { useMonitoringPoint } from '@/stores/monitoringPoint'
import { id } from 'element-plus/es/locale' import { id } from 'element-plus/es/locale'

View File

@@ -744,16 +744,6 @@ const initEcharts = (color: string, key: number, name: string) => {
} }
//渲染echarts //渲染echarts
const init = () => { const init = () => {
loading.value = true
const url = localStorage.getItem('WebSocketUrl') || 'ws://192.168.1.68:10407/api/pushMessage/'
echartsDataV1.value = initEcharts('#DAA520', 0, 'A相')
echartsDataV2.value = initEcharts('#2E8B57', 0, 'B相')
echartsDataV3.value = initEcharts('#A52a2a', 0, 'C相')
echartsDataA1.value = initEcharts('#DAA520', 1, 'A相')
echartsDataA2.value = initEcharts('#2E8B57', 1, 'B相')
echartsDataA3.value = initEcharts('#A52a2a', 1, 'C相')
if (!dataSocket.socketServe) { if (!dataSocket.socketServe) {
console.error('WebSocket 客户端实例不存在') console.error('WebSocket 客户端实例不存在')
return return
@@ -765,9 +755,22 @@ const init = () => {
type: 'warning' type: 'warning'
}) })
} }
loading.value = true
const url = localStorage.getItem('WebSocketUrl') || 'null' //'ws://192.168.1.68:10407/api/pushMessage/'
echartsDataV1.value = initEcharts('#DAA520', 0, 'A相')
echartsDataV2.value = initEcharts('#2E8B57', 0, 'B相')
echartsDataV3.value = initEcharts('#A52a2a', 0, 'C相')
echartsDataA1.value = initEcharts('#DAA520', 1, 'A相')
echartsDataA2.value = initEcharts('#2E8B57', 1, 'B相')
echartsDataA3.value = initEcharts('#A52a2a', 1, 'C相')
let pids = monitoringPoint.state.pid.split(',') let pids = monitoringPoint.state.pid.split(',')
dataSocket.socketServe.connect(`${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}`) dataSocket.socketServe.connect(`${url}${adminInfo.id},${monitoringPoint.state.lineId},${pids[pids.length - 2]}`)
dataSocket.socketServe.registerCallBack('message', (res: any) => { dataSocket.socketServe.registerCallBack('message', (res: any) => {
if (res.Flag === false) {
return (loading.value = false)
}
txtContent.value = res.value txtContent.value = res.value
let data = JSON.parse(res.value) let data = JSON.parse(res.value)
time.value = data.TIME - 0 time.value = data.TIME - 0
@@ -779,12 +782,12 @@ const init = () => {
iRmsA: data.I.A?.IRMS, //A相电流 iRmsA: data.I.A?.IRMS, //A相电流
iRmsB: data.I.B?.IRMS, //B相电流 iRmsB: data.I.B?.IRMS, //B相电流
iRmsC: data.I.C?.IRMS, //C相电流 iRmsC: data.I.C?.IRMS, //C相电流
v1AngA: data.V.A?.VFUND_ANGLE, //A相基波电压相位 v1AngA: steAngle(data.V.A?.VFUND_ANGLE), //A相基波电压相位
v1AngB: data.V.B?.VFUND_ANGLE, //B相基波电压相位 v1AngB: steAngle(data.V.B?.VFUND_ANGLE), //B相基波电压相位
v1AngC: data.V.C?.VFUND_ANGLE, //C相基波电压相位 v1AngC: steAngle(data.V.C?.VFUND_ANGLE), //C相基波电压相位
i1AngA: data.I.A?.I_ANGLE, //A相基波电流相位 i1AngA: steAngle(data.I.A?.I_ANGLE), //A相基波电流相位
i1AngB: data.I.B?.I_ANGLE, //B相基波电流相位 i1AngB: steAngle(data.I.B?.I_ANGLE), //B相基波电流相位
i1AngC: data.I.C?.I_ANGLE, //C相基波电流相位 i1AngC: steAngle(data.I.C?.I_ANGLE), //C相基波电流相位
freq: data.V.T?.FREQ, //频率 freq: data.V.T?.FREQ, //频率
freqDev: data.V.T?.DELTA_FREQ, //频率偏差 freqDev: data.V.T?.DELTA_FREQ, //频率偏差
vUnbalance: data.V.T?.V_UNBAN, //电压不平衡度 vUnbalance: data.V.T?.V_UNBAN, //电压不平衡度
@@ -950,6 +953,20 @@ const setRealData = () => {
] ]
pieChart6.value.initChart() pieChart6.value.initChart()
} }
const steAngle = (phase: any) => {
// 空值判断
if (phase === null || phase === undefined) {
return null
}
let normalizedPhase = phase % 360
if (normalizedPhase > 180) {
normalizedPhase -= 360
} else if (normalizedPhase < -180) {
normalizedPhase += 360
}
return normalizedPhase
}
defineExpose({ setRealData }) defineExpose({ setRealData })
onMounted(() => { onMounted(() => {
init() init()

View File

@@ -10,53 +10,30 @@
<DatePicker ref="datePickerRef" :theCurrentTime="true"></DatePicker> <DatePicker ref="datePickerRef" :theCurrentTime="true"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="指标类型:"> <el-form-item label="指标类型:">
<el-select <el-select v-model="formData.condition" multiple collapse-tags :multiple-limit="checked ? 1 : 3"
v-model="formData.condition" filterable placeholder="请选择指标" @change="conditionChange">
multiple
collapse-tags
:multiple-limit="checked ? 1 : 3"
filterable
placeholder="请选择指标"
@change="conditionChange"
>
<el-option-group v-for="group in indexOptions" :key="group.label" :label="group.label"> <el-option-group v-for="group in indexOptions" :key="group.label" :label="group.label">
<el-option <el-option v-for="item in group.options" :key="item.value" :label="item.label"
v-for="item in group.options" :value="item.value"></el-option>
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-option-group> </el-option-group>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="数值类型:"> <el-form-item label="数值类型:">
<el-select style="width: 100%" v-model="formData.valueType" placeholder="请选择类型"> <el-select style="width: 100%" v-model="formData.valueType" placeholder="请选择类型">
<el-option <el-option v-for="item in typeOptions" :key="item.value" :label="item.label"
v-for="item in typeOptions" :value="item.value"></el-option>
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="谐波次数:" v-show="showXieBoCiShu"> <el-form-item label="谐波次数:" v-show="showXieBoCiShu">
<el-select style="width: 100%" v-model="formData.harmonic" placeholder="请选择谐波"> <el-select style="width: 100%" v-model="formData.harmonic" placeholder="请选择谐波">
<el-option <el-option v-for="item in harmonicOptions" :key="item.value" :label="item.label"
v-for="item in harmonicOptions" :value="item.value"></el-option>
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-show="showJianXieBoCiShu" label="间谐波次数:"> <el-form-item v-show="showJianXieBoCiShu" label="间谐波次数:">
<el-select style="width: 100%" v-model="formData.inHarmonic" placeholder="请选择间谐波"> <el-select style="width: 100%" v-model="formData.inHarmonic" placeholder="请选择间谐波">
<el-option <el-option v-for="item in inharmonicOptions" :key="item.value" :label="item.label"
v-for="item in inharmonicOptions" :value="item.value"></el-option>
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
@@ -67,21 +44,10 @@
<!-- <el-form :inline="true"> <!-- <el-form :inline="true">
</el-form> --> </el-form> -->
<div <div id="canvas" class="mt10" :style="height1" style="overflow-y: auto; overflow-x: hidden"
id="canvas" v-loading="loading">
class="mt10" <my-echart :options="item.option" v-for="item in list" style="min-height: 190px" :style="height"
:style="height1" @triggerPoint="triggerPoint" @group="group" />
style="overflow-y: auto; overflow-x: hidden"
v-loading="loading"
>
<my-echart
:options="item.option"
v-for="item in list"
style="min-height: 190px"
:style="height"
@triggerPoint="triggerPoint"
@group="group"
/>
</div> </div>
</div> </div>
<div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view"> <div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view">
@@ -232,8 +198,8 @@ const shujuchuli = (res: any) => {
let cvalue = [] let cvalue = []
let topLimit = [] let topLimit = []
let lowerLimit = [] let lowerLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -270,7 +236,7 @@ const shujuchuli = (res: any) => {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([ chufa.push([
item.eventDetail[k].time, item.eventDetail[k].time,
item.minValue.toFixed(3), (0).toFixed(3),
item.eventDetail[k].id, item.eventDetail[k].id,
99 99
]) ])
@@ -293,6 +259,7 @@ const shujuchuli = (res: any) => {
lowerLimit: lowerLimit, lowerLimit: lowerLimit,
chufa: chufa chufa: chufa
} }
list.value.push(shuju) list.value.push(shuju)
} }
//图列为频率等,暂降,上限,下限 //图列为频率等,暂降,上限,下限
@@ -300,8 +267,8 @@ const shujuchuli = (res: any) => {
let gvalue = [] let gvalue = []
let topLimit = [] let topLimit = []
let lowerLimit = [] let lowerLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -324,7 +291,7 @@ const shujuchuli = (res: any) => {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([ chufa.push([
item.eventDetail[k].time, item.eventDetail[k].time,
item.minValue.toFixed(3), (0).toFixed(3),
item.eventDetail[k].id, item.eventDetail[k].id,
99 99
]) ])
@@ -378,7 +345,7 @@ const shujuchuli = (res: any) => {
let bvalue = [] let bvalue = []
let cvalue = [] let cvalue = []
let topLimit = [] let topLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -414,7 +381,7 @@ const shujuchuli = (res: any) => {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([ chufa.push([
item.eventDetail[k].time, item.eventDetail[k].time,
item.minValue.toFixed(3), (0).toFixed(3),
item.eventDetail[k].id, item.eventDetail[k].id,
99 99
]) ])
@@ -442,7 +409,7 @@ const shujuchuli = (res: any) => {
if (item.phaiscType.length == 3) { if (item.phaiscType.length == 3) {
let gvalue = [] let gvalue = []
let topLimit = [] let topLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -462,7 +429,7 @@ const shujuchuli = (res: any) => {
//不存在一个暂降点或1个 //处理暂降点 //不存在一个暂降点或1个 //处理暂降点
if (item.eventDetail.length > 0) { if (item.eventDetail.length > 0) {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([item.eventDetail[k].time, item.minValue.toFixed(3)]) chufa.push([item.eventDetail[k].time, (0).toFixed(3)])
} }
} }
let shuju = { let shuju = {
@@ -512,7 +479,7 @@ const shujuchuli = (res: any) => {
let bvalue = [] let bvalue = []
let cvalue = [] let cvalue = []
let lowerLimit = [] let lowerLimit = []
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -546,7 +513,7 @@ const shujuchuli = (res: any) => {
//不存在一个暂降点或1个 //处理暂降点 //不存在一个暂降点或1个 //处理暂降点
if (item.eventDetail.length > 0) { if (item.eventDetail.length > 0) {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([item.eventDetail[k].time, item.minValue.toFixed(3)]) chufa.push([item.eventDetail[k].time, (0).toFixed(3)])
} }
} }
let shuju = { let shuju = {
@@ -571,7 +538,7 @@ const shujuchuli = (res: any) => {
if (item.phaiscType.length == 3) { if (item.phaiscType.length == 3) {
let gvalue = [] let gvalue = []
let lowerLimit = [] let lowerLimit = []
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -591,7 +558,7 @@ const shujuchuli = (res: any) => {
//不存在一个暂降点或1个 //处理暂降点 //不存在一个暂降点或1个 //处理暂降点
if (item.eventDetail.length > 0) { if (item.eventDetail.length > 0) {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([item.eventDetail[k].time, item.minValue.toFixed(3)]) chufa.push([item.eventDetail[k].time, (0).toFixed(3)])
} }
} }
let shuju = { let shuju = {
@@ -632,6 +599,7 @@ const shujuchuli = (res: any) => {
} }
//无限值 //无限值
if (item.topLimit == 0 && item.lowerLimit == 0) { if (item.topLimit == 0 && item.lowerLimit == 0) {
if (item.minValue !== null && item.maxValue !== null) { if (item.minValue !== null && item.maxValue !== null) {
//最小值等于下限值 //最小值等于下限值
//图列为A,B,C,暂降 //图列为A,B,C,暂降
@@ -672,7 +640,7 @@ const shujuchuli = (res: any) => {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([ chufa.push([
item.eventDetail[k].time, item.eventDetail[k].time,
item.minValue.toFixed(3), (0).toFixed(3),
item.eventDetail[k].id, item.eventDetail[k].id,
99 99
]) ])
@@ -717,7 +685,7 @@ const shujuchuli = (res: any) => {
for (let k = 0; k < item.eventDetail.length; k++) { for (let k = 0; k < item.eventDetail.length; k++) {
chufa.push([ chufa.push([
item.eventDetail[k].time, item.eventDetail[k].time,
item.minValue.toFixed(3), (0).toFixed(3),
item.eventDetail[k].id, item.eventDetail[k].id,
99 99
]) ])
@@ -772,8 +740,8 @@ const shujuchuli = (res: any) => {
let cvalue = [] let cvalue = []
let topLimit = [] let topLimit = []
let lowerLimit = [] let lowerLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -828,8 +796,8 @@ const shujuchuli = (res: any) => {
let gvalue = [] let gvalue = []
let topLimit = [] let topLimit = []
let lowerLimit = [] let lowerLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -895,7 +863,7 @@ const shujuchuli = (res: any) => {
let bvalue = [] let bvalue = []
let cvalue = [] let cvalue = []
let topLimit = [] let topLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
// item.minValue=item.lowerLimit // item.minValue=item.lowerLimit
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
@@ -948,7 +916,7 @@ const shujuchuli = (res: any) => {
if (item.phaiscType.length == 2) { if (item.phaiscType.length == 2) {
let gvalue = [] let gvalue = []
let topLimit = [] let topLimit = []
item.maxValue = item.topLimit item.maxValue = (item.topLimit > item.maxValue ? item.topLimit : item.maxValue)
// item.minValue=item.lowerLimit // item.minValue=item.lowerLimit
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
@@ -1013,7 +981,7 @@ const shujuchuli = (res: any) => {
let cvalue = [] let cvalue = []
let lowerLimit = [] let lowerLimit = []
// item.maxValue=item.topLimit // item.maxValue=item.topLimit
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -1066,7 +1034,7 @@ const shujuchuli = (res: any) => {
let gvalue = [] let gvalue = []
let lowerLimit = [] let lowerLimit = []
// item.maxValue=item.topLimit // item.maxValue=item.topLimit
item.minValue = item.lowerLimit item.minValue = (item.lowerLimit < item.minValue ? item.lowerLimit : item.minValue)
//判断数据是否存在 //判断数据是否存在
if (item.value !== null) { if (item.value !== null) {
for (let j = 0; j < item.value.length; j++) { for (let j = 0; j < item.value.length; j++) {
@@ -1227,19 +1195,85 @@ const shujuchuli = (res: any) => {
}) })
rendering() rendering()
} }
const getSeriesDataValues = (data: any[]) => {
if (!data?.length) return []
return data
.map(d => (Array.isArray(d) && d[1] != null && d[1] !== '' ? Number(d[1]) : null))
.filter((v): v is number => v != null && !Number.isNaN(v))
}
const buildItemYAxis = (item: any) => {
if (item.useDualAxis && item.serise?.length) {
const uniqueUnits = [...new Set(item.units.filter((u: string) => u != null && u !== ''))] as string[]
const valuesByUnit: Record<string, number[]> = {}
uniqueUnits.forEach(u => {
valuesByUnit[u] = []
})
item.serise.forEach((s: any) => {
const axisIdx = s.yAxisIndex ?? 0
const unit = uniqueUnits[axisIdx]
if (unit) valuesByUnit[unit].push(...getSeriesDataValues(s.data))
})
return uniqueUnits.map((unit, index) => {
const [min, max] = yMethod(valuesByUnit[unit].length ? valuesByUnit[unit] : [0])
return {
type: 'value',
min,
max,
name: unit,
position: index === 0 ? 'left' : 'right',
minInterval: index === 0 ? 1 : undefined,
axisLine: {
show: true,
onZero: false
},
splitLine: index === 0 ? undefined : { show: false }
}
})
}
const values = item.value?.length ? item.value.map((k: any) => k[1]) : [0]
const [min, max] = yMethod([item.maxValue, item.minValue, ...values])
return [
{
type: 'value',
min,
max,
name: item.valueName,
minInterval: 1,
axisLine: {
show: true,
onZero: false
}
}
]
}
const rendering = () => { const rendering = () => {
height.value = mainHeight(160, list.value.length > 3 ? 3 : list.value.length) height.value = mainHeight(160, list.value.length > 3 ? 3 : list.value.length)
list.value.forEach((item: any) => { list.value.forEach((item: any) => {
const idx = parseInt(String(item.id).replace('qushifenx', ''))
item.units = (tableData.value[idx] as any)?.unit || (item.valueName ? [item.valueName] : [''])
const uniqueUnits = [...new Set(item.units.filter((u: string) => u != null && u !== ''))] as string[]
item.useDualAxis = uniqueUnits.length > 1
const getAxisIndex = (unitIndex: number) => {
if (!item.useDualAxis) return 0
const unit = item.units[unitIndex] ?? item.units[0]
return uniqueUnits.indexOf(unit)
}
const withAxis = (data: any, unitIndex: number) => {
if (item.useDualAxis) data.yAxisIndex = getAxisIndex(unitIndex)
return data
}
const isShanBian = item.targetName.includes('闪变')
const lineSeriesOpts = isShanBian ? { smooth: false, step: 'end' as const } : { smooth: true }
if (item.targetName == '电压不平衡') { if (item.targetName == '电压不平衡') {
item.valueName = '' item.valueName = ''
const phaseNames = ['零序电压', '正序电压', '负序电压']
item.legend = item.legend.map((item2: any) => { item.legend = item.legend.map((item2: any) => {
if (item2 == '零序电压') { const phaseIdx = phaseNames.indexOf(item2)
item2 = item2 + '(V)' if (phaseIdx >= 0 && item.units[phaseIdx]) {
} else if (item2 == '正序电压') { return item2 + '(' + item.units[phaseIdx] + ')'
item2 = item2 + '(kV)'
} else if (item2 == '负序电压') {
item2 = item2 + '(V)'
} }
return item2 return item2
}) })
@@ -1247,13 +1281,16 @@ const rendering = () => {
let opitonserise: any[] = [] let opitonserise: any[] = []
item.legend.forEach((item2: any) => { item.legend.forEach((item2: any) => {
if (item.avalue !== undefined && (item2 == 'A相' || item2 == 'AB相' || item2 == '零序电压(V)')) { if (
item.avalue !== undefined &&
(item2 == 'A相' || item2 == 'AB相' || item2.startsWith('零序电压'))
) {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#DAA520' color: '#DAA520'
@@ -1262,14 +1299,17 @@ const rendering = () => {
data: item.avalue data: item.avalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.bvalue !== undefined && (item2 == 'B相' || item2 == 'BC相' || item2 == '正序电压(kV)')) { } else if (
item.bvalue !== undefined &&
(item2 == 'B相' || item2 == 'BC相' || item2.startsWith('正序电压'))
) {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#2E8B57' color: '#2E8B57'
@@ -1278,14 +1318,17 @@ const rendering = () => {
data: item.bvalue data: item.bvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 1))
} else if (item.cvalue !== undefined && (item2 == 'C相' || item2 == 'CA相' || item2 == '负序电压(V)')) { } else if (
item.cvalue !== undefined &&
(item2 == 'C相' || item2 == 'CA相' || item2.startsWith('负序电压'))
) {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
barWidth: 22, barWidth: 22,
itemStyle: { itemStyle: {
normal: { normal: {
@@ -1294,14 +1337,14 @@ const rendering = () => {
}, },
data: item.cvalue data: item.cvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 2))
} else if (item.topLimit !== undefined && item2 == '上限') { } else if (item.topLimit !== undefined && item2 == '上限') {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#FF33FF', color: '#FF33FF',
@@ -1314,14 +1357,14 @@ const rendering = () => {
}, },
data: item.topLimit data: item.topLimit
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.lowerLimit !== undefined && item2 == '下限') { } else if (item.lowerLimit !== undefined && item2 == '下限') {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
barWidth: 22, barWidth: 22,
itemStyle: { itemStyle: {
normal: { normal: {
@@ -1335,7 +1378,7 @@ const rendering = () => {
}, },
data: item.lowerLimit data: item.lowerLimit
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.chufa !== undefined && item2 == '暂态触发点') { } else if (item.chufa !== undefined && item2 == '暂态触发点') {
let data = { let data = {
name: item2, name: item2,
@@ -1348,14 +1391,14 @@ const rendering = () => {
}, },
data: item.chufa data: item.chufa
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.gvalue !== undefined && item2 == '频率') { } else if (item.gvalue !== undefined && item2 == '频率') {
let data = { let data = {
name: item2, name: item2,
symbol: 'none', symbol: 'none',
symbolSize: 5, symbolSize: 5,
type: 'line', type: 'line',
smooth: true, ...lineSeriesOpts,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#990099', color: '#990099',
@@ -1368,7 +1411,7 @@ const rendering = () => {
}, },
data: item.gvalue data: item.gvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.gvalue !== undefined && item2 == '负序电流') { } else if (item.gvalue !== undefined && item2 == '负序电流') {
let data = { let data = {
name: item2, name: item2,
@@ -1383,7 +1426,7 @@ const rendering = () => {
}, },
data: item.gvalue data: item.gvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.gvalue !== undefined && item2 == '三相电压不平衡度') { } else if (item.gvalue !== undefined && item2 == '三相电压不平衡度') {
let data = { let data = {
name: item2, name: item2,
@@ -1398,7 +1441,7 @@ const rendering = () => {
}, },
data: item.gvalue data: item.gvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if ( } else if (
item.gvalue !== undefined && item.gvalue !== undefined &&
(item2 == '三相总有功功率' || item2 == '三相总无功功率' || item2 == '三相总视在功率') (item2 == '三相总有功功率' || item2 == '三相总无功功率' || item2 == '三相总视在功率')
@@ -1411,12 +1454,12 @@ const rendering = () => {
barWidth: 22, barWidth: 22,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#0033ff' color: '#526ADE'
} }
}, },
data: item.gvalue data: item.gvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} else if (item.gvalue !== undefined && (item2 == '总视在功率因数' || item2 == '总位移功率因数')) { } else if (item.gvalue !== undefined && (item2 == '总视在功率因数' || item2 == '总位移功率因数')) {
let data = { let data = {
name: item2, name: item2,
@@ -1426,32 +1469,91 @@ const rendering = () => {
barWidth: 22, barWidth: 22,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#00FF00' color: '#526ADE'
} }
}, },
data: item.gvalue data: item.gvalue
} }
opitonserise.push(data) opitonserise.push(withAxis(data, 0))
} }
// else { // else {
// opitonserise.push([]) // opitonserise.push([])
// } // }
}) })
if (item.valueName == undefined) { if (item.valueName == undefined) {
item.valueName = '' item.valueName = ''
} }
//console.log('渲染数据体',opitonserise) //console.log('渲染数据体',opitonserise)
item.serise = opitonserise item.serise = opitonserise
}) })
getEcharts() getEcharts()
} }
const measureTextWidth = (text: string, fontSize = 14) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (!ctx) return text.length * fontSize * 0.6
ctx.font = `${fontSize}px dinproRegular, sans-serif`
return ctx.measureText(text).width
}
const getYAxisLeftPadding = (yAxis: any) => {
const splitNumber = yAxis.splitNumber ?? 5
const min = yAxis.min ?? 0
const max = yAxis.max ?? 0
let maxLabelWidth = 0
const formatter = yAxis.axisLabel?.formatter
const formatLabel = (value: number) => {
if (formatter) {
const result = formatter(value)
return result != null && result !== '' ? String(result) : ''
}
return String(parseFloat(value.toFixed(1)))
}
if (yAxis.interval) {
for (let v = min; v <= max + yAxis.interval * 0.01; v += yAxis.interval) {
const label = formatLabel(v)
if (label) maxLabelWidth = Math.max(maxLabelWidth, measureTextWidth(label))
}
} else {
const step = splitNumber > 0 ? (max - min) / splitNumber : 0
for (let i = 0; i <= splitNumber; i++) {
const label = formatLabel(min + step * i)
if (label) maxLabelWidth = Math.max(maxLabelWidth, measureTextWidth(label))
}
}
const nameWidth = yAxis.name ? measureTextWidth(yAxis.name) : 0
return Math.ceil(Math.max(maxLabelWidth, nameWidth)) + 15
}
const alignChartsYAxis = () => {
let maxLeft = 50
let maxRight = 70
let hasDualAxis = false
list.value.forEach((item: any) => {
const yAxes = item.option?.yAxis || []
if (yAxes.length > 1) hasDualAxis = true
yAxes.forEach((yAxis: any, index: number) => {
const padding = getYAxisLeftPadding(yAxis)
if (yAxis.position === 'right' || (yAxes.length > 1 && index > 0)) {
maxRight = Math.max(maxRight, padding)
} else {
maxLeft = Math.max(maxLeft, padding)
}
})
})
if (list.value.length <= 1 && !hasDualAxis) return
list.value.forEach((item: any) => {
const gridUpdate: any = { containLabel: false }
if (list.value.length > 1 || hasDualAxis) gridUpdate.left = maxLeft
if (hasDualAxis) gridUpdate.right = maxRight
item.option.grid = {
...item.option.grid,
...gridUpdate
}
})
}
const getEcharts = () => { const getEcharts = () => {
list.value.forEach((item: any, i: number) => { list.value.forEach((item: any, i: number) => {
const yAxisConfig = buildItemYAxis(item)
const values = item.value && item.value.length > 0 ? item.value.map(k => k[1]) : [0]
let [min, max] = yMethod([item.maxValue, item.minValue, ...values])
item.option = { item.option = {
backgroundColor: '#fff', backgroundColor: '#fff',
title: { title: {
@@ -1470,14 +1572,14 @@ const getEcharts = () => {
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { // axisPointer: {
//type: "shadow", // //type: "shadow",
type: 'cross', // 默认为直线,可选为:'line' | 'shadow' // type: 'cross', // 默认为直线,可选为:'line' | 'shadow'
label: { // label: {
color: '#fff', // color: '#fff',
fontSize: 16 // fontSize: 16
} // }
}, // },
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontStyle: 'normal', fontStyle: 'normal',
@@ -1503,54 +1605,63 @@ const getEcharts = () => {
params[i].marker + params[i].value[1] > 0 params[i].marker + params[i].value[1] > 0
? 'A相谐波电流方向:流入<br/>' ? 'A相谐波电流方向:流入<br/>'
: params[i].value[1] == 0 : params[i].value[1] == 0
? 'A相谐波电流方向:无<br/>' ? 'A相谐波电流方向:无<br/>'
: 'A相谐波电流方向:流出<br/>' : 'A相谐波电流方向:流出<br/>'
} else if (params[i].seriesName == 'B相谐波电流方向') { } else if (params[i].seriesName == 'B相谐波电流方向') {
tips += tips +=
params[i].marker + params[i].value[1] > 0 params[i].marker + params[i].value[1] > 0
? 'B相谐波电流方向:流入<br/>' ? 'B相谐波电流方向:流入<br/>'
: params[i].value[1] == 0 : params[i].value[1] == 0
? 'B相谐波电流方向:无<br/>' ? 'B相谐波电流方向:无<br/>'
: 'B相谐波电流方向:流出<br/>' : 'B相谐波电流方向:流出<br/>'
} else if (params[i].seriesName == 'C相谐波电流方向') { } else if (params[i].seriesName == 'C相谐波电流方向') {
tips += tips +=
params[i].marker + params[i].value[1] > 0 params[i].marker + params[i].value[1] > 0
? 'C相谐波电流方向:流入<br/>' ? 'C相谐波电流方向:流入<br/>'
: params[i].value[1] == 0 : params[i].value[1] == 0
? 'C相谐波电流方向:无<br/>' ? 'C相谐波电流方向:无<br/>'
: 'C相谐波电流方向:流出<br/>' : 'C相谐波电流方向:流出<br/>'
} else if (params[i].seriesName == '总谐波电流方向') { } else if (params[i].seriesName == '总谐波电流方向') {
tips += tips +=
params[i].marker + params[i].value[1] > 0 params[i].marker + params[i].value[1] > 0
? '总谐波电流方向:流入<br/>' ? '总谐波电流方向:流入<br/>'
: params[i].value[1] == 0 : params[i].value[1] == 0
? '总谐波电流方向:无<br/>' ? '总谐波电流方向:无<br/>'
: '总谐波电流方向:流出<br/>' : '总谐波电流方向:流出<br/>'
} else if (params[i].seriesName == '正序电压(kV)') { } else if (params[i].seriesName.includes('正序电压')) {
let str = (params[i].value[1] * 1).toString() let str = (params[i].value[1] * 1).toString()
let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g
let str1 = str.replace(reg, '$1,') let str1 = str.replace(reg, '$1,')
let cleanStr = str1.replace(/,/g, '') let cleanStr = str1.replace(/,/g, '')
let num = Number(cleanStr) let num = Number(cleanStr)
const unitMatch = params[i].seriesName.match(/\(([^)]+)\)$/)
const unit = unitMatch ? unitMatch[1] : 'kV'
tips += tips +=
params[i].marker + params[i].marker +
params[i].seriesName.replace('(kV)', '') + params[i].seriesName.replace(/\([^)]+\)$/, '') +
':' + ':' +
(Number.isNaN(Number(num)) ? '/' : num) + (Number.isNaN(Number(num)) ? '/' : num) +
'kV<br/>' unit +
} else if (params[i].seriesName == '零序电压(V)' || params[i].seriesName == '负序电压(V)') { '<br/>'
} else if (
params[i].seriesName.includes('零序电压') ||
params[i].seriesName.includes('负序电压')
) {
let str = (params[i].value[1] * 1).toString() let str = (params[i].value[1] * 1).toString()
let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g
let str1 = str.replace(reg, '$1,') let str1 = str.replace(reg, '$1,')
let cleanStr = str1.replace(/,/g, '') let cleanStr = str1.replace(/,/g, '')
let num = Number(cleanStr) let num = Number(cleanStr)
const unitMatch = params[i].seriesName.match(/\(([^)]+)\)$/)
const unit = unitMatch ? unitMatch[1] : 'V'
tips += tips +=
params[i].marker + params[i].marker +
params[i].seriesName.replace('(V)', '') + params[i].seriesName.replace(/\([^)]+\)$/, '') +
':' + ':' +
(Number.isNaN(Number(num)) ? '/' : num) + (Number.isNaN(Number(num)) ? '/' : num) +
'V<br/>' unit +
} else if (params[i].seriesName !== '正序电压(kV)') { '<br/>'
} else if (!params[i].seriesName.includes('正序电压')) {
let str = (params[i].value[1] * 1).toString() let str = (params[i].value[1] * 1).toString()
let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g let reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g
let str1 = str.replace(reg, '$1,') let str1 = str.replace(reg, '$1,')
@@ -1639,8 +1750,24 @@ const getEcharts = () => {
} }
}, },
grid: { grid: {
top: '70px' top: '50px',
bottom: '45px'
}, },
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '10px',
end: 100
},
{
start: 0,
height: 13,
bottom: '10px',
end: 100
}
],
xAxis: [ xAxis: [
{ {
name: '时间', name: '时间',
@@ -1665,38 +1792,7 @@ const getEcharts = () => {
// } // }
// } // }
// }, // },
yAxis: [ yAxis: yAxisConfig,
{
type: 'value',
min: min,
max: max,
name: item.valueName,
minInterval: 1,
// max:10,
// min:0,
// axisLabel: {
// interval: 0,
// // formatter: function (value: any) {
// // return value.toFixed(0)
// // },
// left: '20px'
// },
axisLine: {
show: true,
onZero: false, //-----------重点
lineStyle: {}
}
// splitLine: {
// lineStyle: {
// // 使用深浅的间隔色
// type: 'dashed',
// opacity: 0.5
// }
// }
}
],
series: item.serise series: item.serise
} }
let aValues = [] let aValues = []
@@ -1801,13 +1897,14 @@ const getEcharts = () => {
symbolSize: 0, symbolSize: 0,
itemStyle: { itemStyle: {
normal: { normal: {
color: '#0033ff' color: '#526ADE'
} }
} }
} }
] ]
} }
}) })
alignChartsYAxis()
echarts.connect('group') echarts.connect('group')
} }
const conditionChange = () => { const conditionChange = () => {
@@ -1947,7 +2044,7 @@ const conditionChange = () => {
] ]
} }
setTimeout(() => { setTimeout(() => {
//console.log('🚀 ~ setTimeout ~ tableHeaderRef.value:', tableHeaderRef.value) //console.log('🚀 ~ setTimeout ~ tableHeaderRef.value:', tableHeaderRef.value)
//tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow() //tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow()
}, 100) }, 100)

View File

@@ -9,7 +9,7 @@
clearable clearable
maxlength="32" maxlength="32"
show-word-limit show-word-limit
placeholder="筛选数据" placeholder="请输入关键字"
/> />
</el-form-item> </el-form-item>
</template> </template>

View File

@@ -11,11 +11,12 @@
<pane style="background: #fff" :style="height"> <pane style="background: #fff" :style="height">
<TableHeader ref="TableHeaderRef" datePicker :show-search="false"> <TableHeader ref="TableHeaderRef" datePicker :show-search="false">
<template #operation> <template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent" :loading="loading"> <el-button icon="el-icon-Download" type="primary" @click="openDialog" :loading="loading">
生成 生成
</el-button> </el-button>
</template> </template>
</TableHeader> </TableHeader>
<div class="box"> <div class="box">
<div id="luckysheet"> <div id="luckysheet">
<img <img
@@ -25,13 +26,46 @@
/> />
</div> </div>
</div> </div>
<!-- 电压等级选择弹窗 -->
<el-dialog
v-model="dialogVisible"
title="选择电压等级"
width="420px"
:close-on-click-modal="false"
>
<el-form label-width="100px" style="padding:10px 0;">
<el-form-item label="电压等级">
<el-select
v-model="voltageLevel"
multiple
collapse-tags
clearable
value-key="id"
placeholder="请选择电压等级"
style="width: 260px;"
>
<el-option
v-for="item in voltageleveloption"
:key="item.id"
:label="item.name"
:value="item"
></el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmExport" :loading="loading">确定并生成</el-button>
</template>
</el-dialog>
</pane> </pane>
</splitpanes> </splitpanes>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, provide } from 'vue' import { onMounted, ref, provide, watch } from 'vue'
import 'splitpanes/dist/splitpanes.css' import 'splitpanes/dist/splitpanes.css'
import { Splitpanes, Pane } from 'splitpanes' import { Splitpanes, Pane } from 'splitpanes'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
@@ -40,8 +74,7 @@ import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { areaHarmonicReport } from '@/api/process-boot/reportForms' import { areaHarmonicReport } from '@/api/process-boot/reportForms'
import { genFileId, ElMessage, ElNotification } from 'element-plus' import { ElMessage } from 'element-plus'
import type { UploadProps, UploadUserFile } from 'element-plus'
import dayjs from 'dayjs' import dayjs from 'dayjs'
defineOptions({ defineOptions({
@@ -53,7 +86,11 @@ const loading = ref(false)
const dictData = useDictData() const dictData = useDictData()
const TableHeaderRef = ref() const TableHeaderRef = ref()
const dotList: any = ref({}) const dotList: any = ref({})
const Template: any = ref({}) const voltageleveloption = dictData.getBasicData('Dev_Voltage_Stand') || []
const voltageLevel: any = ref([])
// 弹窗状态
const dialogVisible = ref(false)
const tableStore = new TableStore({ const tableStore = new TableStore({
url: '', url: '',
@@ -64,9 +101,15 @@ const tableStore = new TableStore({
}) })
provide('tableStore', tableStore) provide('tableStore', tableStore)
// 弹窗打开时默认全选所有电压等级
watch(dialogVisible, (val) => {
if (val && voltageleveloption.length) {
voltageLevel.value = [...voltageleveloption]
}
})
onMounted(() => { onMounted(() => {
const dom = document.getElementById('navigation-splitpanes') const dom = document.getElementById('navigation-splitpanes')
if (dom) { if (dom) {
size.value = Math.round((180 / dom.offsetHeight) * 120) size.value = Math.round((180 / dom.offsetHeight) * 120)
} }
@@ -76,45 +119,62 @@ const handleNodeClick = (data: any, node: any) => {
dotList.value = data dotList.value = data
} }
// 生成 // 打开弹窗
const exportEvent = () => { const openDialog = () => {
if (!dotList.value?.id) {
ElMessage.warning('请先在左侧选择站点/区域')
return
}
dialogVisible.value = true
}
// 确认生成
const confirmExport = async () => {
loading.value = true loading.value = true
ElMessage('生成报告中...') ElMessage('生成报告中...')
areaHarmonicReport({
deptId: dotList.value.id,
areaReportFlag: 1,
startTime: TableHeaderRef.value.datePickerRef.timeValue[0],
endTime: TableHeaderRef.value.datePickerRef.timeValue[1]
})
.then((res: any) => {
if (res == undefined) {
loading.value = false
return
}
let blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8'
})
// createObjectURL(blob); //创建下载的链接 try {
const url = window.URL.createObjectURL(blob) // 选中数据转为id数组空数组代表导出全部
const link = document.createElement('a') // 创建a标签 const voltageIds = voltageLevel.value.map((item: any) => item.id)
link.href = url const res: any = await areaHarmonicReport({
link.download = dotList.value.name + '区域稳态报告' + dayjs().format('YYYYMMDD') // 设置下载的文件名 deptId: dotList.value.id,
document.body.appendChild(link) areaReportFlag: 1,
link.click() //执行下载 startTime: TableHeaderRef.value.datePickerRef.timeValue[0],
document.body.removeChild(link) endTime: TableHeaderRef.value.datePickerRef.timeValue[1],
loading.value = false voltageIds
}) })
.catch(() => {
if (!res) {
loading.value = false loading.value = false
return
}
const blob = new Blob([res], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=UTF-8'
}) })
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = dotList.value.name + '区域稳态报告' + dayjs().format('YYYYMMDD')
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
URL.revokeObjectURL(url)
ElMessage.success('生成成功')
dialogVisible.value = false
} catch (e) {
ElMessage.error('生成失败,请重试')
} finally {
loading.value = false
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.splitpanes.default-theme .splitpanes__pane { .splitpanes.default-theme .splitpanes__pane {
background: #eaeef1; background: #eaeef1;
} }
.box { .box {
padding: 10px; padding: 10px;
} }

View File

@@ -10,8 +10,14 @@
></PointTree> ></PointTree>
</pane> </pane>
<pane style="background: #fff" :style="height"> <pane style="background: #fff" :style="height">
<TableHeader ref="TableHeaderRef" datePicker @selectChange="selectChange"> <TableHeader ref="TableHeaderRef" datePicker :isStatisticData="isStatisticData" @selectChange="selectChange">
<template v-slot:select> <template v-slot:select>
<el-form-item >
<el-radio-group v-model="isStatisticData" @change="onStatisticDataChange">
<el-radio-button value="1">统计数据</el-radio-button>
<el-radio-button value="0">分钟数据</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="模板策略"> <el-form-item label="模板策略">
<el-select v-model="Template" @change="changetype" placeholder="请选择模版" value-key="id"> <el-select v-model="Template" @change="changetype" placeholder="请选择模版" value-key="id">
<el-option <el-option
@@ -22,22 +28,10 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="报表类型"> <!-- <el-form-item label="报表类型">
<el-input readonly type="text" value="分析报表"></el-input> <el-input readonly type="text" value="分析报表"></el-input>
<!-- <el-select-->
<!-- :disabled="true"--> </el-form-item> -->
<!-- v-model="reportForm"-->
<!-- :popper-append-to-body="false"-->
<!-- placeholder="请选择报表类型"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in reportFormList"-->
<!-- :key="item.value"-->
<!-- :label="item.label"-->
<!-- :value="item.value"-->
<!-- ></el-option>-->
<!-- </el-select>-->
</el-form-item>
</template> </template>
<template #operation> <template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button> <el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button>
@@ -85,6 +79,7 @@ const dotList: any = ref({})
const Template: any = ref({}) const Template: any = ref({})
const reportForm: any = ref('') const reportForm: any = ref('')
const name = ref('') const name = ref('')
const isStatisticData = ref('1')
const templatePolicy: any = ref([]) const templatePolicy: any = ref([])
const reportFormList: any = ref([ const reportFormList: any = ref([
{ {
@@ -108,6 +103,11 @@ const tableStore = new TableStore({
tableStore.table.params.tempId = Template.value.id tableStore.table.params.tempId = Template.value.id
tableStore.table.params.lineId = dotList.value.id tableStore.table.params.lineId = dotList.value.id
name.value = dotList.value.name name.value = dotList.value.name
if (Number(isStatisticData.value) === 0) {
tableStore.table.params.isStatisticData = 0
} else {
delete tableStore.table.params.isStatisticData
}
}, },
loadCallback: () => { loadCallback: () => {
tableStore.table.data.forEach((item: any) => { tableStore.table.data.forEach((item: any) => {
@@ -160,6 +160,12 @@ getTemplateByDept({ id: dictData.state.area[0].id })
const changetype = (val: any) => { const changetype = (val: any) => {
reportForm.value = val.reportForm reportForm.value = val.reportForm
} }
const onStatisticDataChange = () => {
TableHeaderRef.value?.setTheDate(3)
if (dotList.value?.id) {
// tableStore.index()
}
}
const selectChange = () => { const selectChange = () => {
//console.log('🚀 ~ selectChange ~ tableStore.table.data.lnegth :', tableStore.table.data.length) //console.log('🚀 ~ selectChange ~ tableStore.table.data.lnegth :', tableStore.table.data.length)
if (tableStore.table.data.length != 0) { if (tableStore.table.data.length != 0) {

View File

@@ -3,101 +3,47 @@
<TableHeader area ref="TableHeaderRef" showExport> <TableHeader area ref="TableHeaderRef" showExport>
<template #select> <template #select>
<el-form-item label="运行状态"> <el-form-item label="运行状态">
<el-select <el-select filterable multiple collapse-tags v-model="tableStore.table.params.runFlag" clearable
filterable placeholder="请选择运行状态">
multiple <el-option v-for="item in runFlagList" :key="item.id" :label="item.name"
collapse-tags :value="item.id"></el-option>
v-model="tableStore.table.params.runFlag" clearable placeholder="请选择运行状态">
<el-option
v-for="item in runFlagList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据筛选">
<el-input
style="width: 240px"
placeholder="电站名称,终端编号,监测点名称、电压等级、终端厂家、干扰源类型"
v-model="tableStore.table.params.searchValue"
clearable
maxlength="32"
show-word-limit
></el-input>
</el-form-item>
<el-form-item label="通讯状态:">
<el-select
v-model="tableStore.table.params.comFlag"
filterable
multiple
collapse-tags
clearable
placeholder="请选择通讯状态"
>
<el-option
v-for="item in communicationstatus"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="通讯状态">
<el-select <el-select v-model="tableStore.table.params.comFlag" filterable multiple collapse-tags clearable
v-model="tableStore.table.params.scale" placeholder="请选择通讯状态">
filterable <el-option v-for="item in communicationstatus" :key="item.value" :label="item.label"
multiple :value="item.value"></el-option>
collapse-tags
clearable
placeholder="请选择电压等级"
value-key="id"
>
<el-option
v-for="item in voltageleveloption"
:key="item.id"
:label="item.name"
:value="item"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:">
<el-select <el-form-item label="电压等级">
v-model="tableStore.table.params.manufacturer" <el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable
filterable placeholder="请选择电压等级" value-key="id">
multiple <el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name"
collapse-tags :value="item"></el-option>
clearable
placeholder="请选择终端厂家"
value-key="id"
>
<el-option
v-for="item in terminaloption"
:key="item.id"
:label="item.name"
:value="item"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="终端厂家">
<el-select <el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags
v-model="tableStore.table.params.loadType" clearable placeholder="请选择终端厂家" value-key="id">
filterable <el-option v-for="item in terminaloption" :key="item.id" :label="item.name"
multiple :value="item"></el-option>
collapse-tags
clearable
placeholder="请选择干扰源类型"
value-key="id"
>
<el-option
v-for="item in interfereoption"
:key="item.id"
:label="item.name"
:value="item"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型">
<el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable
placeholder="请选择干扰源类型" value-key="id">
<el-option v-for="item in interfereoption" :key="item.id" :label="item.name"
:value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="数据筛选">
<el-input style="width: 240px" placeholder="电站名称,终端编号,监测点名称、电压等级、终端厂家、干扰源类型"
v-model="tableStore.table.params.searchValue" clearable maxlength="32"
show-word-limit></el-input>
</el-form-item>
</template> </template>
<template #operation> <template #operation>

View File

@@ -3,7 +3,7 @@
<TableHeader area> <TableHeader area>
<template #select> <template #select>
<el-form-item label="监测点性质:"> <el-form-item label="监测点性质">
<el-select v-model="tableStore.table.params.powerFlag" filterable collapse-tags <el-select v-model="tableStore.table.params.powerFlag" filterable collapse-tags
placeholder="请选择监测点性质"> placeholder="请选择监测点性质">
<el-option v-for="item in terminalstatus" :key="item.value" :label="item.label" <el-option v-for="item in terminalstatus" :key="item.value" :label="item.label"
@@ -11,7 +11,7 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.scale" filterable multiple collapse-tags clearable
placeholder="请选择电压等级" value-key="id"> placeholder="请选择电压等级" value-key="id">
<el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name" :value="item">
@@ -19,14 +19,14 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags <el-select v-model="tableStore.table.params.manufacturer" filterable multiple collapse-tags
clearable placeholder="请选择终端厂家" value-key="id"> clearable placeholder="请选择终端厂家" value-key="id">
<el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in terminaloption" :key="item.id" :label="item.name" :value="item">
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable <el-select v-model="tableStore.table.params.loadType" filterable multiple collapse-tags clearable
placeholder="请选择干扰源类型" value-key="id"> placeholder="请选择干扰源类型" value-key="id">
<el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item"> <el-option v-for="item in interfereoption" :key="item.id" :label="item.name" :value="item">
@@ -37,7 +37,7 @@
<el-form-item label="上报类型:"> <el-form-item label="上报类型">
<el-select v-model="tableStore.table.params.monitorFlag" <el-select v-model="tableStore.table.params.monitorFlag"
placeholder="请选择上报类型"> placeholder="请选择上报类型">
<el-option v-for="item in communicationstatus" :key="item.value" :label="item.label" <el-option v-for="item in communicationstatus" :key="item.value" :label="item.label"

View File

@@ -10,7 +10,7 @@
</el-form-item> --> </el-form-item> -->
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select <el-select
v-model="tableStore.table.params.manufacturer" v-model="tableStore.table.params.manufacturer"
filterable filterable
@@ -29,10 +29,14 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="数据筛选"> <el-form-item label="数据筛选">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入市公司、变电站、用户" /> <el-input
v-model="tableStore.table.params.searchValue"
clearable
placeholder="输入市公司、变电站、用户"
/>
</el-form-item> </el-form-item>
<el-form-item label="通讯状态:"> <el-form-item label="通讯状态">
<el-select <el-select
v-model="tableStore.table.params.comF" v-model="tableStore.table.params.comF"
filterable filterable
@@ -49,7 +53,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端状态:"> <el-form-item label="终端状态">
<el-select <el-select
v-model="tableStore.table.params.runF" v-model="tableStore.table.params.runF"
filterable filterable
@@ -66,7 +70,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="干扰源类型:"> <el-form-item label="干扰源类型">
<el-select <el-select
v-model="tableStore.table.params.loadType" v-model="tableStore.table.params.loadType"
filterable filterable
@@ -84,7 +88,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="电压等级:"> <el-form-item label="电压等级">
<el-select <el-select
v-model="tableStore.table.params.scale" v-model="tableStore.table.params.scale"
filterable filterable
@@ -102,8 +106,6 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
</TableHeader> </TableHeader>
<Table ref="tableRef" /> <Table ref="tableRef" />
@@ -115,6 +117,10 @@ import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
defineOptions({
name: 'harmonic-boot/run/terminalmessage'
})
const dictData = useDictData() const dictData = useDictData()
const view = ref(true) const view = ref(true)
@@ -159,7 +165,7 @@ const tableStore = new TableStore({
{ field: 'manufacturer', title: '厂家', minWidth: 100 }, { field: 'manufacturer', title: '厂家', minWidth: 100 },
{ field: 'devName', title: '终端名称', minWidth: 100 }, { field: 'devName', title: '终端名称', minWidth: 100 },
{ field: 'ip', title: '网络参数' ,width:110 }, { field: 'ip', title: '网络参数', width: 110 },
{ field: 'loginTime', title: '投运时间', minWidth: 90 }, { field: 'loginTime', title: '投运时间', minWidth: 90 },
{ field: 'devType', title: '终端型号', minWidth: 100 }, { field: 'devType', title: '终端型号', minWidth: 100 },
{ field: 'port', title: '端口', minWidth: 60 }, { field: 'port', title: '端口', minWidth: 60 },
@@ -186,8 +192,7 @@ const tableStore = new TableStore({
正常: 'success', 正常: 'success',
中断: 'danger' 中断: 'danger'
} }
}, }
], ],
beforeSearchFun: () => { beforeSearchFun: () => {
@@ -199,11 +204,11 @@ const tableStore = new TableStore({
tableStore.table.params.runFlag = [] tableStore.table.params.runFlag = []
if (tableStore.table.params.runF != null && tableStore.table.params.runF != '') { if (tableStore.table.params.runF != null && tableStore.table.params.runF != '') {
tableStore.table.params.runFlag = [tableStore.table.params.runF] tableStore.table.params.runFlag = tableStore.table.params.runF
} }
tableStore.table.params.comFlag = [] tableStore.table.params.comFlag = []
if (tableStore.table.params.comF != null&&tableStore.table.params.comF != '') { if (tableStore.table.params.comF != null && tableStore.table.params.comF != '') {
tableStore.table.params.comFlag = [tableStore.table.params.comF] tableStore.table.params.comFlag = tableStore.table.params.comF
} }
} }
}) })
@@ -220,7 +225,6 @@ tableStore.table.params.scale = []
tableStore.table.params.manufacturer = [] tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = [] tableStore.table.params.loadType = []
provide('tableStore', tableStore) provide('tableStore', tableStore)
onMounted(() => { onMounted(() => {
tableStore.index() tableStore.index()

View File

@@ -300,7 +300,7 @@ const list: any = ref([
]) ])
const countList: any = ref([ const countList: any = ref([
{ {
title: '冀北', title: '网公司',
children: [ children: [
{ {
title: '电网侧监测点', title: '电网侧监测点',

View File

@@ -3,28 +3,38 @@
<DatePicker ref="datePickerRef" style="display: none" theCurrentTime /> <DatePicker ref="datePickerRef" style="display: none" theCurrentTime />
<el-page-header :icon="ArrowLeft" @back="emit('back')"> <el-page-header :icon="ArrowLeft" @back="emit('back')">
<template #content> <template #content>
<span style="font-size: 16px">{{ dropList.lineName }}详情 </span> <span style="">{{ dropList.gdName }}_{{ dropList.bdName }}_{{ dropList.lineName }}</span>
<span style="font-weight: 500">最新数据时间</span> <span style="font-weight: 500" class="ml20">最新数据时间</span>
<span style="color: var(--color-primary-default)">{{ dropList.updateTime }}</span> <span style="color: var(--el-color-primary)">{{ dropList.updateTime }}</span>
<span style="font-weight: 500" class="ml20">统计日期</span>
<span style="color: var(--el-color-primary)">
{{ getTimeOfTheMonth('3')[0] + '至' + getTimeOfTheMonth('3')[1] }}
</span>
</template> </template>
</el-page-header> </el-page-header>
<el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`"> <el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`">
<el-col :span="8"> <el-col :span="8">
<h3 class="mb10 iconBox"> <h3 class="mb10 iconBox " >
<span></span> <span></span>
台账信息 台账信息
</h3> </h3>
<el-descriptions title="" border :column="2"> <el-descriptions title="" label-width="100px" border :column="2" size="small">
<el-descriptions-item label="监测点名称" width="140px"> <el-descriptions-item label="变电站名称">
{{ dropList.bdName }}
</el-descriptions-item>
<el-descriptions-item label="监测点名称">
{{ dropList.lineName }} {{ dropList.lineName }}
</el-descriptions-item> </el-descriptions-item>
<el-descriptions-item label="监测对象名称">
{{ dropList.objName }}
</el-descriptions-item>
<el-descriptions-item label="所属厂家">{{ dropList.manufacturer }}</el-descriptions-item> <el-descriptions-item label="所属厂家">{{ dropList.manufacturer }}</el-descriptions-item>
<el-descriptions-item label="电压等级">{{ dropList.scale }}</el-descriptions-item> <el-descriptions-item label="电压等级">{{ dropList.scale }}</el-descriptions-item>
<el-descriptions-item label="投运日期">{{ dropList.loginTime }}</el-descriptions-item> <el-descriptions-item label="投运日期">{{ dropList.loginTime }}</el-descriptions-item>
<el-descriptions-item label="PT">{{ dropList.pt }}</el-descriptions-item> <!-- <el-descriptions-item label="PT">{{ dropList.pt }}</el-descriptions-item>
<el-descriptions-item label="CT">{{ dropList.ct }}</el-descriptions-item> <el-descriptions-item label="CT">{{ dropList.ct }}</el-descriptions-item> -->
<el-descriptions-item label="干扰源类型">{{ dropList.loadType }}</el-descriptions-item> <el-descriptions-item label="干扰源类型">{{ dropList.loadType }}</el-descriptions-item>
<el-descriptions-item label="通讯状态" width="140px"> <el-descriptions-item label="通讯状态">
<el-tag size="small" :type="dropList.comFlag == '正常' ? 'success' : 'danger'" effect="dark"> <el-tag size="small" :type="dropList.comFlag == '正常' ? 'success' : 'danger'" effect="dark">
{{ dropList.comFlag }} {{ dropList.comFlag }}
</el-tag> </el-tag>
@@ -32,22 +42,33 @@
</el-descriptions> </el-descriptions>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<h3 class="mb10 iconBox"> <h3
class="mb10 iconBox "
>
<span></span> <span></span>
告警明细 () 告警天数
</h3> </h3>
<el-descriptions title="" border :column="2" size="small"> <el-descriptions title="" border :column="2" size="small">
<el-descriptions-item width="140px" label="告警原因"> <el-descriptions-item width="140px" label="告警原因">
<span style="font-weight: 550" <span
:style="TargetData.info == 0 ? 'color: #0e8780;' : TargetData.info == 3 ? 'color: #000' : 'color: #ff0000;'"> style="font-weight: 550"
:style="
TargetData.info == 0
? 'color: #0e8780;'
: TargetData.info == 3
? 'color: #000'
: 'color: #ff0000;'
"
>
{{ {{
TargetData.info == 1 TargetData.info == 1
? '超标告警' ? '超标告警'
: TargetData.info == 2 : TargetData.info == 2
? '完整性告警' ? '完整性告警'
: TargetData.info == 0 : TargetData.info == 0
? '无告警' ? '无告警'
: '暂无数据' : '暂无数据'
}} }}
</span> </span>
</el-descriptions-item> </el-descriptions-item>
@@ -72,72 +93,27 @@
数据质量 数据质量
</h3> </h3>
<div style="display: flex"> <div style="display: flex">
<MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="ComCharts" @click="Integrity" /> <MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="ComCharts" />
<MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="onLineCharts" <MyEChart
@click="OnlineRate" /> :style="`height: calc(${rowHeight} - 31px)`"
:options="onLineCharts"
/>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`"> <el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`">
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
监测点总体评价结论
</h3>
<div class="evaluationData">
<el-row style="width: 96%" class="row pb5">
<el-col :span="12" style="display: flex">
<span>{{ dropList.lineName }}</span>
</el-col>
<el-col :span="12" style="display: flex">
<div>
综合评估得分:
<span class="conclusion" :class="dropList.assessData == '特质'
? 'background1'
: dropList.assessData == '较差'
? 'background2'
: dropList.assessData == '极差'
? 'background3'
: ''
">
{{ dropList.assessData }}
</span>
</div>
</el-col>
</el-row>
<el-row style="width: 96%" v-for="(item, i) in evaluationData" class="row pb4 pt3">
<el-col :span="14" style="display: flex; align-items: center">
<img :src="url[i]" />
<span style="line-height: 20px">{{ item.targetName }}</span>
</el-col>
<el-col :span="10" style="display: flex; align-items: center">
<div style="width: 100%">
评估得分
<span class="conclusion" :class="item.avg == '特质'
? 'background1'
: item.avg == '较差'
? 'background2'
: item.avg == '极差'
? 'background3'
: ''
">
{{ item.avg }}
</span>
</div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="8"> <el-col :span="8">
<h3 class="mb10 iconBox"> <h3 class="mb10 iconBox ">
<span></span> <span></span>
稳态指标合格率 稳态指标合格率
</h3> </h3>
<div :style="`height: calc(${rowHeight} - 31px)`" ref="chartRef"></div>
<div :style="`height: calc(${rowHeight} - 31px); `" ref="chartRef"></div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<h3 class="mb10 iconBox"> <h3 class="mb10 iconBox" >
<span></span> <span></span>
暂态事件统计 暂态事件统计
</h3> </h3>
@@ -167,6 +143,7 @@ import DatePicker from '@/components/form/datePicker/index.vue'
import MyEChart from '@/components/echarts/MyEchart.vue' import MyEChart from '@/components/echarts/MyEchart.vue'
import echarts from '@/components/echarts/echarts' import echarts from '@/components/echarts/echarts'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { getTimeOfTheMonth } from '@/utils/formatTime'
const router = useRouter() const router = useRouter()
import { getLineDetailData } from '@/api/advance-boot/bearingCapacity' import { getLineDetailData } from '@/api/advance-boot/bearingCapacity'
import { import {
@@ -175,14 +152,14 @@ import {
lineQualifiedDetail, lineQualifiedDetail,
getLineAssess, getLineAssess,
getEventDetailByLineId, getEventDetailByLineId,
getGridDiagramTargetData getGridDiagramTargetData,
} from '@/api/device-boot/panorama' } from '@/api/device-boot/panorama'
import { formatter } from 'element-plus' import { formatter } from 'element-plus'
const loading=ref(false)
const emit = defineEmits(['back']) const emit = defineEmits(['back'])
const dropList: any = ref({}) const dropList: any = ref({})
const TargetData: any = ref({}) const TargetData: any = ref({})
const evaluationData: any = ref([])
const incidentCharts: any = ref({}) const incidentCharts: any = ref({})
const ComCharts: any = ref({}) const ComCharts: any = ref({})
const onLineCharts: any = ref({}) const onLineCharts: any = ref({})
@@ -362,42 +339,8 @@ const open = async (id: string) => {
} }
} }
}) })
loading.value = true
// 监测点总体评价结论
getLineAssess({
lineId: id,
startTime: datePickerRef.value.timeValue[0],
endTime: datePickerRef.value.timeValue[1]
}).then((res: any) => {
dropList.value.assessData = res.data.assessLevel
evaluationData.value = [
{
targetName: '频率偏差(Hz)',
avg: res.data.freqAssessLevel,
sd: res.data.freqQualifyData
},
{
targetName: '电压偏差(%)',
avg: res.data.vdevAssessLevel,
sd: res.data.vdevQualifyData
},
{
targetName: '电压总谐波畸变率(%)',
avg: res.data.harmAssessLevel,
sd: res.data.harmQualifyData
},
{
targetName: '三相电压不平衡度(%)',
avg: res.data.unbalanceAssessLevel,
sd: res.data.unbalanceQualifyData
},
{
targetName: '闪变',
avg: res.data.flickerAssessLevel,
sd: res.data.flickerQualifyData
}
]
})
// 稳态指标合格率 // 稳态指标合格率
lineQualifiedDetail({ lineQualifiedDetail({
@@ -522,7 +465,7 @@ const open = async (id: string) => {
if (res.data[k] != '/') { if (res.data[k] != '/') {
judgment = false judgment = false
} }
flag += (res.data[k] == '/' ? 0 : res.data[k]) flag += res.data[k] == '/' ? 0 : res.data[k]
} }
} }
@@ -633,7 +576,7 @@ const echart = (row: any) => {
}, },
indicator: indicator indicator: indicator
}, },
color: color,
series: [] series: []
} }
@@ -642,32 +585,25 @@ const echart = (row: any) => {
name: item.time, name: item.time,
type: 'radar', type: 'radar',
symbol: 'none', symbol: 'none',
areaStyle: { areaStyle: {
normal: { opacity: 0.6, // 调整透明度,避免重叠遮挡
color: '#2a9fe069' color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
} { offset: 0, color: `${color[i]}50` },
{ offset: 1, color: `${color[i]}50` } // 渐变透明
])
}, },
itemStyle: { lineStyle: {
color: '#2a9fe0' color: color[i],
width: 2
}, },
data: [item.ratioList] data: [item.ratioList]
}) })
}) })
// console.log("🚀 ~ echart ~ option:", option)
chart.setOption(option) chart.setOption(option)
} }
// 跳转
const Integrity = () => {
router.push({
name: 'harmonic-boot/harmonic/getIntegrityData'
})
}
const OnlineRate = () => {
router.push({
name: 'harmonic-boot/area/OnlineRate'
})
}
onMounted(() => { onMounted(() => {
// open('4c87b7dff2281254fc55c25a4da31506') // open('4c87b7dff2281254fc55c25a4da31506')
@@ -708,7 +644,7 @@ defineExpose({ open })
.iconBox { .iconBox {
display: flex; display: flex;
align-items: center;
span { span {
display: inline-block; display: inline-block;
width: 3px; width: 3px;
@@ -737,7 +673,16 @@ defineExpose({ open })
} }
.background3 { .background3 {
background-color: #A52a2a; background-color: #a52a2a;
color: #fff; color: #fff;
} }
:deep(.el-table--small .el-table__cell) {
padding: 2px 0 !important;
}
.text-style {
cursor: pointer;
text-decoration: underline;
text-decoration-color: var(--el-color-primary);
text-underline-offset: 4px;
}
</style> </style>

View File

@@ -0,0 +1,743 @@
<template>
<div class="default-main lineInfo" :style="height">
<DatePicker ref="datePickerRef" style="display: none" theCurrentTime />
<el-page-header :icon="ArrowLeft" @back="emit('back')">
<template #content>
<span style="font-size: 16px">{{ dropList.objName ? dropList.objName + '_' : '' }}{{ dropList.lineName }}详情 </span>
<span style="font-weight: 500">最新数据时间</span>
<span style="color: var(--color-primary-default)">{{ dropList.updateTime }}</span>
</template>
</el-page-header>
<el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`">
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
台账信息
</h3>
<el-descriptions title="" border :column="2">
<el-descriptions-item label="监测点名称" width="140px">
{{ dropList.lineName }}
</el-descriptions-item>
<el-descriptions-item label="所属厂家">{{ dropList.manufacturer }}</el-descriptions-item>
<el-descriptions-item label="电压等级">{{ dropList.scale }}</el-descriptions-item>
<el-descriptions-item label="投运日期">{{ dropList.loginTime }}</el-descriptions-item>
<el-descriptions-item label="PT">{{ dropList.pt }}</el-descriptions-item>
<el-descriptions-item label="CT">{{ dropList.ct }}</el-descriptions-item>
<el-descriptions-item label="干扰源类型">{{ dropList.loadType }}</el-descriptions-item>
<el-descriptions-item label="通讯状态" width="140px">
<el-tag size="small" :type="dropList.comFlag == '正常' ? 'success' : 'danger'" effect="dark">
{{ dropList.comFlag }}
</el-tag>
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
告警明细 ()
</h3>
<el-descriptions title="" border :column="2" size="small">
<el-descriptions-item width="140px" label="告警原因">
<span style="font-weight: 550"
:style="TargetData.info == 0 ? 'color: #0e8780;' : TargetData.info == 3 ? 'color: #000' : 'color: #ff0000;'">
{{
TargetData.info == 1
? '超标告警'
: TargetData.info == 2
? '完整性告警'
: TargetData.info == 0
? '无告警'
: '暂无数据'
}}
</span>
</el-descriptions-item>
<el-descriptions-item label="频率偏差">{{ TargetData.freqDevOvertime }}</el-descriptions-item>
<el-descriptions-item label="电压偏差">{{ TargetData.voltageDevOvertime }}</el-descriptions-item>
<el-descriptions-item label="谐波电流">{{ TargetData.iharmOvertime }}</el-descriptions-item>
<el-descriptions-item label="负序电流">{{ TargetData.inegOvertime }}</el-descriptions-item>
<el-descriptions-item label="间谐波电压">{{ TargetData.inuharmOvertime }}</el-descriptions-item>
<el-descriptions-item label="电压总谐波畸变率">
{{ TargetData.uaberranceOvertime }}
</el-descriptions-item>
<el-descriptions-item label="闪变">{{ TargetData.flickerOvertime }}</el-descriptions-item>
<el-descriptions-item label="谐波电压">{{ TargetData.uharmOvertime }}</el-descriptions-item>
<el-descriptions-item width="140px" label="三相电压不平衡度">
{{ TargetData.ubalanceOvertime }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
数据质量
</h3>
<div style="display: flex">
<MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="ComCharts" @click="Integrity" />
<MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="onLineCharts"
@click="OnlineRate" />
</div>
</el-col>
</el-row>
<el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`">
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
监测点总体评价结论
</h3>
<div class="evaluationData">
<el-row style="width: 96%" class="row pb5">
<el-col :span="12" style="display: flex">
<span>{{ dropList.lineName }}</span>
</el-col>
<el-col :span="12" style="display: flex">
<div>
综合评估得分:
<span class="conclusion" :class="dropList.assessData == '特质'
? 'background1'
: dropList.assessData == '较差'
? 'background2'
: dropList.assessData == '极差'
? 'background3'
: ''
">
{{ dropList.assessData }}
</span>
</div>
</el-col>
</el-row>
<el-row style="width: 96%" v-for="(item, i) in evaluationData" class="row pb4 pt3">
<el-col :span="14" style="display: flex; align-items: center">
<img :src="url[i]" />
<span style="line-height: 20px">{{ item.targetName }}</span>
</el-col>
<el-col :span="10" style="display: flex; align-items: center">
<div style="width: 100%">
评估得分
<span class="conclusion" :class="item.avg == '特质'
? 'background1'
: item.avg == '较差'
? 'background2'
: item.avg == '极差'
? 'background3'
: ''
">
{{ item.avg }}
</span>
</div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
稳态指标合格率
</h3>
<div :style="`height: calc(${rowHeight} - 31px)`" ref="chartRef"></div>
</el-col>
<el-col :span="8">
<h3 class="mb10 iconBox">
<span></span>
暂态事件统计
</h3>
<MyEChart :style="`height: calc(${rowHeight} - 31px)`" :options="incidentCharts" />
</el-col>
</el-row>
<el-row :gutter="20" class="mt10" :style="`height:${rowHeight}`">
<el-col :span="24">
<h3 class="mb10 iconBox">
<span></span>
历史趋势图
</h3>
<history :lineId="lineId" ref="historyRef" />
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { onMounted, reactive, ref, provide } from 'vue'
import { ArrowLeft } from '@element-plus/icons-vue'
import { mainHeight } from '@/utils/layout'
import history from './history.vue'
import { color } from '@/components/echarts/color'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEChart from '@/components/echarts/MyEchart.vue'
import echarts from '@/components/echarts/echarts'
import { useRouter } from 'vue-router'
const router = useRouter()
import { getLineDetailData } from '@/api/advance-boot/bearingCapacity'
import {
getTotalIntegrityByLineIds,
getTotalOnlineRates,
lineQualifiedDetail,
getLineAssess,
getEventDetailByLineId,
getGridDiagramTargetData
} from '@/api/device-boot/panorama'
import { formatter } from 'element-plus'
const emit = defineEmits(['back'])
const dropList: any = ref({})
const TargetData: any = ref({})
const evaluationData: any = ref([])
const incidentCharts: any = ref({})
const ComCharts: any = ref({})
const onLineCharts: any = ref({})
const datePickerRef = ref()
const chartRef = ref<HTMLDivElement>()
const historyRef = ref()
const IntegrityNum = ref(0)
const url: any = [
new URL(`@/assets/img/PLPC.png`, import.meta.url),
new URL(`@/assets/img/DYPC.png`, import.meta.url),
new URL(`@/assets/img/JBL.png`, import.meta.url),
new URL(`@/assets/img/SXDY.png`, import.meta.url),
new URL(`@/assets/img/SB.png`, import.meta.url)
]
const lineId: any = ref('')
const height = mainHeight(20)
const rowHeight = mainHeight(190, 3).height
// 查询
const open = async (id: string) => {
let form = {
comFlag: 1,
endTime: datePickerRef.value.timeValue[1],
lineIds: [id],
ids: [id],
searchValue: '',
startTime: datePickerRef.value.timeValue[0]
}
lineId.value = id
const { data } = await getLineDetailData({ id: id })
dropList.value = data
// 运行状态
// 完整性
getTotalIntegrityByLineIds(form).then((res: any) => {
let num = (res.data || 0) / 100
IntegrityNum.value = res.data
ComCharts.value = {
title: {
text: '完整性',
bottom: '10%',
left: 'center',
textStyle: {
fontSize: 16
}
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
//第二个球的填充
type: 'liquidFill',
radius: '65%',
center: ['50%', '40%'], //中心点
color: [
{
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 1,
color: '#2aa1e3'
}
],
globalCoord: false
}
],
data: [num, num], // data个数代表波浪数
backgroundStyle: {
borderWidth: 1,
color: '#f7f8fc'
},
label: {
normal: {
formatter: () => {
return (num * 100).toFixed(2) + '%'
},
textStyle: {
fontSize: 20,
color: '#000'
}
}
},
outline: {
// show: false
borderDistance: 0,
itemStyle: {
borderWidth: 2,
borderColor: '#fff'
}
}
}
]
}
}
// 稳态指标合格率
})
// 在线率
getTotalOnlineRates({ ...form, id: dropList.value.devId, ids: [dropList.value.devId] }).then((res: any) => {
let num = (res.data || 0) / 100
onLineCharts.value = {
title: {
text: '在线率',
bottom: '10%',
left: 'center',
textStyle: {
fontSize: 16
}
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
//第二个球的填充
type: 'liquidFill',
radius: '65%',
center: ['50%', '40%'], //中心点
color: [
{
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 1,
color: '#67c23a'
}
],
globalCoord: false
}
],
data: [num, num], // data个数代表波浪数
backgroundStyle: {
color: '#f7f8fc'
},
label: {
normal: {
formatter: () => {
return (num * 100).toFixed(2) + '%'
},
textStyle: {
fontSize: 20,
color: '#000'
}
}
},
outline: {
// show: false
borderDistance: 0,
itemStyle: {
borderWidth: 2,
borderColor: '#fff'
}
}
}
]
}
}
})
// 监测点总体评价结论
getLineAssess({
lineId: id,
startTime: datePickerRef.value.timeValue[0],
endTime: datePickerRef.value.timeValue[1]
}).then((res: any) => {
dropList.value.assessData = res.data.assessLevel
evaluationData.value = [
{
targetName: '频率偏差(Hz)',
avg: res.data.freqAssessLevel,
sd: res.data.freqQualifyData
},
{
targetName: '电压偏差(%)',
avg: res.data.vdevAssessLevel,
sd: res.data.vdevQualifyData
},
{
targetName: '电压总谐波畸变率(%)',
avg: res.data.harmAssessLevel,
sd: res.data.harmQualifyData
},
{
targetName: '三相电压不平衡度(%)',
avg: res.data.unbalanceAssessLevel,
sd: res.data.unbalanceQualifyData
},
{
targetName: '闪变',
avg: res.data.flickerAssessLevel,
sd: res.data.flickerQualifyData
}
]
})
// 稳态指标合格率
lineQualifiedDetail({
lineId: id,
startTime: datePickerRef.value.timeValue[0],
endTime: datePickerRef.value.timeValue[1]
}).then(res => {
echart([
{
time: datePickerRef.value.timeValue[0].substring(0, 7),
targetList: [
'频率偏差(Hz)',
'电压偏差(%)',
'电压总谐波畸变率(%)',
'三相电压不平衡度(%)',
'闪变',
'谐波电压(%)',
'谐波电流(%)',
'间谐波电压(%)',
'负序电流(A)'
],
ratioList: [
res.data.freqDev == 3.14159 ? null : res.data.freqDev,
res.data.vdev == 3.14159 ? null : res.data.vdev,
res.data.vthd == 3.14159 ? null : res.data.vthd,
res.data.ubalance == 3.14159 ? null : res.data.ubalance,
res.data.plt == 3.14159 ? null : res.data.plt,
res.data.uharm == 3.14159 ? null : res.data.uharm,
res.data.iharm == 3.14159 ? null : res.data.iharm,
res.data.inuHarm == 3.14159 ? null : res.data.inuHarm,
res.data.ineg == 3.14159 ? null : res.data.ineg
]
}
])
})
// 暂态事件统计
getEventDetailByLineId({
id: id,
startTime: datePickerRef.value.timeValue[0],
endTime: datePickerRef.value.timeValue[1],
type: datePickerRef.value.interval
}).then((res: any) => {
let data = [
{
name: '电压暂升',
value: res.data?.swellTimes || 0
},
{
name: '电压暂降',
value: res.data?.sagTimes || 0
},
{
name: '电压中断',
value: res.data?.interruptTimes || 0
}
]
incidentCharts.value = {
title: {
text: '总数:' + (data[0].value + data[1].value + data[2].value),
left: '40%',
top: '45%',
textStyle: {
// fontWeight: 600,
fontSize: 12
}
// subtext: '总数',
// subtextStyle: {
// fontWeight: 550,
// fontSize: 14
// }
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
top: 'center',
right: '10%',
formatter: function (e: any) {
return e + ' ' + data.filter(item => item.name == e)[0].value + '条'
}
},
xAxis: {
show: false
},
yAxis: {
show: false
},
options: {
dataZoom: null,
series: [
{
type: 'pie',
center: ['45%', '50%'],
radius: ['60%', '80%'],
label: {
show: false,
position: 'outside',
textStyle: {
//数值样式
}
},
data: data
}
]
}
}
})
// 告警明细
getGridDiagramTargetData({ ...form, id: id, type: 3 }).then(res => {
TargetData.value = res.data
let num = 0
let flag = 0
let judgment = true
for (let k in res.data) {
if (k != 'lineId') {
if (res.data[k] != '/') {
judgment = false
}
flag += (res.data[k] == '/' ? 0 : res.data[k])
}
}
if (IntegrityNum.value == 0) {
num = 2 //完整性告警
} else {
if (flag > 0) {
num = 1 //超标告警
} else {
num = 0 //无告警
}
if (judgment) {
num = 3
}
}
TargetData.value.info = num
})
}
const echart = (row: any) => {
let chart = echarts.init(chartRef.value as HTMLDivElement)
let dataname = [
'频率偏差(Hz)',
'电压偏差(%)',
'电压总谐波畸变率(%)',
'三相电压不平衡度(%)',
'闪变',
'谐波电压(%)',
'谐波电流(%)',
'间谐波电压(%)',
'负序电流(A)'
]
let datamax = [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100]
let indicator = []
for (let i = 0; i < dataname.length; i++) {
indicator.push({
name: dataname[i],
max: datamax[i]
})
}
let option: any = {
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0
},
legend: {
data: row.map((item: any) => item.time),
type: 'scroll',
orient: 'vertical',
icon: 'roundRect',
right: '20',
itemGap: 10,
itemWidth: 16,
itemHeight: 16,
textStyle: {
fontSize: '15',
color: '#656565'
}
},
radar: {
center: ['50%', '50%'],
radius: '65%',
startAngle: 90,
splitNumber: 5,
splitArea: {
areaStyle: {
color: ['#FFFFFF', '#F5F9FF'].reverse()
}
},
axisLabel: {
show: false
},
axisLine: {
show: true,
lineStyle: {
color: '#D2E4F8'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#D2E4F8'
}
},
name: {
formatter: '{value}',
textStyle: {
color: '#656565',
fontSize: 15
}
},
indicator: indicator
},
series: []
}
row.forEach((item: any, i: any) => {
option.series.push({
name: item.time,
type: 'radar',
symbol: 'none',
areaStyle: {
normal: {
color: '#2a9fe069'
}
},
itemStyle: {
color: '#2a9fe0'
},
data: [item.ratioList]
})
})
// console.log("🚀 ~ echart ~ option:", option)
chart.setOption(option)
}
// 跳转
const Integrity = () => {
router.push({
name: 'harmonic-boot/harmonic/getIntegrityData'
})
}
const OnlineRate = () => {
router.push({
name: 'harmonic-boot/area/OnlineRate'
})
}
onMounted(() => {
// open('4c87b7dff2281254fc55c25a4da31506')
})
defineExpose({ open })
</script>
<style lang="scss" scoped>
.lineInfo {
padding: 0 10px 10px 10px;
}
:deep(.el-page-header__header) {
height: 45px;
border-bottom: 1px solid #f1eded;
}
:deep(.el-descriptions__header) {
margin-bottom: 10px;
}
.evaluationData {
display: grid;
grid-template-rows: repeat(5, auto);
height: 87%;
.row {
margin: 4px 2% 0;
width: 100%;
box-shadow: 1px 1px 1px 1px #e8e3e3;
}
img {
width: 6%;
margin: 0px 15px;
}
}
.iconBox {
display: flex;
span {
display: inline-block;
width: 3px;
height: 18px;
background: var(--el-color-primary);
margin-right: 5px;
margin-left: 3px;
}
}
.conclusion {
display: inline-block;
padding: 2px 5px;
height: 20px;
border-radius: 4px;
}
.background1 {
background-color: #339966;
color: #fff;
}
.background2 {
background-color: #97017e;
color: #fff;
}
.background3 {
background-color: #A52a2a;
color: #fff;
}
</style>

View File

@@ -7,7 +7,7 @@
v-model.trim="inputQuery" v-model.trim="inputQuery"
style="height: 46px; width: 334px" style="height: 46px; width: 334px"
@keyup.enter="DeviceQ" @keyup.enter="DeviceQ"
placeholder="请输入终端名称" placeholder="请输入监测点相关信息"
> >
<template #prefix> <template #prefix>
<div class="Icon"></div> <div class="Icon"></div>
@@ -37,7 +37,7 @@
@click="flyTo(k)" @click="flyTo(k)"
> >
<p>{{ k.psrName }}</p> <p>{{ k.psrName }}</p>
<p>{{ k.vlevelName }}|{{ k.maintOrgName }}</p> <p>{{ k.vlevelName }} | {{ k.maintOrgName }} {{ k.objName ? `| ${k.objName}` : '' }}</p>
</div> </div>
</div> </div>
</el-collapse-item> </el-collapse-item>
@@ -484,6 +484,9 @@ const lookPoint = (e: any) => {
emit('show', true) emit('show', true)
} }
// 搜索 // 搜索
const matchLineItem = (item: any, regex: RegExp) =>
regex.test(item.lineName) || (item.objName && regex.test(item.objName))
const DeviceQ = () => { const DeviceQ = () => {
showCollapse.value = true showCollapse.value = true
if (inputQuery.value.length == 0) return if (inputQuery.value.length == 0) return
@@ -491,13 +494,14 @@ const DeviceQ = () => {
let list = [] let list = []
let regex = new RegExp(inputQuery.value, 'i') let regex = new RegExp(inputQuery.value, 'i')
let data = areaLineInfo.value let data = areaLineInfo.value
.filter((item: any) => regex.test(item.lineName)) .filter((item: any) => matchLineItem(item, regex))
.map((item: any) => { .map((item: any) => {
return { return {
psrName: item.lineName, psrName: item.lineName,
vlevelName: item.voltageScale, vlevelName: item.voltageScale,
maintOrgName: item.gdName, maintOrgName: item.gdName,
coordinate: [item.lng, item.lat] coordinate: [item.lng, item.lat],
objName: item.objName
} }
}) })
// data.replace(//s/g,',') // data.replace(//s/g,',')
@@ -522,7 +526,7 @@ const flyTo = (e: any, zoom?: number) => {
zoomMap.value = zoom zoomMap.value = zoom
} else { } else {
zoomMap.value = 15 zoomMap.value = 15
let data = areaLineInfo.value.filter((item: any) => regex.test(item.lineName))[0] let data = areaLineInfo.value.filter((item: any) => matchLineItem(item, regex))[0]
if (data) { if (data) {
markerClick(data) markerClick(data)
} }

View File

@@ -10,8 +10,7 @@
<img src="@/assets/img/FGX.png" /> <img src="@/assets/img/FGX.png" />
</div> </div>
<div style="display: flex"> <div style="display: flex">
<div v-for="(item, i) in list" class="cardBox" :style="i == 1 ? 'flex:1.3' : ''"> <div v-for="(item, i) in list" class="cardBox" :style="i == 1 ? 'flex:1.2' : i === 2 ? 'flex: 1.3' : ''"> <div class="card">
<div class="card">
<span style="cursor: pointer" @click="GridDiagram(i)">{{ item.title }}</span> <span style="cursor: pointer" @click="GridDiagram(i)">{{ item.title }}</span>
<span <span
:style="`color: ${item.color[0]}; cursor:pointer`" :style="`color: ${item.color[0]}; cursor:pointer`"
@@ -30,10 +29,10 @@
</div> </div>
<!-- 监测规模 列表 --> <!-- 监测规模 列表 -->
<div> <div>
<div class="vcl mt5"> <div class="vcl mt2">
<p <p
v-for="(item, i) in vList" v-for="(item, i) in displayVList"
:style="i == 0 ? 'width: 60px' : i == vList?.length - 1 ? 'width: 32px' : 'flex:1'" :style="i == 0 ? 'width: 60px' : i == displayVList?.length - 1 ? IS_LN ? 'flex:1' : 'width: 32px' : 'flex:1'"
> >
{{ item }} {{ item }}
</p> </p>
@@ -44,7 +43,7 @@
{{ item.title }} {{ item.title }}
</p> </p>
<p <p
v-for="(k, i) in vList?.slice(0, vList.length - 2)" v-for="(k, i) in dataVList"
class="numOne" class="numOne"
@click="LookMap(item.list[i].numOneList, item.list[i].numTwoList, 0)" @click="LookMap(item.list[i].numOneList, item.list[i].numTwoList, 0)"
> >
@@ -59,7 +58,7 @@
<p class="numOne" @click="LookMap(item.list[3].numOneList, item.list[3].numTwoList, 0)"> <p class="numOne" @click="LookMap(item.list[3].numOneList, item.list[3].numTwoList, 0)">
{{ item.list[3].numOne }} {{ item.list[3].numOne }}
</p> --> </p> -->
<p <p v-if="!IS_LN"
style="font-size: 12px; width: 32px; cursor: pointer; color: var(--el-color-primary)" style="font-size: 12px; width: 32px; cursor: pointer; color: var(--el-color-primary)"
@click.stop="open(i)" @click.stop="open(i)"
> >
@@ -69,16 +68,16 @@
</div> </div>
</div> </div>
<!-- 监测点指标统计 --> <!-- 监测点指标统计 -->
<div :style="`height:calc(${boxHeight.height} + 50px)`"> <div :style="`height:calc(${boxHeight.height} + 10px)`" >
<div class="title"> <div class="title">
<span>监测点指标统计</span> <span>监测点指标统计</span>
</div> </div>
<div style="display: flex" class="mt2"> <div style="display: flex" class="mt2">
<img src="@/assets/img/FGX.png" /> <img src="@/assets/img/FGX.png" />
</div> </div>
<div :style="`height:calc(${boxHeight.height} + 20px);overflow-y: auto;`"> <div :style="`height:calc(${boxHeight.height} );overflow-y: auto;`">
<div v-for="item in countList"> <div v-for="item in countList">
<div class="title mt5" style="font-weight: 500"> <div class="title mt3" style="font-weight: 500">
<img src="@/assets/img/TJ.png" /> <img src="@/assets/img/TJ.png" />
{{ item.title }} {{ item.title }}
</div> </div>
@@ -110,7 +109,7 @@
</div> </div>
</div> </div>
<!-- 监测点指标统计 --> <!-- 监测点指标统计 -->
<div :style="`height:calc(${boxHeight.height} - 55px)`"> <div :style="`height:calc(${boxHeight.height} - 75px)`" class="mt20">
<div class="title"> <div class="title">
<span>监测运行统计</span> <span>监测运行统计</span>
</div> </div>
@@ -166,7 +165,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, reactive, ref, provide } from 'vue' import { onMounted, reactive, ref, provide, computed } from 'vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { ArrowRight, View } from '@element-plus/icons-vue' import { ArrowRight, View } from '@element-plus/icons-vue'
@@ -178,15 +177,53 @@ import {
getGridDiagramMonitor, getGridDiagramMonitor,
getGridDiagramDev, getGridDiagramDev,
getGridDiagramStatistics, getGridDiagramStatistics,
getGridDiagramRunData getGridDiagramRunData, getAreaObjAlarm
} from '@/api/device-boot/panorama' } from '@/api/device-boot/panorama'
const emit = defineEmits(['LookMap', 'GridDiagram']) const emit = defineEmits(['LookMap', 'GridDiagram'])
const IS_LN = import.meta.env.VITE_NAME == 'LN' || import.meta.env.VITE_NAME == 'LNqr'
const dictData = useDictData() const dictData = useDictData()
const show = ref(false) const show = ref(false)
const standRef = ref() const standRef = ref()
const terminalRef = ref() const terminalRef = ref()
const pointRef = ref() const pointRef = ref()
const list: any = ref([ const list: any = ref([
{
title: '场站',
color: ['#000', '#bd3124'],
list: [
{
numOne: 0,
numTwo: 0,
numOneList: [],
numTwoList: []
},
{
numOne: 0,
numTwo: 0,
numOneList: [],
numTwoList: []
},
{
numOne: 0,
numTwo: 0,
numOneList: [],
numTwoList: []
},
{
numOne: 0,
numTwo: 0,
numOneList: [],
numTwoList: []
},
{
numOne: 0,
numTwo: 0,
numOneList: [],
numTwoList: []
}
]
},
{ {
title: '变电站', title: '变电站',
color: ['#000', '#bd3124'], color: ['#000', '#bd3124'],
@@ -300,7 +337,7 @@ const list: any = ref([
]) ])
const countList: any = ref([ const countList: any = ref([
{ {
title: '冀北', title: '网公司',
children: [ children: [
{ {
title: '电网侧监测点', title: '电网侧监测点',
@@ -355,6 +392,10 @@ const legengList = [
] ]
const panoramicVoltage: any = dictData.getBasicData('Dev_Voltage_Stand') const panoramicVoltage: any = dictData.getBasicData('Dev_Voltage_Stand')
const vList = ref(['', '500kV', '220kV', '110kV', '35kV', '']) const vList = ref(['', '500kV', '220kV', '110kV', '35kV', ''])
const displayVList = computed(() => (IS_LN && vList.value.length ? vList.value.slice(0, -1) : vList.value))
const dataVList = computed(() =>
IS_LN ? vList.value.slice(1, -1) : vList.value.slice(0, vList.value.length - 2)
)
const formRow: any = ref({}) const formRow: any = ref({})
const height = mainHeight(30) const height = mainHeight(30)
const boxHeight = mainHeight(290, 2) const boxHeight = mainHeight(290, 2)
@@ -383,8 +424,8 @@ const info = async (row: any) => {
countList.value[0].title = row.areaName countList.value[0].title = row.areaName
formRow.value = form formRow.value = form
vList.value = [''] vList.value = ['']
// 变电站
getSubLineGiveAnAlarm(form).then(res => { getAreaObjAlarm(form).then(res => {
let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info
data[0].data.forEach((item: any) => { data[0].data.forEach((item: any) => {
if (item.columnName) vList.value.push(panoramicVoltage.find((v: any) => v.id == item.columnName).name) if (item.columnName) vList.value.push(panoramicVoltage.find((v: any) => v.id == item.columnName).name)
@@ -392,16 +433,22 @@ const info = async (row: any) => {
vList.value.push('') vList.value.push('')
list.value[0].list = data[0].data list.value[0].list = data[0].data
}) })
// 变电站
getSubLineGiveAnAlarm(form).then(res => {
let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info
list.value[1].list = data[0].data
})
// 终端 // 终端
getGridDiagramDev(form).then(res => { getGridDiagramDev(form).then(res => {
let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info
list.value[1].list = data[0].data list.value[2].list = data[0].data
}) })
// 监测点 // 监测点
await getGridDiagramMonitor(form).then(res => { await getGridDiagramMonitor(form).then(res => {
let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info let data = row.isUpToGrid == 1 ? res.data.gwInfo : res.data.info
list.value[2].list = data[0].data.map((item: any) => { list.value[3].list = data[0].data.map((item: any) => {
return { return {
numOne: item.num, numOne: item.num,
numTwo: item.onLineNum, numTwo: item.onLineNum,
@@ -464,12 +511,12 @@ defineExpose({ info, show })
.card { .card {
justify-content: center; justify-content: center;
margin-top: 15px; margin-top: 1px;
margin-right: 2%; margin-right: 2%;
display: flex; display: flex;
flex: 1; flex: 1;
align-items: center; align-items: center;
font-size: 16px; font-size: 15px;
span:nth-child(2) { span:nth-child(2) {
font-weight: 550; font-weight: 550;

View File

@@ -302,7 +302,7 @@ const list: any = ref([
]) ])
const countList: any = ref([ const countList: any = ref([
{ {
title: '冀北', title: '网公司',
children: [ children: [
{ {
title: '电网侧监测点', title: '电网侧监测点',

View File

@@ -142,14 +142,14 @@ narimap.publicKey = 'JBb74325ae94dc49358b7d699660b692'
narimap.Require( narimap.Require(
[ [
'PSRMap', 'PSRMap',//pwgdgeomapsdk
'ManageGrid', 'ManageGrid',// pwmagdmapsdk
'Components.Query', 'Components.Query',// EquipSearchCBB
'Components.DeviceCard', 'Components.DeviceCard',//EquipOverviewCBB、EquipDetailCBB
'Popup', 'Popup', //mapsdk
'Components.MapSelector', 'Components.MapSelector',//MapThemeSwitchCBB
'Components.RegionSelector', 'Components.RegionSelector',//OrgSelectorCBB
'Marker' 'Marker' //mapsdk
], ],
// ['PSRMap', 'Components.Query', 'Marker'], // ['PSRMap', 'Components.Query', 'Marker'],
() => { () => {

View File

@@ -314,7 +314,7 @@ const list: any = ref([
]) ])
const countList: any = ref([ const countList: any = ref([
{ {
title: '冀北', title: '网公司',
children: [ children: [
{ {
title: '电网侧监测点', title: '电网侧监测点',

View File

@@ -27,7 +27,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="tableStore.table.params.manufacturer" clearable placeholder="请选择终端厂家"> <el-select v-model="tableStore.table.params.manufacturer" clearable placeholder="请选择终端厂家">
<el-option <el-option
v-for="item in terminaloption" v-for="item in terminaloption"

View File

@@ -27,7 +27,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="终端厂家:"> <el-form-item label="终端厂家">
<el-select v-model="tableStore.table.params.manufacturer" clearable placeholder="请选择终端厂家"> <el-select v-model="tableStore.table.params.manufacturer" clearable placeholder="请选择终端厂家">
<el-option <el-option
v-for="item in terminaloption" v-for="item in terminaloption"

View File

@@ -4,12 +4,8 @@
<template v-slot:select> <template v-slot:select>
<el-form-item label="运行状态"> <el-form-item label="运行状态">
<el-select v-model="tableStore.table.params.lineRunFlag" clearable placeholder="请选择运行状态"> <el-select v-model="tableStore.table.params.lineRunFlag" clearable placeholder="请选择运行状态">
<el-option <el-option v-for="item in runFlagList" :key="item.id" :label="item.name"
v-for="item in runFlagList" :value="item.id"></el-option>
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="筛选数据"> <el-form-item label="筛选数据">
@@ -40,14 +36,8 @@
</div> </div>
</template> </template>
<div class="mb5" style="height: 40px"> <div class="mb5" style="height: 40px">
<el-segmented <el-segmented style="height: 100%" v-model="segmented" :props="props" :options="segmentedList"
style="height: 100%" block @change="tableStore.index()">
v-model="segmented"
:props="props"
:options="segmentedList"
block
@change="tableStore.index()"
>
<template #default="scope"> <template #default="scope">
<div> <div>
<div>{{ scope.item.name }}</div> <div>{{ scope.item.name }}</div>
@@ -61,8 +51,8 @@
segmented == 'Power_Network' segmented == 'Power_Network'
? '区域' ? '区域'
: segmented == 'Manufacturer' : segmented == 'Manufacturer'
? '终端厂家' ? '终端厂家'
: '电网标志' : '电网标志'
}} }}
</span> </span>
<span style="width: 90px">终端总数</span> <span style="width: 90px">终端总数</span>
@@ -77,33 +67,21 @@
{{ o.name }} {{ o.name }}
</span> </span>
<!-- 终端总数 --> <!-- 终端总数 -->
<span <span style="width: 90px; color: #388e3c" class="text text-style"
style="width: 90px; color: #388e3c" @click="renderTable(o.list, o.name + '_')">
class="text text-style"
@click="renderTable(o.list, o.name + '_')"
>
{{ o.count }} {{ o.count }}
</span> </span>
<!-- --> <!-- -->
<span <span style="flex: 1; color: #388e3c" class="text"
style="flex: 1; color: #388e3c" :class="` ${o.integrity < 90 ? 'text-red' : ''}`">
class="text"
:class="` ${o.integrity < 90 ? 'text-red' : ''}`"
>
{{ o.integrity }} {{ o.integrity }}
</span> </span>
<span <span style="width: 80px; color: #388e3c" :class="` ${o.online < 90 ? 'text-red' : ''}`"
style="width: 80px; color: #388e3c" class="text">
:class="` ${o.online < 90 ? 'text-red' : ''}`"
class="text"
>
{{ o.online }} {{ o.online }}
</span> </span>
<span <span style="width: 80px; color: #388e3c" :class="` ${o.qualified > 10 ? 'text-red' : ''}`"
style="width: 80px; color: #388e3c" class="text">
:class="` ${o.qualified > 10 ? 'text-red' : ''}`"
class="text"
>
{{ o.qualified }} {{ o.qualified }}
</span> </span>
</div> </div>
@@ -120,13 +98,8 @@
<!--表格--> <!--表格-->
<div :style="{ height: tableStore.table.height }" v-loading="loading"> <div :style="{ height: tableStore.table.height }" v-loading="loading">
<vxe-table <vxe-table height="auto" :data="dataList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
height="auto" v-bind="defaultAttribute" ref="tableRef" :scroll-y="{ enabled: true }">
:data="dataList.slice((pageNum - 1) * pageSize, pageNum * pageSize)"
v-bind="defaultAttribute"
ref="tableRef"
:scroll-y="{ enabled: true }"
>
<vxe-column type="seq" title="序号" width="80px"> <vxe-column type="seq" title="序号" width="80px">
<template #default="{ rowIndex }"> <template #default="{ rowIndex }">
<span> <span>
@@ -146,19 +119,16 @@
<vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column> <vxe-column field="ip" title="终端IP" :formatter="formatter" width="120px"></vxe-column>
<vxe-column field="runFlag" title="运行状态" width="100px"> <vxe-column field="runFlag" title="运行状态" width="100px">
<template #default="{ row }"> <template #default="{ row }">
<el-tag <el-tag :type="row.runFlag == '运行'
:type=" ? 'success'
row.runFlag == '运' : row.runFlag == '运'
? 'success'
: row.runFlag == '停运'
? 'danger' ? 'danger'
: row.runFlag == '检修' : row.runFlag == '检修'
? 'warning' ? 'warning'
: row.runFlag == '调试' : row.runFlag == '调试'
? 'warning' ? 'warning'
: 'danger' : 'danger'
" ">
>
{{ row.runFlag }} {{ row.runFlag }}
</el-tag> </el-tag>
</template> </template>
@@ -169,14 +139,9 @@
</vxe-table> </vxe-table>
</div> </div>
<div class="table-pagination"> <div class="table-pagination">
<el-pagination <el-pagination v-model:currentPage="pageNum" v-model:page-size="pageSize"
v-model:currentPage="pageNum" :page-sizes="[10, 20, 50, 100, 200]" background
v-model:page-size="pageSize" layout="sizes,total, ->, prev, pager, next, jumper" :total="dataList.length"></el-pagination>
:page-sizes="[10, 20, 50, 100, 200]"
background
layout="sizes,total, ->, prev, pager, next, jumper"
:total="dataList.length"
></el-pagination>
</div> </div>
</el-card> </el-card>
</div> </div>
@@ -187,7 +152,7 @@
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { onMounted, provide, ref } from 'vue' import { onMounted, provide, ref, nextTick } from 'vue'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
@@ -273,7 +238,7 @@ const tableStore = new TableStore({
if (tableStore.table.params.statisticalType.name == '终端厂家') { if (tableStore.table.params.statisticalType.name == '终端厂家') {
return k.count != 0 return k.count != 0
} else { } else {
return k.name != '上送国网' && k.name != '上送国网' return !k.name.includes('上送')
} }
}) })
// 合并子集数据 并去重 // 合并子集数据 并去重
@@ -465,15 +430,9 @@ const onExport = () => {
}) })
} }
onMounted(() => { onMounted(() => {
// TableHeaderRef.value.setDatePicker([ nextTick(() => {
// { label: '年份', value: 1 }, TableHeaderRef.value?.onComSearch()
// { label: '季度', value: 2 }, })
// { label: '月份', value: 3 }
// ])
// 加载数据
tableStore.index()
}) })
tableStore.table.params.name = '' tableStore.table.params.name = ''
@@ -482,14 +441,17 @@ provide('tableStore', tableStore)
<style lang="scss" scoped> <style lang="scss" scoped>
.card-list { .card-list {
display: flex; display: flex;
.monitoringPoints { .monitoringPoints {
width: 460px; width: 460px;
position: relative; position: relative;
.statistics { .statistics {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px; margin-bottom: 10px;
.divBox { .divBox {
width: 215x; width: 215x;
height: 70px; height: 70px;
@@ -500,33 +462,41 @@ provide('tableStore', tableStore)
font-size: 40px; font-size: 40px;
margin-right: 5px; margin-right: 5px;
} }
.divBox_title { .divBox_title {
font-weight: 550; font-weight: 550;
} }
.divBox_num { .divBox_num {
font-size: 20px; font-size: 20px;
font-weight: 550; font-weight: 550;
margin-left: auto; margin-left: auto;
font-family: AlimamaDongFangDaKai; font-family: AlimamaDongFangDaKai;
} }
align-items: center; align-items: center;
// text-align: center; // text-align: center;
border-radius: 5px; border-radius: 5px;
&:nth-child(1) { &:nth-child(1) {
background-color: #eef8f0; background-color: #eef8f0;
} }
&:nth-child(2) { &:nth-child(2) {
background-color: #fff6ed; background-color: #fff6ed;
} }
&:nth-child(3) { &:nth-child(3) {
background-color: #e5f8f6; background-color: #e5f8f6;
} }
} }
} }
} }
.detail { .detail {
flex: 1; flex: 1;
} }
.abnormal { .abnormal {
width: 100%; width: 100%;
background-color: #f3f6f9; background-color: #f3f6f9;
@@ -535,9 +505,11 @@ provide('tableStore', tableStore)
// justify-content: space-between; // justify-content: space-between;
align-items: center; align-items: center;
padding: 5px 0px 5px 10px; padding: 5px 0px 5px 10px;
.iconDiv { .iconDiv {
display: flex; display: flex;
align-items: center; align-items: center;
div { div {
width: 4px; width: 4px;
height: 18px; height: 18px;
@@ -545,6 +517,7 @@ provide('tableStore', tableStore)
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
} }
} }
.text { .text {
font-weight: 700; font-weight: 700;
font-size: 16px; font-size: 16px;
@@ -555,6 +528,7 @@ provide('tableStore', tableStore)
} }
} }
} }
.header { .header {
display: flex; display: flex;
text-align: center; text-align: center;
@@ -562,40 +536,50 @@ provide('tableStore', tableStore)
font-weight: 700; font-weight: 700;
padding: 5px; padding: 5px;
} }
:deep(.el-card__header) { :deep(.el-card__header) {
padding: 10px; padding: 10px;
span { span {
font-weight: 600; font-weight: 600;
} }
} }
:deep(.el-card__body) { :deep(.el-card__body) {
padding: 10px; padding: 10px;
} }
.iconFont { .iconFont {
font-size: 18px; font-size: 18px;
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
} }
.form { .form {
position: relative; position: relative;
.form_but { .form_but {
position: absolute; position: absolute;
right: -22px; right: -22px;
} }
} }
.card-header { .card-header {
font-size: 16px; font-size: 16px;
} }
:deep(.table_name) { :deep(.table_name) {
color: var(--el-color-primary); color: var(--el-color-primary);
cursor: pointer; cursor: pointer;
text-underline-offset: 4px; text-underline-offset: 4px;
} }
.echartTitle { .echartTitle {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-size: 14px; font-size: 14px;
font-weight: 600; font-weight: 600;
div:nth-child(2) { div:nth-child(2) {
font-size: 16px; font-size: 16px;
color: #ff6600; color: #ff6600;
@@ -605,20 +589,25 @@ provide('tableStore', tableStore)
:deep(.el-segmented__item-selected, ) { :deep(.el-segmented__item-selected, ) {
clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%); clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%);
} }
:deep(.el-segmented__item, ) { :deep(.el-segmented__item, ) {
clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%); clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%);
position: relative; position: relative;
} }
:deep(.el-segmented) { :deep(.el-segmented) {
clip-path: polygon(4% 0, 100% 0, 96% 100%, 0 100%); clip-path: polygon(4% 0, 100% 0, 96% 100%, 0 100%);
} }
.text-red { .text-red {
color: #ff9100 !important; color: #ff9100 !important;
} }
.text-style { .text-style {
cursor: pointer; cursor: pointer;
text-decoration: underline; text-decoration: underline;
} }
.segmentedIcon { .segmentedIcon {
position: absolute; position: absolute;
top: 1px; top: 1px;
@@ -631,6 +620,7 @@ provide('tableStore', tableStore)
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
} }
.table-pagination { .table-pagination {
height: 58px; height: 58px;
box-sizing: border-box; box-sizing: border-box;

View File

@@ -13,7 +13,13 @@
<Area v-model="form.deptId" @change="changeArea" /> <Area v-model="form.deptId" @change="changeArea" />
</el-form-item> </el-form-item>
<el-form-item for="-" label="计划名称:" prop="planName"> <el-form-item for="-" label="计划名称:" prop="planName">
<el-input v-model="form.planName" placeholder="请输入计划名称" clearable maxlength="32" show-word-limit></el-input> <el-input
v-model="form.planName"
placeholder="请输入计划名称"
clearable
maxlength="32"
show-word-limit
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="监督类型:" prop="supvType"> <el-form-item label="监督类型:" prop="supvType">
<el-select v-model="form.supvType" placeholder="请选择监督类型" style="width: 100%" @change="++key"> <el-select v-model="form.supvType" placeholder="请选择监督类型" style="width: 100%" @change="++key">
@@ -26,7 +32,13 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item for="-" label="监督对象名称:" prop="supvObjectName"> <el-form-item for="-" label="监督对象名称:" prop="supvObjectName">
<el-input v-model="form.supvObjectName" placeholder="请输入监督对象名称" clearable maxlength="32" show-word-limit></el-input> <el-input
v-model="form.supvObjectName"
placeholder="请输入监督对象名称"
clearable
maxlength="32"
show-word-limit
></el-input>
</el-form-item> </el-form-item>
<el-form-item for="-" label="计划开始时间:" prop="planStartTime"> <el-form-item for="-" label="计划开始时间:" prop="planStartTime">
<el-date-picker <el-date-picker
@@ -336,7 +348,12 @@ const changeArea = () => {
treeList.value.forEach((item: any) => { treeList.value.forEach((item: any) => {
if (item.id == form.value.deptId) { if (item.id == form.value.deptId) {
list.push(item) list.push(item)
if (item.id != treeListCgy.value[0].id && item.name != '冀北电力有限公司' && item.name != '超高压') { if (
item.id != treeListCgy.value[0].id &&
!item.name.includes('电力有限公司') &&
item.name != '超高压'
) {
list.push(...treeListCgy.value) list.push(...treeListCgy.value)
} }
} else { } else {

View File

@@ -19,7 +19,7 @@
show-word-limit show-word-limit
/> />
</el-form-item> </el-form-item>
<el-form-item label="触发类型:"> <el-form-item label="触发类型">
<el-select <el-select
v-model="tableStore.table.params.waveType" v-model="tableStore.table.params.waveType"
placeholder="请选择触发类型" placeholder="请选择触发类型"
@@ -36,7 +36,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="是否有波形:"> <el-form-item label="是否有波形">
<el-select <el-select
v-model="tableStore.table.params.fileFlag" v-model="tableStore.table.params.fileFlag"
placeholder="请选择是否存在波形" placeholder="请选择是否存在波形"
@@ -51,7 +51,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="暂态持续时间(s):"> <el-form-item label="暂态持续时间(s)">
<el-input <el-input
v-model="tableStore.table.params.persistMin" v-model="tableStore.table.params.persistMin"
placeholder="请输入X秒" placeholder="请输入X秒"
@@ -69,7 +69,7 @@
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="事件严重度:"> <el-form-item label="事件严重度">
<el-input <el-input
v-model="tableStore.table.params.severityMin" v-model="tableStore.table.params.severityMin"
placeholder="请输入正负数" placeholder="请输入正负数"
@@ -94,7 +94,7 @@
:value="item.id"></el-option> :value="item.id"></el-option>
</el-select> </el-select>
</el-form-item> --> </el-form-item> -->
<el-form-item label="暂态原因:"> <el-form-item label="暂态原因">
<el-select <el-select
v-model="tableStore.table.params.eventReason" v-model="tableStore.table.params.eventReason"
placeholder="请选择暂态原因" placeholder="请选择暂态原因"
@@ -111,7 +111,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="暂态核实原因:"> <el-form-item label="暂态核实原因">
<el-select <el-select
v-model="tableStore.table.params.verifyReason" v-model="tableStore.table.params.verifyReason"
placeholder="请选择暂态核实原因" placeholder="请选择暂态核实原因"
@@ -128,7 +128,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="变电站(监测点):"> <el-form-item label="变电站(监测点)">
<el-cascader <el-cascader
v-model="tableStore.table.params.lineIds" v-model="tableStore.table.params.lineIds"
:options="options" :options="options"
@@ -217,33 +217,17 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ field: 'startTime', title: '暂降发生时刻', minWidth: '200' }, { field: 'startTime', title: '暂降发生时刻', minWidth: '200', sortable: true },
{ field: 'gdName', title: '供电公司', minWidth: '100' },
{ field: 'subName', title: '变电站', minWidth: '200' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'lineName', title: '监测点', minWidth: '100' },
{ field: 'scale', title: '电压等级(kV)', minWidth: '120' },
{
field: 'verifyReason',
title: '暂态核实原因',
minWidth: '120',
formatter: function (row) {
return verifyReasonList.filter(item => item.id == row.cellValue)[0]?.name || '/' //row.cellValue ? row.cellValue : '/'
}
},
// {
// field: 'verifyReasonDetail', title: '暂降核实原因详情', minWidth: '200', formatter: function (row) {
// return row.cellValue ? row.cellValue : '/'
// }
// },
{ {
field: 'featureAmplitude', field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)', title: '暂降(骤升)幅值(%)',
minWidth: '130', minWidth: '160',
sortable: true,
formatter: (row: any) => { formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100 return Math.floor(row.cellValue * 10000) / 100
} }
}, },
{ field: 'duration', title: '持续时间(s)', minWidth: 120, sortable: true },
{ {
field: 'eventType', field: 'eventType',
title: '触发类型', title: '触发类型',
@@ -253,17 +237,32 @@ const tableStore = new TableStore({
return triggeroptions.filter(item => item.id == row.eventType)[0]?.name return triggeroptions.filter(item => item.id == row.eventType)[0]?.name
} }
}, },
// { field: 'advanceType', title: '触发类型', minWidth: '100', },
{ field: 'advanceReason', title: '暂态原因', minWidth: '100' },
{ {
field: 'depth', field: 'depth',
title: '暂降深度(%)', title: '暂降深度(%)',
minWidth: '100', minWidth: 120,
formatter: ({ row }: any) => formatter: ({ row }: any) =>
row.featureAmplitude < 1 ? 100 - (row.featureAmplitude * 100).toFixed(0) : '/' row.featureAmplitude < 1 ? 100 - (row.featureAmplitude * 100).toFixed(0) : '/'
}, },
{ field: 'duration', title: '持续时间(s)', minWidth: '100' }, { field: 'advanceReason', title: '暂态原因', minWidth: '100' },
{
field: 'verifyReason',
title: '暂态核实原因',
minWidth: '120',
formatter: function (row) {
return verifyReasonList.filter(item => item.id == row.cellValue)[0]?.name || '/' //row.cellValue ? row.cellValue : '/'
}
},
{ field: 'gdName', title: '供电公司', minWidth: '100' },
{ field: 'subName', title: '变电站', minWidth: '200' },
{ field: 'lineName', title: '监测点', minWidth: '100' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'scale', title: '电压等级(kV)', minWidth: '130', sortable: true },
// { field: 'advanceType', title: '触发类型', minWidth: '100', },
{ {
field: 'severity', field: 'severity',
title: '严重度', title: '严重度',
@@ -272,7 +271,8 @@ const tableStore = new TableStore({
}, },
{ {
title: '操作',fixed: 'right', title: '操作',
fixed: 'right',
width: '150', width: '150',
render: 'buttons', render: 'buttons',
@@ -424,6 +424,7 @@ const download = () => {
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
}) })
} }
</script> </script>

View File

@@ -3,9 +3,9 @@
<div v-show="view"> <div v-show="view">
<TableHeader datePicker :showReset="false" showExport ref="TableHeaderRef"> <TableHeader datePicker :showReset="false" showExport ref="TableHeaderRef">
<template #select> <template #select>
<!-- <el-form-item label="筛选数据">--> <!-- <el-form-item label="筛选数据">-->
<!-- <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入关键字筛选" />--> <!-- <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入关键字筛选" />-->
<!-- </el-form-item>--> <!-- </el-form-item>-->
</template> </template>
<template #operation> <template #operation>
<el-button icon="el-icon-Tickets" type="primary" @click="analysis1">分析记录管理</el-button> <el-button icon="el-icon-Tickets" type="primary" @click="analysis1">分析记录管理</el-button>
@@ -29,7 +29,7 @@
</template> </template>
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
<el-pagination <el-pagination
class="mt10" class="mt10"
:currentPage="form.pageNum" :currentPage="form.pageNum"
:page-size="form.pageSize" :page-size="form.pageSize"
@@ -39,7 +39,7 @@
:total="total" :total="total"
@size-change="onTableSizeChange" @size-change="onTableSizeChange"
@current-change="onTableCurrentChange" @current-change="onTableCurrentChange"
></el-pagination> ></el-pagination>
</el-dialog> </el-dialog>
</div> </div>
<div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view"> <div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view">
@@ -70,7 +70,7 @@ const loading = ref(false)
const view = ref(true) const view = ref(true)
const view2 = ref(false) const view2 = ref(false)
const TableHeaderRef = ref() const TableHeaderRef = ref()
const waveFormRef = ref() const waveFormRef = ref()
const tableStore = new TableStore({ const tableStore = new TableStore({
url: '/advance-boot/process/querySagEventsPage', url: '/advance-boot/process/querySagEventsPage',
method: 'POST', method: 'POST',
@@ -83,19 +83,23 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ field: 'startTime', title: '发生时间' }, { field: 'startTime', title: '暂降发生时刻', sortable: true, minWidth: 200 },
{ field: 'duration', title: '持续时间(s)' },
{ {
field: 'featureAmplitude', field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)' title: '暂降(骤升)幅值(%)',
sortable: true,
minWidth: 160
}, },
{ field: 'gdName', title: '供电公司' }, { field: 'duration', title: '持续时间(s)', sortable: true, minWidth: 120 },
{ field: 'subName', title: '变电站' }, { field: 'gdName', title: '供电公司', minWidth: 140 },
{ field: 'lineName', title: '监测点' }, { field: 'subName', title: '变电站', minWidth: 140 },
{ field: 'lineName', title: '监测点', minWidth: 140 },
{ {
field: 'dealFlag', field: 'dealFlag',
title: '暂降特征幅值计算', title: '暂降特征幅值计算',
render: 'tag', render: 'tag',
minWidth: 160,
custom: { custom: {
0: 'warning', 0: 'warning',
1: 'success', 1: 'success',
@@ -115,6 +119,7 @@ const tableStore = new TableStore({
field: 'fileFlag', field: 'fileFlag',
title: '录波文件', title: '录波文件',
render: 'tag', render: 'tag',
minWidth: 140,
custom: { custom: {
0: 'warning', 0: 'warning',
1: 'success' 1: 'success'
@@ -125,7 +130,8 @@ const tableStore = new TableStore({
} }
}, },
{ {
title: '操作',fixed: 'right', title: '操作',
fixed: 'right',
width: '120', width: '120',
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
@@ -140,9 +146,9 @@ const tableStore = new TableStore({
render: 'basicButton', render: 'basicButton',
click: async row => { click: async row => {
view.value = false view.value = false
setTimeout(() => { setTimeout(() => {
waveFormRef.value.open(row) waveFormRef.value.open(row)
},100) }, 100)
// row.loading = true // row.loading = true
// boxoList.value = row // boxoList.value = row
// await getMonitorEventAnalyseWave({ id: row.eventId, systemType: 0 }) // await getMonitorEventAnalyseWave({ id: row.eventId, systemType: 0 })
@@ -173,7 +179,7 @@ const tableStore = new TableStore({
} }
], ],
loadCallback: () => { } loadCallback: () => {}
}) })
tableStore.table.params.searchValue = '' tableStore.table.params.searchValue = ''
const bxactiveName = ref('ssbx') const bxactiveName = ref('ssbx')
@@ -190,25 +196,21 @@ provide('tableStore', tableStore)
onMounted(() => { onMounted(() => {
TableHeaderRef.value.setTheDate(1) TableHeaderRef.value.setTheDate(1)
nextTick(() => { nextTick(() => {
// tableStore.index() // tableStore.index()
TableHeaderRef.value.onComSearch() TableHeaderRef.value.onComSearch()
}) })
}) })
// 分页 // 分页
const onTableSizeChange = (val: number) => { const onTableSizeChange = (val: number) => {
form.value.pageSize = val form.value.pageSize = val
form.value.pageNum = 1 // 改变每页条数时回到第一页 form.value.pageNum = 1 // 改变每页条数时回到第一页
loadAnalysisData() // 重新加载数据 loadAnalysisData() // 重新加载数据
} }
const onTableCurrentChange = (val: number) => { const onTableCurrentChange = (val: number) => {
form.value.pageNum = val form.value.pageNum = val
loadAnalysisData() // 重新加载数据 loadAnalysisData() // 重新加载数据
} }
// 封装数据加载逻辑 // 封装数据加载逻辑
@@ -230,13 +232,12 @@ const loadAnalysisData = async () => {
//分析记录管理 //分析记录管理
const analysis1 = async () => { const analysis1 = async () => {
// 初始化分页参数 // 初始化分页参数
form.value.pageNum = 1 form.value.pageNum = 1
await loadAnalysisData() await loadAnalysisData()
dialogAnalysis.value = true dialogAnalysis.value = true
} }
// 启动关联分析 // 启动关联分析
const firing = () => { const firing = () => {
processEvents({ processEvents({
@@ -257,7 +258,7 @@ const details = (row: any) => {
type: 'success', type: 'success',
message: res.message message: res.message
}) })
// 重新加载当前页的数据 // 重新加载当前页的数据
loadAnalysisData() loadAnalysisData()
}) })
} }
@@ -266,6 +267,4 @@ const backbxlb = () => {
view.value = true view.value = true
view2.value = false view2.value = false
} }
</script> </script>

View File

@@ -2,8 +2,14 @@
<div class="default-main"> <div class="default-main">
<TableHeader datePicker ref="TableHeaderRef"> <TableHeader datePicker ref="TableHeaderRef">
<template #select> <template #select>
<el-form-item label="关键字"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入事件关联分析描述" maxlength="32" show-word-limit/> <el-input
v-model="tableStore.table.params.searchValue"
clearable
placeholder="输入事件关联分析描述"
maxlength="32"
show-word-limit
/>
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
@@ -35,25 +41,18 @@
</vxe-table-column> </vxe-table-column>
<vxe-table-column <vxe-table-column
field="startTime" field="startTime"
title="发生时" title="暂降发生时"
align="center" align="center"
sortable
width="200"
:show-overflow="true" :show-overflow="true"
></vxe-table-column> ></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column> <vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" sortable align="center" width="160">
<vxe-table-column
field="subName"
:show-overflow="true"
title="变电站"
align="center"
></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" align="center" width="140">
<template #default="{ row }"> <template #default="{ row }">
<span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span> <span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span>
</template> </template>
</vxe-table-column> </vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" align="center" width="120"></vxe-table-column> <vxe-table-column field="duration" title="持续时间(s)" sortable align="center" width="120"></vxe-table-column>
<vxe-table-column <vxe-table-column
field="advanceType" field="advanceType"
title="触发类型" title="触发类型"
@@ -68,6 +67,15 @@
width="120" width="120"
:formatter="formFilter" :formatter="formFilter"
></vxe-table-column> ></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column
field="subName"
:show-overflow="true"
title="变电站"
align="center"
></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
</vxe-table> </vxe-table>
<el-pagination <el-pagination
class="mt10" class="mt10"
@@ -131,7 +139,8 @@ const tableStore = new TableStore({
title: '事件关联分析描述' title: '事件关联分析描述'
}, },
{ {
title: '操作',fixed: 'right', title: '操作',
fixed: 'right',
width: '200', width: '200',
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
@@ -176,7 +185,6 @@ const bxcontrast = () => {
} }
} }
// 波形分析 // 波形分析
const source = () => { const source = () => {
queryEventDetailByAssId(form.value).then(res => { queryEventDetailByAssId(form.value).then(res => {
@@ -245,14 +253,14 @@ const exportEvent = () => {
} }
// 导出波形分析 // 导出波形分析
const positioningexport = () => { const positioningexport = () => {
const selectedRecords = positioningtableRef.value.getCheckboxRecords(); const selectedRecords = positioningtableRef.value.getCheckboxRecords()
if (selectedRecords.length === 0) { if (selectedRecords.length === 0) {
ElMessage({ ElMessage({
message: '请先选择要导出的数据!', message: '请先选择要导出的数据!',
type: 'warning' type: 'warning'
}); })
return; return
} }
positioningtableRef.value.exportData({ positioningtableRef.value.exportData({

View File

@@ -3,7 +3,7 @@
<div v-show="view"> <div v-show="view">
<TableHeader datePicker ref="TableHeaderRef" > <TableHeader datePicker ref="TableHeaderRef" >
<template #select> <template #select>
<el-form-item label="关键字"> <el-form-item label="筛选数据">
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入事件关联分析描述" <el-input v-model="tableStore.table.params.searchValue" clearable placeholder="输入事件关联分析描述"
maxlength="32" show-word-limit /> maxlength="32" show-word-limit />
</el-form-item> </el-form-item>
@@ -27,22 +27,23 @@
<span>{{ (form.pageNum - 1) * form.pageSize + row.rowIndex + 1 }}</span> <span>{{ (form.pageNum - 1) * form.pageSize + row.rowIndex + 1 }}</span>
</template> </template>
</vxe-table-column> </vxe-table-column>
<vxe-table-column field="startTime" title="发生时" align="center" <vxe-table-column field="startTime" title="暂降发生时" align="center" sortable width="200"
:show-overflow="true"></vxe-table-column> :show-overflow="true"></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column> <vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" sortable align="center" width="160">
<vxe-table-column field="subName" :show-overflow="true" title="变电站" align="center"></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
<vxe-table-column field="featureAmplitude" title="暂降(骤升)幅值(%)" align="center" width="140">
<template #default="{ row }"> <template #default="{ row }">
<span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span> <span>{{ (row.featureAmplitude * 100).toFixed(2) }}</span>
</template> </template>
</vxe-table-column> </vxe-table-column>
<vxe-table-column field="duration" title="持续时间(s)" align="center" width="120"></vxe-table-column> <vxe-table-column field="duration" title="持续时间(s)" align="center" sortable width="120"></vxe-table-column>
<vxe-table-column field="advanceType" title="触发类型" align="center" width="120" <vxe-table-column field="advanceType" title="触发类型" align="center" width="120"
:formatter="formFilter"></vxe-table-column> :formatter="formFilter"></vxe-table-column>
<vxe-table-column field="advanceReason" title="暂降原因" align="center" width="120" <vxe-table-column field="advanceReason" title="暂降原因" align="center" width="120"
:formatter="formFilter"></vxe-table-column> :formatter="formFilter"></vxe-table-column>
<vxe-table-column field="gdName" title="供电公司" align="center"></vxe-table-column>
<vxe-table-column field="subName" :show-overflow="true" title="变电站" align="center"></vxe-table-column>
<vxe-table-column field="lineName" title="监测点" align="center"></vxe-table-column>
<vxe-table-column field="voltageId" title="电压等级(kV)" align="center"></vxe-table-column>
</vxe-table> </vxe-table>
<el-pagination class="mt10" :currentPage="form.pageNum" :page-size="form.pageSize" <el-pagination class="mt10" :currentPage="form.pageNum" :page-size="form.pageSize"
:page-sizes="[10, 20, 50, 100]" background :layout="'sizes,total, ->, prev, pager, next, jumper'" :page-sizes="[10, 20, 50, 100]" background :layout="'sizes,total, ->, prev, pager, next, jumper'"

View File

@@ -56,34 +56,37 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ title: '变电站名称', field: 'subName', minWidth: '140' }, { title: '暂降发生时刻', field: 'startTime', width: '200', sortable: true, },
{ title: '监测点名称', field: 'lineName', minWidth: '130' },
{ title: '网络参数', field: 'ip', width: '120px' },
{ title: '电压等级(kV)', field: 'voltageScale', width: '120' },
{ title: '暂降发生时刻', field: 'startTime', width: '200' },
// { title: '触发类型', field: 'advanceType', minWidth: '130' },
{ title: '暂降原因', field: 'advanceReason', minWidth: '130' },
{
title: '触发类型',
field: 'eventType',
minWidth: '80',
formatter: (row: any) => {
return eventTypeOptions.find(item => item.id === row.cellValue)?.name || '/'
}
},
{ {
title: '暂降(骤升)幅值(%)', title: '暂降(骤升)幅值(%)',
field: 'featureAmplitude', field: 'featureAmplitude',
minWidth: '140', minWidth: '160',
sortable: true,
formatter: (row: any) => { formatter: (row: any) => {
return Math.floor(row.cellValue * 10000) / 100 return Math.floor(row.cellValue * 10000) / 100
} }
}, },
{ title: '持续时间(s)', field: 'duration', minWidth: '100' }, { title: '持续时间(s)', field: 'duration', minWidth: '120' , sortable: true, },
{
title: '触发类型',
field: 'eventType',
minWidth: '100',
formatter: (row: any) => {
return eventTypeOptions.find(item => item.id === row.cellValue)?.name || '/'
}
},
{ title: '暂降原因', field: 'advanceReason', minWidth: '130' },
{ title: '变电站名称', field: 'subName', minWidth: '140' },
{ title: '监测点名称', field: 'lineName', minWidth: '130' },
{ title: '网络参数', field: 'ip', width: '120px' },
{ title: '电压等级(kV)', field: 'voltageScale', width: '120' },
// { title: '触发类型', field: 'advanceType', minWidth: '130' },
// { title: '严重度', field: 'severity', minWidth: '80' }, // { title: '严重度', field: 'severity', minWidth: '80' },
{ {
title: '操作',fixed: 'right', title: '操作',
fixed: 'right',
width: '180', width: '180',
render: 'buttons', render: 'buttons',
@@ -127,7 +130,6 @@ const tableStore = new TableStore({
], ],
beforeSearchFun: () => { beforeSearchFun: () => {
tableStore.table.params.lineId = monitoringPoint.state.lineId tableStore.table.params.lineId = monitoringPoint.state.lineId
}, },
loadCallback: () => {} loadCallback: () => {}
}) })
@@ -174,6 +176,7 @@ const download = () => {
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签
ElMessage.success('波形下载成功')
}) })
} }
</script> </script>

View File

@@ -68,7 +68,7 @@
></bm-marker> ></bm-marker>
</template> </template>
<!-- --> <!-- -->
<BmlMarkerClusterer maxZoom="12"> <BmlMarkerClusterer maxZoom="12" :styles="styles">
<bm-marker <bm-marker
:position="path" :position="path"
v-for="path in areaLineInfo" v-for="path in areaLineInfo"
@@ -163,6 +163,44 @@ const areaLineInfo = ref<any>([])
const siteList = ref<any>([]) const siteList = ref<any>([])
const polyline = ref<any>([]) const polyline = ref<any>([])
const lineId = ref('') const lineId = ref('')
const imageUrl = new URL('@/assets/imgs/m0.png', import.meta.url).href
const imageUrl1 = new URL('@/assets/imgs/m1.png', import.meta.url).href
const imageUrl2 = new URL('@/assets/imgs/m3.png', import.meta.url).href
const imageUrl3 = new URL('@/assets/imgs/m4.png', import.meta.url).href
const styles = [
{
url: imageUrl,
size: {
width: 53,
height: 52
},
opt_textSize: 10
},
{
url: imageUrl1,
size: {
width: 56,
height: 55
},
opt_textSize: 12
},
{
url: imageUrl2,
size: {
width: 78,
height: 77
},
opt_textSize: 14
},
{
url: imageUrl3,
size: {
width: 90,
height: 89
},
opt_textSize: 14
},
]
const handler = async ({ BMap, map }: any) => { const handler = async ({ BMap, map }: any) => {
let data = props.mapList let data = props.mapList
let r = 0.0035 let r = 0.0035

View File

@@ -82,7 +82,7 @@
></bm-marker> ></bm-marker>
</template> </template>
<!-- --> <!-- -->
<BmlMarkerClusterer maxZoom="12"> <BmlMarkerClusterer maxZoom="12" :styles="styles">
<bm-marker <bm-marker
:position="path" :position="path"
v-for="path in areaLineInfo" v-for="path in areaLineInfo"
@@ -196,13 +196,51 @@ const areaLineInfo = ref<any>([])
const siteList = ref<any>([]) const siteList = ref<any>([])
const polyline = ref<any>([]) const polyline = ref<any>([])
const lineId = ref('') const lineId = ref('')
const imageUrl = new URL('@/assets/imgs/m0.png', import.meta.url).href
const imageUrl1 = new URL('@/assets/imgs/m1.png', import.meta.url).href
const imageUrl2 = new URL('@/assets/imgs/m3.png', import.meta.url).href
const imageUrl3 = new URL('@/assets/imgs/m4.png', import.meta.url).href
const styles = [
{
url: imageUrl,
size: {
width: 53,
height: 52
},
opt_textSize: 10
},
{
url: imageUrl1,
size: {
width: 56,
height: 55
},
opt_textSize: 12
},
{
url: imageUrl2,
size: {
width: 78,
height: 77
},
opt_textSize: 14
},
{
url: imageUrl3,
size: {
width: 90,
height: 89
},
opt_textSize: 14
},
]
const handler = async ({ BMap, map }: any) => { const handler = async ({ BMap, map }: any) => {
params.value.deptIndex = adminInfo.$state.deptId params.value.deptIndex = adminInfo.$state.deptId
params.value.searchBeginTime = datePickerRef.value.timeValue[0] params.value.searchBeginTime = datePickerRef.value.timeValue[0]
params.value.searchEndTime = datePickerRef.value.timeValue[1] params.value.searchEndTime = datePickerRef.value.timeValue[1]
let { data } = await getAreaLineInfo(params.value) let { data } = await getAreaLineInfo(params.value)
let r = 0.0035 let r = 0.0035
let list = data.filter((item: any) => item.lng != 0) let list = data//.filter((item: any) => item.lng != 0)
list.forEach((item: any) => { list.forEach((item: any) => {
// 变电站图标 // 变电站图标
item.icon = { item.icon = {

View File

@@ -3,21 +3,21 @@
<div style="height: 40vh"> <div style="height: 40vh">
<vxe-table v-loading="loading" height="auto" auto-resize :data="tableData" v-bind="defaultAttribute"> <vxe-table v-loading="loading" height="auto" auto-resize :data="tableData" v-bind="defaultAttribute">
<vxe-column type="seq" title="序号" width="80px"></vxe-column> <vxe-column type="seq" title="序号" width="80px"></vxe-column>
<vxe-column field="startTime" title="发生时" width="180"></vxe-column> <vxe-column field="startTime" title="暂降发生时" width="200" sortable></vxe-column>
<vxe-column field="duration" title="持续时间(s)" width="100"></vxe-column> <vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="160" sortable>
<vxe-column field="gdName" title="供电公司" min-width="150"></vxe-column> <template #default="{ row }">
<vxe-column field="subName" title="变电站" min-width="150"></vxe-column> {{ (row.featureAmplitude * 100).toFixed(2) }}
<vxe-column field="lineName" title="监测点" min-width="150"></vxe-column> </template>
</vxe-column>
<vxe-column field="duration" title="持续时间(s)" width="120" sortable></vxe-column>
<vxe-column field="advanceType" title="触发类型" width="100"> <vxe-column field="advanceType" title="触发类型" width="100">
<template #default="{ row }"> <template #default="{ row }">
{{ type.find(item => item.id === row.advanceType)?.name }} {{ type.find(item => item.id === row.advanceType)?.name }}
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="150"> <vxe-column field="gdName" title="供电公司" min-width="140"></vxe-column>
<template #default="{ row }"> <vxe-column field="subName" title="变电站" min-width="140"></vxe-column>
{{ (row.featureAmplitude * 100).toFixed(2) }} <vxe-column field="lineName" title="监测点名称" min-width="140"></vxe-column>
</template>
</vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</el-dialog> </el-dialog>

View File

@@ -23,14 +23,15 @@
<div style="flex: 1; overflow: hidden"> <div style="flex: 1; overflow: hidden">
<vxe-table height="auto" auto-resize :data="tableData" v-bind="defaultAttribute"> <vxe-table height="auto" auto-resize :data="tableData" v-bind="defaultAttribute">
<vxe-column type="seq" title="序号" width="70px"></vxe-column> <vxe-column type="seq" title="序号" width="70px"></vxe-column>
<vxe-column field="startTime" title="发生时刻" width="200"></vxe-column> <vxe-column field="startTime" title="暂降发生时刻" width="200" sortable></vxe-column>
<vxe-column field="lineName" title="监测点" width="120"></vxe-column> <vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)" width="160" sortable>
<vxe-column field="featureAmplitude" title="暂降(骤升)幅值(%)">
<template #default="{ row }"> <template #default="{ row }">
{{ (row.featureAmplitude * 100).toFixed(2) }} {{ row.featureAmplitude.toFixed(2) }}
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="duration" title="持续时间(s)"></vxe-column> <vxe-column field="duration" title="持续时间(s)" sortable width="120"></vxe-column>
<vxe-column field="lineName" title="监测点" width="120"></vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </div>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="default-main"> <div class="default-main">
<TableHeader date-picker area > <TableHeader date-picker area>
<template v-slot:select> <template v-slot:select>
<el-form-item label="统计类型"> <el-form-item label="统计类型">
<el-radio-group v-model="tableStore.table.params.comFlag"> <el-radio-group v-model="tableStore.table.params.comFlag">
@@ -48,10 +48,12 @@
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
<el-button icon="el-icon-Download" type="primary" @click="exportEvent" :loading="loading">导出</el-button> <el-button icon="el-icon-Download" type="primary" @click="exportEvent" :loading="loading">
报告生成
</el-button>
</template> </template>
</TableHeader> </TableHeader>
<Table ref="tableRef" /> <Table ref="tableRef" :checkboxConfig="checkboxConfig" />
</div> </div>
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
@@ -64,7 +66,7 @@ import { getEventReport } from '@/api/event-boot/report'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
defineOptions({ defineOptions({
name: 'Operationmanagement/terminalmanagement' name: 'TransientReport/eventreports'
}) })
const dictData = useDictData() const dictData = useDictData()
const triggerType = dictData.getBasicData('Event_Statis') const triggerType = dictData.getBasicData('Event_Statis')
@@ -82,6 +84,7 @@ const tableStore = new TableStore({
url: '/event-boot/report/getEventReport', url: '/event-boot/report/getEventReport',
method: 'POST', method: 'POST',
column: [ column: [
{ width: '60', type: 'checkbox' },
{ {
title: '序号', title: '序号',
@@ -93,42 +96,18 @@ const tableStore = new TableStore({
}, },
{ {
field: 'startTime', field: 'startTime',
title: '发生时刻', title: '暂降发生时刻',
width: '180', width: '180',
sortable: true,
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue ? row.cellValue.replace('T', ' ') : '/' return row.cellValue ? row.cellValue.replace('T', ' ') : '/'
} }
}, },
{ field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '120' },
{ field: 'ip', title: '网络参数', width: '120px' },
{ field: 'lineName', title: '监测点', minWidth: '120' },
{
field: 'eventType',
title: '触发类型',minWidth: '100' ,
formatter: (row: any) => {
return triggerType.filter(item => item.id === row.cellValue)[0].name
}
},
{
field: 'advanceType',
title: '暂态类型',
minWidth: '100'
},
{
field: 'advanceReason',
title: '暂态原因',
minWidth: '100'
},
{
field: 'voltageScale',
title: '电压等级',
minWidth: '100'
},
{ {
field: 'featureAmplitude', field: 'featureAmplitude',
title: '暂降(骤升)幅值(%)', title: '暂降(骤升)幅值(%)',
width: '140', width: '160',
sortable: true,
formatter: (row: any) => { formatter: (row: any) => {
// return (row.cellValue * 100).toFixed(0) // return (row.cellValue * 100).toFixed(0)
@@ -138,8 +117,44 @@ const tableStore = new TableStore({
{ {
field: 'duration', field: 'duration',
title: '持续时间(s)', title: '持续时间(s)',
width: '100' width: '120',
sortable: true
},
{
field: 'eventType',
title: '触发类型',
minWidth: '100',
formatter: (row: any) => {
return triggerType.filter(item => item.id === row.cellValue)[0].name
}
},
{
field: 'advanceType',
title: '暂态类型',
minWidth: '100',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{
field: 'advanceReason',
title: '暂态原因',
minWidth: '100',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{ field: 'gdName', title: '供电公司', minWidth: '120' },
{ field: 'subName', title: '变电站', minWidth: '120' },
{ field: 'lineName', title: '监测点', minWidth: '120' },
{ field: 'ip', title: '网络参数', width: '120px' },
{
field: 'voltageScale',
title: '电压等级',
minWidth: '100'
} }
// { field: 'severity', title: '严重度' } // { field: 'severity', title: '严重度' }
] ]
}) })
@@ -156,7 +171,11 @@ tableStore.table.params.statisticalType = dictData.getBasicData('Statistical_Typ
'Voltage_Level', 'Voltage_Level',
'Load_Type' 'Load_Type'
])[0] ])[0]
const checkboxConfig = reactive<VxeTablePropTypes.CheckboxConfig<any>>({
checkMethod: ({ row }) => {
return row.fileFlag === 1
}
})
provide('tableStore', tableStore) provide('tableStore', tableStore)
onMounted(() => { onMounted(() => {
@@ -178,15 +197,17 @@ const exportEvent = () => {
// } // }
// }) // })
// }) // })
if (!tableStore.table.selection.length) {
ElMessage.warning('请选择数据')
const ids = tableStore.table.data.map((item: any) => item.eventId); return
}
const ids = tableStore.table.selection.map((item: any) => item.eventId)
loading.value = true loading.value = true
ElMessage('生成报告中,请稍等!') ElMessage('生成报告中,请稍等!')
getEventReport(ids) getEventReport(ids)
.then((res: any) => { .then((res: any) => {
if (res == undefined) { if (res == undefined) {
loading.value = false loading.value = false
return return
} }
@@ -197,14 +218,14 @@ const exportEvent = () => {
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = '事件报告' // 设置下载的文件名 link.download = '事件报告' // 设置下载的文件名
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) document.body.removeChild(link)
loading.value = false loading.value = false
}) .catch(() => { })
.catch(() => {
loading.value = false loading.value = false
}) })
} }
</script> </script>

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