Compare commits

..

10 Commits

Author SHA1 Message Date
guanj
2e58e58c73 微调 2025-09-23 08:44:17 +08:00
sjl
50bc0f9396 修改时间控件带时分秒 2025-09-22 13:34:42 +08:00
sjl
0e485b1893 报表界面添加查询时间 2025-09-22 11:32:29 +08:00
guanj
f1b157ac26 优化页面 2025-07-18 16:27:39 +08:00
guanj
aa323c0d9c 需求变更整改 2025-07-15 16:31:06 +08:00
guanj
96518a4c9d 新增 半月报功能 2025-07-10 16:33:41 +08:00
guanj
7ab8e4ed9c 修改 模块运行状态页面添加数据展示 2025-07-09 16:48:18 +08:00
guanj
e1851f7ebb 修改 模块数据页面样式 2025-07-08 10:47:04 +08:00
guanj
7fabcb7f0f Web端添加治理模块状态展示界面、模块事件展示、主动询问模块状态功能 2025-07-08 08:44:13 +08:00
GGJ
4cde4e367e 优化 APF治理效果页面 2025-05-21 12:42:28 +08:00
64 changed files with 10157 additions and 2508 deletions

3552
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,21 +11,20 @@ import { provide, onMounted, ref } from 'vue'
//线上mqtt
// let buildUrl = 'wss://pqmcn.com:8087/mqtt'//102
let buildUrl = 'ws://pqmcn.com:8073/mqtt'//27
let buildUrl = 'ws://pqmcn.com:8073/mqtt' //27
// 从 Nginx 获取 MQTT URL
const fetchMqttUrl = async () => {
const response = await fetch('/')
const mqttUrl = response.headers.get('X-Mqtt-Url')
const zutai = response.headers.get('X-Mqttzutai-Url')
window.localStorage.setItem('MQTTURL', mqttUrl || buildUrl)
window.localStorage.setItem('MQTTZUTAI', zutai || '')
}
//本地mqtt
// let devUrl = 'ws://192.168.1.24:8085/mqtt'
// let devUrl = 'ws://192.168.1.24:8085/mqtt'
onMounted(() => {
fetchMqttUrl()

View File

@@ -121,8 +121,24 @@ export function getById(data?: any) {
//测试项日志修改
export function updateRecordData(data?: any) {
return createAxios({
url: 'cs-device-boot/wlRecord/updateRecordData',
url: '/cs-device-boot/wlRecord/updateRecordData',
method: 'POST',
data
})
}
//模块数据
export function allModelData(data?: any) {
return createAxios({
url: '/cs-harmonic-boot/data/allModelData',
method: 'POST',
data
})
}
//刷新状态
export function getModuleState(data?: any) {
return createAxios({
url: '/cs-harmonic-boot/data/getModuleState',
method: 'POST',
params: data
})
}

View File

@@ -22,11 +22,21 @@ export const auditEdData = (data) => {
data: data,
})
}
// 修改工程
export const auditEngineering = (data) => {
return request({
url: '/cs-device-boot/engineering/auditEngineering',
method: 'post',
data: data,
})
}
// 修改项目
export const updateProject = (data) => {
return request({
url: '/cs-device-boot/project/updateProject',
method: 'post',
data: data,
})
}

1690
src/assets/map/area.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -51,13 +51,7 @@ const initChart = () => {
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
@@ -66,7 +60,7 @@ const initChart = () => {
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
confine: true,
// confine: true,
...(props.options?.tooltip || null)
},
toolbox: {
@@ -109,6 +103,7 @@ const initChart = () => {
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 100
},
@@ -117,7 +112,7 @@ const initChart = () => {
height: 13,
bottom: '20px',
end: 100
},
}
// {
// show: true,
// yAxisIndex: 0,
@@ -135,7 +130,7 @@ const initChart = () => {
handlerBar(options)
// 处理柱状图
chart.setOption(options, true)
chart.group = 'group'
setTimeout(() => {
chart.resize()
}, 0)

View File

@@ -1,4 +1,4 @@
export let color = [ '#07CCCA','#00BFF5', '#FFBF00', '#77DA63', '#D5FF6B', '#Ff6600', '#FF9100', '#5B6E96', '#66FFCC', '#B3B3B3']
export const gradeColor3 = ['#339966', '#FFCC33', '#CC0000']
export const gradeColor5 = ['#00CC00', '#99CC99', '#FF9900','#996600','#CC0000']
export const gradeColor3 = ['#339966', '#FFCC33', '#A52a2a']
export const gradeColor5 = ['#00CC00', '#99CC99', '#FF9900','#996600','#A52a2a']

View File

@@ -745,7 +745,7 @@ export default {
zhou = waveDatas[0].RMSSMinDetail.secondeZhou;
}
colors.push("#FFCC00");
colors.push("#DAA520");
colors.push("#fff");
colors.push("#fff");
break;
@@ -783,8 +783,8 @@ export default {
rmsvY = waveDatas[0].RMSSMinDetail.rmsvSecondY;
zhou = waveDatas[0].RMSSMinDetail.secondeZhou;
}
colors.push("#FFCC00");
colors.push("#009900");
colors.push("#DAA520");
colors.push("#2E8B57");
colors.push("#fff");
break;
case 3:
@@ -822,9 +822,9 @@ export default {
rmsvY = waveDatas[0].RMSSMinDetail.rmsvSecondY;
zhou = waveDatas[0].RMSSMinDetail.secondeZhou;
}
colors.push("#FFCC00");
colors.push("#009900");
colors.push("#CC0000");
colors.push("#DAA520");
colors.push("#2E8B57");
colors.push("#A52a2a");
break;
}
if (waveDatas[0].unit === "电压") {
@@ -1090,7 +1090,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#FFCC00",
color: "#DAA520",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1105,7 +1105,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#009900",
color: "#2E8B57",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1120,7 +1120,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#CC0000",
color: "#A52a2a",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1518,7 +1518,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#FFCC00",
color: "#DAA520",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1533,7 +1533,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#009900",
color: "#2E8B57",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1548,7 +1548,7 @@ export default {
symbol: "none",
sampling: "average",
itemStyle: {
color: "#CC0000",
color: "#A52a2a",
},
progressive: 500,
// 渲染阈值,大于此值则启动渐进渲染

View File

@@ -461,7 +461,7 @@ export default {
adata = waveDatas[0].shunshiS.shunshiSA
}
colors.push('#FFCC00')
colors.push('#DAA520')
colors.push('#fff')
colors.push('#fff')
break
@@ -481,8 +481,8 @@ export default {
adata = waveDatas[0].shunshiS.shunshiSA
bdata = waveDatas[0].shunshiS.shunshiSB
}
colors.push('#FFCC00')
colors.push('#009900')
colors.push('#DAA520')
colors.push('#2E8B57')
colors.push('#fff')
break
case 3:
@@ -505,9 +505,9 @@ export default {
cdata = waveDatas[0].shunshiS.shunshiSC
}
colors.push('#FFCC00')
colors.push('#009900')
colors.push('#CC0000')
colors.push('#DAA520')
colors.push('#2E8B57')
colors.push('#A52a2a')
break
}
@@ -754,7 +754,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#FFCC00'
color: '#DAA520'
},
progressive: 1000,
// 渲染阈值,大于此值则启动渐进渲染
@@ -770,7 +770,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#009900'
color: '#2E8B57'
},
progressive: 1000,
// 渲染阈值,大于此值则启动渐进渲染
@@ -786,7 +786,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#CC0000'
color: '#A52a2a'
},
progressive: 1000,
// 渲染阈值,大于此值则启动渐进渲染
@@ -844,24 +844,24 @@ export default {
switch (this.iphasic) {
case 1:
a = waveDataTemp.title.aTitle
colors.push('#FFCC00')
colors.push('#DAA520')
colors.push('#fff')
colors.push('#fff')
break
case 2:
a = waveDataTemp.title.aTitle
b = waveDataTemp.title.bTitle
colors.push('#FFCC00')
colors.push('#009900')
colors.push('#DAA520')
colors.push('#2E8B57')
colors.push('#fff')
break
case 3:
a = waveDataTemp.title.aTitle
b = waveDataTemp.title.bTitle
c = waveDataTemp.title.cTitle
colors.push('#FFCC00')
colors.push('#009900')
colors.push('#CC0000')
colors.push('#DAA520')
colors.push('#2E8B57')
colors.push('#A52a2a')
break
}
@@ -1123,7 +1123,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#FFCC00'
color: '#DAA520'
},
large: true,
progressive: 1000,
@@ -1138,7 +1138,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#009900'
color: '#2E8B57'
},
progressive: 1000,
// 渲染阈值,大于此值则启动渐进渲染
@@ -1153,7 +1153,7 @@ export default {
symbol: 'none',
sampling: 'average',
itemStyle: {
color: '#CC0000'
color: '#A52a2a'
},
progressive: 1000,
// 渲染阈值,大于此值则启动渐进渲染

View File

@@ -417,7 +417,7 @@ const setTime = (flag = 0, e = 0) => {
let data = ''
if ((dd < 4 || dd == 0) && interval.value != 4 && !props.theCurrentTime) {
if ((dd < 2 || dd == 0) && interval.value != 4 && !props.theCurrentTime) {
data = window.XEUtils.toDateString(new Date().getTime() - (e + dd) * 3600 * 1000 * 24, 'yyyy-MM-dd')
} else {
data = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'yyyy-MM-dd')

View File

@@ -0,0 +1,606 @@
<template>
<div style="width: 680px">
<el-select v-model.trim="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-select>
<el-date-picker v-model.trim="timeValue" type="datetimerange" :disabled="disabledPicker"
style="width: 360px; margin-right: 10px" unlink-panels :clearable="false" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss"
:shortcuts="shortcuts" />
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
<el-button :disabled="preDisabled" type="primary" :icon="DArrowRight" @click="next"></el-button>
</div>
</template>
<script lang="ts" setup>
import { DArrowLeft, VideoPause, DArrowRight } from '@element-plus/icons-vue'
import { ref, onMounted } from 'vue'
interface Props {
nextFlag?: boolean
theCurrentTime?: boolean
}
const props = withDefaults(defineProps<Props>(), {
nextFlag: false,
theCurrentTime: true
})
const interval = ref(3)
const timeFlag = ref(1)
const count = ref(0)
const disabledPicker = ref(true)
const timeValue = ref()
const backDisabled = ref(false)
const preDisabled = ref(true)
const timeOptions: any = ref([
{ label: '年份', value: 1 },
{ label: '季度', value: 2 },
{ label: '月份', value: 3 },
{ label: '周', value: 4 },
{ label: '自定义', value: 5 }
])
// 添加格式化时间显示的函数
const formatDateTimeDisplay = (date: Date) => {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
const shortcuts = [
{
text: '最近一周',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
// 设置开始时间为当天的00:00:00
start.setHours(0, 0, 0, 0)
// 设置结束时间为当天的23:59:59
end.setHours(23, 59, 59, 999)
return [start, end]
}
},
{
text: '最近一个月',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
// 设置开始时间为当天的00:00:00
start.setHours(0, 0, 0, 0)
// 设置结束时间为当天的23:59:59
end.setHours(23, 59, 59, 999)
return [start, end]
}
},
{
text: '最近3个月',
value: () => {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
// 设置开始时间为当天的00:00:00
start.setHours(0, 0, 0, 0)
// 设置结束时间为当天的23:59:59
end.setHours(23, 59, 59, 999)
return [start, end]
}
}
]
onMounted(() => {
timeChange(3)
})
// 选择时间范围
const timeChange = (e: number) => {
backDisabled.value = false
preDisabled.value = true
count.value = 0
if (e == 1) {
disabledPicker.value = true
timeValue.value = [setTime(1), setTime()]
} else if (e == 2) {
disabledPicker.value = true
timeValue.value = [setTime(2), setTime()]
} else if (e == 3) {
disabledPicker.value = true
timeValue.value = [setTime(3), setTime()]
} else if (e == 4) {
let year = parseInt(setTime().substring(0, 4))
let month = parseInt(setTime().substring(5, 7))
let date = parseInt(setTime().substring(8, 10))
var start = new Date(year, month - 1, date)
var dayOfWeek = start.getDay() == 0 ? 7 : start.getDay() - 1 // 如果为周日则置为7天
disabledPicker.value = true
timeValue.value = [setTime(0, dayOfWeek), setTime(0, -6 + dayOfWeek)]
} else if (e == 5) {
disabledPicker.value = false
backDisabled.value = true
preDisabled.value = true
timeValue.value = [setTime(), setTime()]
}
if (e == 1 || e == 2) {
timeFlag.value = 0
} else {
timeFlag.value = 1
}
// 添加时分秒
if (timeValue.value && timeValue.value.length === 2) {
if (e != 5) { // 非自定义时间
// 开始时间设置为00:00:00
if (timeValue.value[0] && typeof timeValue.value[0] === 'string' && timeValue.value[0].length === 10) {
timeValue.value[0] += ' 00:00:00'
} else if (timeValue.value[0] instanceof Date) {
timeValue.value[0].setHours(0, 0, 0, 0)
}
// 结束时间设置为23:59:59
if (timeValue.value[1] && typeof timeValue.value[1] === 'string' && timeValue.value[1].length === 10) {
timeValue.value[1] += ' 23:59:59'
} else if (timeValue.value[1] instanceof Date) {
timeValue.value[1].setHours(23, 59, 59, 999)
}
}
}
}
// 当前
const nowTime = () => {
timeChange(interval.value)
}
// 上一个
const preClick = () => {
preDisabled.value = false
let startTime = timeValue.value[0]
let endTime = timeValue.value[1]
let year = parseInt(startTime.substring(0, 4))
let month = parseInt(startTime.substring(5, 7))
let date = parseInt(startTime.substring(8, 10))
//按月
if (interval.value == 3) {
// 换年份
if (month == 1) {
year = year - 1
startTime = year + '-12-01 00:00:00'
endTime = year + '-12-31 23:59:59'
} else if (month <= 10) {
month = month - 1
startTime = year + '-0' + month + '-01 00:00:00'
let day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
} else {
month = month - 1
startTime = year + '-' + month + '-01 00:00:00'
let day = getDays(year, month)
endTime = year + '-' + month + '-' + day + ' 23:59:59'
}
//按周
} else if (interval.value == 4) {
//根据开始时间推
let start = new Date(year, month - 1, date)
start.setDate(start.getDate() - 7)
startTime = formatTime(start) + ' 00:00:00'
var end = new Date(start)
end.setDate(start.getDate() + 6)
endTime = formatTime(end) + ' 23:59:59'
//按季度
} else if (interval.value == 2) {
// 换年份
if (month == 1) {
year = year - 1
startTime = year + '-10-01 00:00:00'
endTime = year + '-12-31 23:59:59'
} else {
// 还是本年
month = month - 3
startTime = year + '-0' + month + '-01 00:00:00'
month = month + 2
var day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
}
//自定义
} else if (interval.value == 1) {
year = year - 1
startTime = year + '-01-01 00:00:00'
endTime = year + '-12-31 23:59:59'
}
timeValue.value = [startTime, endTime]
}
//下一个
const next = () => {
//向后
let startTime = timeValue.value[0]
let endTime = timeValue.value[1]
let year = parseInt(startTime.substring(0, 4))
let month = parseInt(startTime.substring(5, 7))
let date = parseInt(startTime.substring(8, 10))
var now = new Date()
// 获取当前年份
var presentY = now.getFullYear()
// 获取当前月份
var presentM = now.getMonth() + 1
// 获取当前日期
var presentD = now.getDate()
if (interval.value == 3) {
if (month == 12) {
year = year + 1
// 年份进位后,大于当前的年份,是不科学的
if (presentY < year && !props.nextFlag) {
startTime = presentY + '-12-01 00:00:00'
if (presentD < 10) {
endTime = presentY + '-12' + '-0' + presentD + ' 23:59:59'
} else {
endTime = presentY + '-12' + '-' + presentD + ' 23:59:59'
}
// 年份进位后,等于当前的年份
} else if (presentY == year) {
startTime = year + '-01-01 00:00:00'
if (presentM > 1) {
endTime = year + '-01-31 23:59:59'
} else {
if (presentD < 10) {
endTime = year + '-01' + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-01' + '-' + presentD + ' 23:59:59'
}
}
// 年份进位后,依旧小于当前的年份
} else {
startTime = year + '-01-01 00:00:00'
endTime = year + '-01-31 23:59:59'
}
} else {
month = month + 1
// 年份等于当前年份
if (presentY == year) {
// 月份超过当前月份,是不科学的
if (month >= presentM && !props.nextFlag) {
if (presentM < 10) {
startTime = year + '-0' + presentM + '-01 00:00:00'
if (presentD < 10) {
endTime = year + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
} else {
startTime = year + '-' + presentM + '-01 00:00:00'
if (presentD < 10) {
endTime = year + '-' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-' + presentM + '-' + presentD + ' 23:59:59'
}
}
} else {
if (month < 10) {
startTime = year + '-0' + month + '-01 00:00:00'
var day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
} else {
startTime = year + '-' + month + '-01 00:00:00'
var day = getDays(year, month)
endTime = year + '-' + month + '-' + day + ' 23:59:59'
}
}
// 年份小于当前的年份
} else {
if (month < 10) {
startTime = year + '-0' + month + '-01 00:00:00'
var day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
} else {
startTime = year + '-' + month + '-01 00:00:00'
var day = getDays(year, month)
endTime = year + '-' + month + '-' + day + ' 23:59:59'
}
}
}
} else if (interval.value == 2) {
// 前进需要年份进位
if (month == 10) {
year = year + 1
// 年份进位后大于当前年份是不科学的
if (year > presentY && !props.nextFlag) {
startTime = presentY + '-10-01 00:00:00'
if (presentD < 10) {
endTime = year + '-' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-' + presentM + '-' + presentD + ' 23:59:59'
}
} else if (year == presentY) {
startTime = year + '-01-01 00:00:00'
// 当前月份大约3月份
if (presentM > 3) {
endTime = year + '-03-31 23:59:59'
} else {
// 当前月份也在第一季度里
if (presentD < 10) {
endTime = year + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
}
} else {
startTime = year + '-01-01 00:00:00'
endTime = year + '-03-31 23:59:59'
}
} else {
month = month + 3
// 季度进位后,超过当前月份是不科学的
if (year == presentY && !props.nextFlag) {
if (month >= presentM) {
// 当季度进位后大于当前月,以当前月的时间显示季度
if (presentM > 0 && presentM < 4) {
// 第一季度
startTime = year + '-01-01 00:00:00'
if (presentD < 10) {
endTime = year + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
} else if (presentM > 3 && presentM < 7) {
// 第二季度
startTime = year + '-04-01 00:00:00'
if (presentD < 10) {
endTime = year + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
} else if (presentM > 6 && presentM < 10) {
// 第三季度
startTime = year + '-07-01 00:00:00'
if (presentD < 10) {
endTime = year + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
} else {
// 第四季度
startTime = year + '-10-01 00:00:00'
if (presentD < 10) {
endTime = year + '-' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = year + '-' + presentM + '-' + presentD + ' 23:59:59'
}
}
} else {
if (month == 10) {
startTime = year + '-' + month + '-01 00:00:00'
} else {
startTime = year + '-0' + month + '-01 00:00:00'
}
month = month + 2
if (month >= presentM) {
endTime = NowgetEndTime() + ' 23:59:59'
} else {
var day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
}
}
} else {
if (month == 10) {
startTime = year + '-' + month + '-01 00:00:00'
month = month + 2
var day = getDays(year, month)
endTime = year + '-' + month + '-' + day + ' 23:59:59'
} else {
startTime = year + '-0' + month + '-01 00:00:00'
month = month + 2
var day = getDays(year, month)
endTime = year + '-0' + month + '-' + day + ' 23:59:59'
}
}
}
} else if (interval.value == 5) {
// 自定义时间保持原样
} else if (interval.value == 4) {
//根据开始时间推
var start = new Date(year, month - 1, date)
start.setDate(start.getDate() + 7)
startTime = formatTime(start) + ' 00:00:00'
var end = new Date(start)
end.setDate(start.getDate() + 6)
endTime = formatTime(end) + ' 23:59:59'
} else {
year = year + 1
// 年份进位后大于当前年份,是不科学的
if (year >= presentY && !props.nextFlag) {
startTime = presentY + '-01-01 00:00:00'
if (presentM < 10) {
if (presentD < 10) {
endTime = presentY + '-0' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = presentY + '-0' + presentM + '-' + presentD + ' 23:59:59'
}
} else {
if (presentD < 10) {
endTime = presentY + '-' + presentM + '-0' + presentD + ' 23:59:59'
} else {
endTime = presentY + '-' + presentM + '-' + presentD + ' 23:59:59'
}
}
} else {
startTime = year + '-01-01 00:00:00'
endTime = year + '-12-31 23:59:59'
}
}
if (!props.nextFlag) {
if (new Date(endTime).getTime() >= new Date().setHours(0, 0, 0, 0)) {
preDisabled.value = true
}
}
timeValue.value = [startTime, endTime]
}
const setTime = (flag = 0, e = 0) => {
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')
let data = ''
if ((dd < 2 || dd == 0) && interval.value != 4 && !props.theCurrentTime) {
data = window.XEUtils.toDateString(new Date().getTime() - (e + dd) * 3600 * 1000 * 24, 'yyyy-MM-dd')
} else {
data = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'yyyy-MM-dd')
}
if (flag == 1) {
data = data.slice(0, 5) + '01-01'
} else if (flag == 2) {
let quarter = parseInt(data.slice(5, 7))
if (0 < quarter && quarter <= 3) {
data = data.slice(0, 5) + '01-01'
} else if (3 < quarter && quarter <= 6) {
data = data.slice(0, 5) + '04-01'
} else if (6 < quarter && quarter <= 9) {
data = data.slice(0, 5) + '07-01'
} else {
data = data.slice(0, 5) + '10-01'
}
}
if (flag == 3) {
data = data.slice(0, 8) + '01'
}
return data
}
// 获取月份的天数
const getDays = (year: any, month: any) => {
let max = new Date(year, month, 0).getDate()
return max
}
// 时间格式化
const formatTime = (time: any) => {
return (
time.getFullYear() +
'-' +
(time.getMonth() + 1 < 10 ? '0' : '') +
(time.getMonth() + 1) +
'-' +
(time.getDate() < 10 ? '0' : '') +
time.getDate()
)
}
const NowgetEndTime = () => {
let now = new Date()
let sep = '-'
let year = now.getFullYear()
let month: any = now.getMonth() + 1
if (month < 10) {
month = '0' + month
}
let date: any = now.getDate()
if (date < 10) {
date = '0' + date
}
// 拼接当前的日期
let endTime = year + sep + month + sep + date
return endTime
}
const setTimeOptions = (list: any) => {
timeOptions.value = list
}
const setInterval = (value: any) => {
interval.value = value
timeChange(value)
}
// 获取时间范围的同比
function getYearOnYear(startDate: string, endDate: string): [string, string] {
const startYearAgo = new Date(startDate)
startYearAgo.setFullYear(startYearAgo.getFullYear() - 1)
const endYearAgo = new Date(endDate)
endYearAgo.setFullYear(endYearAgo.getFullYear() - 1)
return [formatDate(startYearAgo), formatDate(endYearAgo)]
}
// 获取时间范围的环比
function getMonthOnMonth(startDate: string, endDate: string): [string, string] {
const start = new Date(startDate)
const end = new Date(endDate)
const diffTime = end.getTime() - start.getTime() + 60 * 60 * 24 * 1000 // 计算时间差
const startMonthAgo = new Date(start)
startMonthAgo.setTime(startMonthAgo.getTime() - diffTime) // 将开始时间向前推移相同的时间差
const endMonthAgo = new Date(start)
endMonthAgo.setDate(start.getDate() - 1) // 结束时间是开始时间的前一天
return [formatDate(startMonthAgo), formatDate(endMonthAgo)]
}
// 格式化日期为 YYYY-MM-DD
function formatDate(date: Date): string {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
defineExpose({
timeValue,
interval,
timeFlag,
setTimeOptions,
setInterval,
getYearOnYear,
getMonthOnMonth,
timeChange,
formatDateTimeDisplay // 暴露格式化函数
})
</script>
<style scoped>
.demo-date-picker {
display: flex;
width: 100%;
padding: 0;
flex-wrap: wrap;
}
.demo-date-picker .block {
padding: 30px 0;
text-align: center;
border-right: solid 1px var(--el-border-color);
flex: 1;
}
.demo-date-picker .block:last-child {
border-right: none;
}
.demo-date-picker .demonstration {
display: block;
color: var(--el-text-color-secondary);
font-size: 14px;
margin-bottom: 20px;
}
</style>

View File

@@ -1,23 +1,44 @@
<template>
<div :style="{ height: tableStore.table.height }">
<vxe-table ref="tableRef" height="auto" :data="tableStore.table.data" v-loading="tableStore.table.loading"
v-bind="Object.assign({}, defaultAttribute, $attrs)" @checkbox-all="selectChangeEvent"
@checkbox-change="selectChangeEvent" :showOverflow="showOverflow">
<vxe-table
ref="tableRef"
height="auto"
: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-config="{ remote: true }"
@sort-change="handleSortChange"
>
<!-- Column 组件内部是 el-table-column -->
<template v-if="isGroup">
<GroupColumn :column="tableStore.table.column" />
</template>
<template v-else>
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode">
<Column
:attr="item"
:key="key + '-column'"
v-for="(item, key) in tableStore.table.column"
:tree-node="item.treeNode"
>
<!-- tableStore 预设的列 render 方案 -->
<template v-if="item.render" #default="scope">
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
" />
<FieldRender
:field="item"
:row="scope.row"
:column="scope.column"
:index="scope.rowIndex"
:key="
key +
'-' +
item.render +
'-' +
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
"
/>
</template>
</Column>
</template>
@@ -26,11 +47,16 @@
</div>
<div v-if="tableStore.showPage" class="table-pagination">
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
:page-sizes="pageSizes" background
<el-pagination
: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'"
:total="tableStore.table.total" @size-change="onTableSizeChange"
@current-change="onTableCurrentChange"></el-pagination>
:total="tableStore.table.total"
@size-change="onTableSizeChange"
@current-change="onTableCurrentChange"
></el-pagination>
</div>
<slot name="footer"></slot>
</template>
@@ -51,7 +77,7 @@ const config = useConfig()
const tableRef = ref<VxeTableInstance>()
const tableStore = inject('tableStore') as TableStoreClass
const router = useRouter()
const key = ref(0)
interface Props extends /* @vue-ignore */ Partial<InstanceType<typeof ElTable>> {
isGroup?: boolean
showOverflow?: boolean
@@ -82,7 +108,31 @@ const pageSizes = computed(() => {
}
return defaultSizes
})
const handleSortChange = ({ field, order }: any) => {
// console.log('🚀 ~ handleSortChange ~ prop, order :', field, order)
if (field && order) {
// 根据当前排序条件对所有数据进行排序
const list = tableStore.table.copyData.sort((a, b) => {
if (order === 'asc') {
return a[field] > b[field] ? 1 : -1
} else {
return a[field] < b[field] ? 1 : -1
}
})
if (tableStore.isWebPaging) {
tableStore.table.data = JSON.parse(
JSON.stringify(
window.XEUtils.chunk(list, tableStore.table.params!.pageSize)[tableStore.table.params!.pageNum - 1]
)
)
} else {
tableStore.table.data = JSON.parse(JSON.stringify(list))
}
// key.value += 1
}
}
/*
* 记录选择的项
*/
@@ -98,8 +148,6 @@ watch(
() => tableStore.table.allFlag,
newVal => {
if (tableStore.table.allFlag) {
console.log("🚀 ~ tableStore.table:", tableStore.exportName || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '')
tableRef.value?.exportData({
filename: tableStore.exportName || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '', // 文件名字
sheetName: 'Sheet1',
@@ -107,14 +155,15 @@ watch(
useStyle: true,
data: tableStore.table.allData, // 数据源 // 过滤那个字段导出
columnFilterMethod: function (column: any) {
return !(column.column.title === undefined || column.column.title === '序号' || column.column.title === '操作')
return !(
column.column.title === undefined ||
column.column.title === '序号' ||
column.column.title === '操作'
)
}
})
tableStore.table.allFlag = false
}
}
)
watch(

View File

@@ -1,34 +1,73 @@
<!-- 设备管理使用折叠面板渲染多个tree -->
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
<Icon v-show="menuCollapse" @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 mt20 menu-collapse"
style="cursor: pointer" />
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
<Icon
v-show="menuCollapse"
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<!-- <el-form-item> -->
<el-input maxlength="32" show-word-limit v-model.trim="filterText" autocomplete="off"
placeholder="请输入内容" clearable>
<el-input
maxlength="32"
show-word-limit
v-model.trim="filterText"
autocomplete="off"
placeholder="请输入内容"
clearable
>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
<!-- </el-form-item> -->
<Icon @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse"
style="cursor: pointer" v-if="props.canExpand" />
<Icon
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 menu-collapse"
style="cursor: pointer"
v-if="props.canExpand"
/>
</div>
<el-collapse :accordion="true" v-model.trim="activeName" style="flex: 1; height: 100%"
@change="changeDevice">
<el-collapse
:accordion="true"
v-model.trim="activeName"
style="flex: 1; height: 100%"
@change="changeDevice"
>
<el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0">
<el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10">
<el-option label="功能调试" value="2"></el-option>
<el-option label="出厂调试" value="3"></el-option>
<el-option label="正式投运" value="4"></el-option>
</el-select>
<el-tree
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 300px)' : 'calc(100vh - 238px)' }"
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
node-key="id" default-expand-all v-bind="$attrs" :data="zlDeviceData" style="overflow: auto">
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
ref="treeRef1"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
default-expand-all
v-bind="$attrs"
:data="zlDevList"
style="overflow: auto"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
v-if="data.icon" />
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
@@ -37,13 +76,24 @@
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
<el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
style="overflow: auto">
ref="treeRef2"
:props="defaultProps"
highlight-current
default-expand-all
:filter-node-method="filterNode"
node-key="id"
:data="bxsDeviceData"
v-bind="$attrs"
style="overflow: auto"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
v-if="data.icon" />
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
@@ -84,8 +134,10 @@ const defaultProps = {
label: 'name',
value: 'id'
}
const process = ref('')
//治理设备数据
const zlDeviceData = ref([])
const zlDevList = ref<any>([])
//便携式设备数据
const bxsDeviceData = ref([])
watch(
@@ -118,6 +170,38 @@ watch(filterText, val => {
treeRef2.value!.filter(val)
}
})
watch(process, val => {
if (val == '') {
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
}
setTimeout(() => {
changeDevice(activeName.value)
}, 0)
})
function filterProcess(nodes: any) {
if (process.value == '') {
return nodes
}
return nodes
.map(node => {
// 递归处理子节点
const children = node.children ? filterProcess(node.children) : []
// 如果当前节点的process=4或者有子节点满足条件则保留当前节点
if (node.process == process.value || children.length > 0) {
return {
...node,
children: node.children
}
}
// 否则过滤掉当前节点
return null
})
.filter(Boolean) // 移除null节点
}
const onMenuCollapse = () => {
menuCollapse.value = !menuCollapse.value
proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
@@ -126,14 +210,12 @@ const filterNode = (value: string, data: any, node: any) => {
if (!value) return true
// return data.name.includes(value)
if (data.name) {
return chooseNode(value, data, node)
}
}
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
return true
}
@@ -161,7 +243,9 @@ const chooseNode = (value: string, data: any, node: any) => {
const changeDevice = (val: any) => {
let arr1: any = []
zlDeviceData.value.forEach((item: any) => {
//zlDeviceData
zlDevList.value.forEach((item: any) => {
item.children.forEach((item2: any) => {
item2.children.forEach((item3: any) => {
arr1.push(item3)
@@ -197,6 +281,7 @@ defineExpose({ treeRef1, treeRef2 })
onMounted(() => {
setTimeout(() => {
if (zlDeviceData.value.length != 0) {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
@@ -205,7 +290,9 @@ onMounted(() => {
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = ''
}
changeDevice(activeName.value)
nextTick(() => {
changeDevice(activeName.value)
})
}, 500)
})
</script>

View File

@@ -32,6 +32,7 @@ const config = useConfig()
const tree = ref()
const treRef = ref()
const changeDeviceType = (val: any, obj: any) => {
console.log("🚀 ~ changeDeviceType ~ val:", val,obj)
emit('deviceTypeChange', val, obj)
}
getDeviceTree().then(res => {

View File

@@ -12,11 +12,9 @@ import { useDictData } from '@/stores/dictData'
// const props = defineProps(['template'])
interface Props {
template?: boolean
}
const props = withDefaults(defineProps<Props>(), {
template: false,
template: false
})
defineOptions({
name: 'govern/deviceTree'
@@ -29,29 +27,25 @@ const dictData = useDictData()
const treRef = ref()
const width = ref('')
const info = () => {
tree.value = []
let arr1: any[] = []
let arr2: any[] = []
getLineTree().then(res => {
let arr1: any[] = []
let arr2: any[] = []
//治理设备
res.data.map((item: any) => {
if (item.name == '治理设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.level=1
item.level = 1
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.level=1
item2.level = 1
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.level=1
item3.level = 1
item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => {
@@ -71,13 +65,15 @@ const info = () => {
item.color = item.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-Platform'
item2.color = item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item2.color =
item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
arr2.push(item2)
})
})
}
})
tree.value = res.data
nextTick(() => {
if (arr1.length) {
//初始化选中
@@ -98,7 +94,6 @@ const info = () => {
// })
// }
else {
emit('init', arr2[0])
}
})
@@ -108,17 +103,16 @@ const changePointType = (val: any, obj: any) => {
emit('pointTypeChange', val, obj)
}
if (props.template) {
getTemplateByDept({ id: dictData.state.area[0].id }).then((res: any) => {
emit('Policy', res.data)
info()
}).catch(err => {
info()
})
getTemplateByDept({ id: dictData.state.area[0].id })
.then((res: any) => {
emit('Policy', res.data)
info()
})
.catch(err => {
info()
})
} else {
info()
}
onMounted(() => {
})
onMounted(() => {})
</script>

View File

@@ -1,9 +1,16 @@
<!-- 设备监控使用折叠面板渲染多个tree -->
<template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
<Icon v-show="menuCollapse" @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 mt20 menu-collapse" style="cursor: pointer"
v-if="route.path != '/admin/govern/reportCore/statistics/index'" />
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
<Icon
v-show="menuCollapse"
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
v-if="route.path != '/admin/govern/reportCore/statistics/index'"
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1, display: menuCollapse ? 'none' : '' }">
<div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
@@ -11,22 +18,49 @@
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
<Icon @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse"
<Icon
@click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''"
size="18"
class="fold ml10 menu-collapse"
style="cursor: pointer"
v-if="props.canExpand && route.path != '/admin/govern/reportCore/statistics/index'" />
v-if="props.canExpand && route.path != '/admin/govern/reportCore/statistics/index'"
/>
</div>
<el-collapse :accordion="true" v-model.trim="activeName" style="flex: 1; height: 100%"
@change="changeDevice">
<el-collapse
:accordion="true"
v-model.trim="activeName"
style="flex: 1; height: 100%"
@change="changeDevice"
>
<el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0">
<el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10">
<el-option label="功能调试" value="2"></el-option>
<el-option label="出厂调试" value="3"></el-option>
<el-option label="正式投运" value="4"></el-option>
</el-select>
<el-tree
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 300px)' : 'calc(100vh - 238px)' }"
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
node-key="id" default-expand-all v-bind="$attrs" :data="zlDeviceData" style="overflow: auto">
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
ref="treeRef1"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
default-expand-all
v-bind="$attrs"
:data="zlDevList"
style="overflow: auto"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
v-if="data.icon" />
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
@@ -35,13 +69,24 @@
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
<el-tree
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
style="overflow: auto">
ref="treeRef2"
:props="defaultProps"
highlight-current
default-expand-all
:filter-node-method="filterNode"
node-key="id"
:data="bxsDeviceData"
v-bind="$attrs"
style="overflow: auto"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
v-if="data.icon" />
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
@@ -55,7 +100,7 @@
<script lang="ts" setup>
import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus'
import { ref, watch, defineEmits, onMounted, nextTick } from 'vue'
import { ref, watch, defineEmits, onMounted, nextTick, computed } from 'vue'
import { useRoute } from 'vue-router'
defineOptions({
name: 'govern/tree'
@@ -74,7 +119,7 @@ const props = withDefaults(defineProps<Props>(), {
type: '',
data: []
})
const process = ref('')
const route = useRoute()
const { proxy } = useCurrentInstance()
const menuCollapse = ref(false)
@@ -86,6 +131,7 @@ const defaultProps = {
}
//治理设备数据
const zlDeviceData = ref<any>([])
const zlDevList = ref<any>([])
//便携式设备数据
const bxsDeviceData = ref<any>([])
watch(
@@ -97,12 +143,26 @@ watch(
item.children.map((vv: any) => {
zlDeviceData.value.push(vv)
})
// console.log('🚀 ~ item.children.map ~ zlDeviceData.value:', zlDeviceData.value)
} else if (item.name == '便携式设备') {
item.children.map((vv: any) => {
bxsDeviceData.value.push(vv)
})
}
})
if (zlDeviceData.value.length != 0) {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = ''
}
nextTick(() => {
changeDevice(activeName.value)
})
}
},
{
@@ -118,9 +178,21 @@ watch(filterText, val => {
treeRef2.value!.filter(val)
}
})
watch(process, val => {
if (val == '') {
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
} else {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
}
setTimeout(() => {
changeDevice(activeName.value)
}, 0)
})
const changeDevice = (val: any) => {
let arr1: any = []
zlDeviceData.value.forEach((item: any) => {
//zlDeviceData
zlDevList.value.forEach((item: any) => {
item.children.forEach((item2: any) => {
item2.children.forEach((item3: any) => {
item3.children.forEach((item4: any) => {
@@ -162,14 +234,34 @@ const filterNode = (value: string, data: any, node: any) => {
if (!value) return true
// return data.name.includes(value)
if (data.name) {
return chooseNode(value, data, node)
}
}
function filterProcess(nodes: any) {
if (process.value == '') {
return nodes
}
return nodes
.map(node => {
// 递归处理子节点
const children = node.children ? filterProcess(node.children) : []
// 如果当前节点的process=4或者有子节点满足条件则保留当前节点
if (node.process == process.value || children.length > 0) {
return {
...node,
children: node.children
}
}
// 否则过滤掉当前节点
return null
})
.filter(Boolean) // 移除null节点
}
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) {
return true
}
@@ -200,18 +292,10 @@ const treeRef1 = ref<InstanceType<typeof ElTree>>()
const treeRef2 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2 })
onMounted(() => {
setTimeout(() => {
if (zlDeviceData.value.length != 0) {
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = ''
}
changeDevice(activeName.value)
}, 500)
// nextTick(() => {
// // setTimeout(() => {
// // }, 500)
// })
})
</script>

View File

@@ -1,298 +1,313 @@
import type { AxiosRequestConfig, Method } from 'axios'
import axios from 'axios'
import { ElLoading, ElMessage, ElNotification, type LoadingOptions } from 'element-plus'
import { refreshToken } from '@/api/user-boot/user'
import router from '@/router/index'
import { useAdminInfo } from '@/stores/adminInfo'
import { set } from 'lodash'
window.requests = []
window.tokenRefreshing = false
const pendingMap = new Map()
const loadingInstance: LoadingInstance = {
target: null,
count: 0
}
/**
* 根据运行环境获取基础请求URL
*/
export const getUrl = (): string => {
return '/api'
}
/**
* 创建`Axios`
* 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise`
* 关闭`reductDataFormat`,返回类型则为`AxiosPromise`
*/
function createAxios<Data = any, T = ApiPromise<Data>>(
axiosConfig: AxiosRequestConfig,
options: Options = {},
loading: LoadingOptions = {}
): T {
const adminInfo = useAdminInfo()
const Axios = axios.create({
baseURL: getUrl(),
timeout: 1000 * 60 * 5,
headers: {},
responseType: 'json'
})
options = Object.assign(
{
CancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true
loading: false, // 是否开启loading层效果, 默认为false
reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true
showErrorMessage: true, // 是否开启接口错误信息展示,默认为true
showCodeMessage: true, // 是否开启code不为1时的信息提示, 默认为true
showSuccessMessage: false, // 是否开启code为1时的信息提示, 默认为false
anotherToken: '' // 当前请求使用另外的用户token
},
options
)
// 请求拦截
Axios.interceptors.request.use(
config => {
// if(config.url?.substring(0, 13)=='/advance-boot'){
// config.url=config.url?.slice(13)
// config.baseURL='/hzj'
// }
// 取消重复请求
if (
!(
config.url == '/system-boot/file/upload' ||
config.url == '/harmonic-boot/grid/getAssessOverview' ||
config.url == '/harmonic-boot/gridDiagram/getGridDiagramAreaData'
)
)
removePending(config)
options.CancelDuplicateRequest && addPending(config)
// 创建loading实例
if (options.loading) {
loadingInstance.count++
if (loadingInstance.count === 1) {
loadingInstance.target = ElLoading.service(loading)
}
}
// 自动携带token
if (config.headers) {
const token = adminInfo.getToken()
if (token) {
;(config.headers as anyObj).Authorization = token
} else {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
}
}
if (config.url == '/user-boot/user/generateSm2Key' || config.url == '/pqs-auth/oauth/token') {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截
Axios.interceptors.response.use(
response => {
removePending(response.config)
options.loading && closeLoading(options) // 关闭loading
if (
response.data.code === 'A0000' ||
response.data.type === 'application/json' ||
Array.isArray(response.data) ||
response.data.size
// ||
// response.data.type === 'application/octet-stream' ||
// response.data.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
) {
return options.reductDataFormat ? response.data : response
} else if (response.data.code == 'A0202') {
if (!window.tokenRefreshing) {
window.tokenRefreshing = true
return refreshToken()
.then(res => {
adminInfo.setToken(res.data.access_token, 'auth')
window.requests.forEach(cb => cb(res.data.access_token))
window.requests = []
return Axios(response.config)
})
.catch(err => {
adminInfo.removeToken()
router.push({ name: 'login' })
return Promise.reject(err)
})
.finally(() => {
window.tokenRefreshing = false
})
} else {
return new Promise(resolve => {
// 用函数形式将 resolve 存入,等待刷新后再执行
window.requests.push((token: string) => {
response.headers.Authorization = `${token}`
resolve(Axios(response.config))
})
})
}
} else if (response.data.code == 'A0024') {
// 登录失效
ElMessage({
type: 'error',
message: response.data.message
})
adminInfo.removeToken()
router.push({ name: 'login' })
return Promise.reject(response.data)
} else {
if (options.showCodeMessage) {
if (response.config.url == '/access-boot/device/wlRegister') {
setTimeout(() => {
ElMessage.error(response.data.message || '未知错误')
}, 6000)
} else {
ElMessage.error(response.data.message || '未知错误')
}
}
return Promise.reject(response.data)
}
},
error => {
error.config && removePending(error.config)
options.loading && closeLoading(options) // 关闭loading
return Promise.reject(error) // 错误继续返回给到具体页面
}
)
return Axios(axiosConfig) as T
}
export default createAxios
/**
* 关闭Loading层实例
*/
function closeLoading(options: Options) {
if (options.loading && loadingInstance.count > 0) loadingInstance.count--
if (loadingInstance.count === 0) {
loadingInstance.target.close()
loadingInstance.target = null
}
}
/**
* 储存每个请求的唯一cancel回调, 以此为标识
*/
function addPending(config: AxiosRequestConfig) {
const pendingKey = getPendingKey(config)
config.cancelToken =
config.cancelToken ||
new axios.CancelToken(cancel => {
if (!pendingMap.has(pendingKey)) {
pendingMap.set(pendingKey, cancel)
}
})
}
/**
* 删除重复的请求
*/
function removePending(config: AxiosRequestConfig) {
const pendingKey = getPendingKey(config)
if (pendingMap.has(pendingKey)) {
const cancelToken = pendingMap.get(pendingKey)
cancelToken(pendingKey)
pendingMap.delete(pendingKey)
}
}
/**
* 生成每个请求的唯一key
*/
function getPendingKey(config: AxiosRequestConfig) {
let { data } = config
const { url, method, params, headers } = config
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
return [
url,
method,
headers && (headers as anyObj).Authorization ? (headers as anyObj).Authorization : '',
headers && (headers as anyObj)['ba-user-token'] ? (headers as anyObj)['ba-user-token'] : '',
JSON.stringify(params),
JSON.stringify(data)
].join('&')
}
/**
* 根据请求方法组装请求数据/参数
*/
export function requestPayload(method: Method, data: anyObj, paramsPOST: boolean) {
if (method == 'GET') {
return {
params: data
}
} else if (method == 'POST') {
if (paramsPOST) {
return { params: data }
} else {
return { data: data }
}
}
}
// 适配器, 用于适配不同的请求方式
export function baseRequest(url, value = {}, method = 'post', options = {}) {
url = sysConfig?.API_URL + url
if (method === 'post') {
return service.post(url, value, options)
} else if (method === 'get') {
return service.get(url, { params: value, ...options })
} else if (method === 'formdata') {
// form-data表单提交的方式
return service.post(url, qs.stringify(value), {
headers: {
'Content-Type': 'multipart/form-data'
},
...options
})
} else {
// 其他请求方式例如put、delete
return service({
method: method,
url: url,
data: value,
...options
})
}
}
// 模块内的请求, 会自动加上模块的前缀
export const moduleRequest =
moduleUrl =>
(url, ...arg) => {
return baseRequest(moduleUrl + url, ...arg)
}
interface LoadingInstance {
target: any
count: number
}
interface Options {
// 是否开启取消重复请求, 默认为 true
CancelDuplicateRequest?: boolean
// 是否开启loading层效果, 默认为false
loading?: boolean
// 是否开启简洁的数据结构响应, 默认为true
reductDataFormat?: boolean
// 是否开启code不为A0000时的信息提示, 默认为true
showCodeMessage?: boolean
// 是否开启code为0时的信息提示, 默认为false
showSuccessMessage?: boolean
// 当前请求使用另外的用户token
anotherToken?: string
}
import type { AxiosRequestConfig, Method } from 'axios'
import axios from 'axios'
import { ElLoading, ElMessage, ElNotification, type LoadingOptions } from 'element-plus'
import { refreshToken } from '@/api/user-boot/user'
import router from '@/router/index'
import { useAdminInfo } from '@/stores/adminInfo'
window.requests = []
window.tokenRefreshing = false
let loginExpireTimer:any=null
const pendingMap = new Map()
const loadingInstance: LoadingInstance = {
target: null,
count: 0
}
/**
* 根据运行环境获取基础请求URL
*/
export const getUrl = (): string => {
return '/api'
}
/**
* 创建`Axios`
* 默认开启`reductDataFormat(简洁响应)`,返回类型为`ApiPromise`
* 关闭`reductDataFormat`,返回类型则为`AxiosPromise`
*/
function createAxios<Data = any, T = ApiPromise<Data>>(
axiosConfig: AxiosRequestConfig,
options: Options = {},
loading: LoadingOptions = {}
): T {
const adminInfo = useAdminInfo()
const Axios = axios.create({
baseURL: getUrl(),
timeout: 1000 * 60 * 5,
headers: {},
responseType: 'json'
})
options = Object.assign(
{
CancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true
loading: false, // 是否开启loading层效果, 默认为false
reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true
showErrorMessage: true, // 是否开启接口错误信息展示,默认为true
showCodeMessage: true, // 是否开启code不为1时的信息提示, 默认为true
showSuccessMessage: false, // 是否开启code为1时的信息提示, 默认为false
anotherToken: '' // 当前请求使用另外的用户token
},
options
)
// 请求拦截
Axios.interceptors.request.use(
config => {
// if(config.url?.substring(0, 13)=='/advance-boot'){
// config.url=config.url?.slice(13)
// config.baseURL='/hzj'
// }
// 取消重复请求
if (
!(
config.url == '/system-boot/file/upload' ||
config.url == '/harmonic-boot/grid/getAssessOverview' ||
config.url == '/harmonic-boot/gridDiagram/getGridDiagramAreaData'
)
)
removePending(config)
options.CancelDuplicateRequest && addPending(config)
// 创建loading实例
if (options.loading) {
loadingInstance.count++
if (loadingInstance.count === 1) {
loadingInstance.target = ElLoading.service(loading)
}
}
// 自动携带token
if (config.headers) {
const token = adminInfo.getToken()
if (token) {
;(config.headers as anyObj).Authorization = token
} else {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
}
}
if (config.url == '/user-boot/user/generateSm2Key' || config.url == '/pqs-auth/oauth/token') {
config.headers.Authorization = 'Basic bmpjbnRlc3Q6bmpjbnBxcw=='
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截
Axios.interceptors.response.use(
response => {
removePending(response.config)
options.loading && closeLoading(options) // 关闭loading
if (
response.data.code === 'A0000' ||
response.data.type === 'application/json' ||
Array.isArray(response.data) ||
response.data.size
// ||
// response.data.type === 'application/octet-stream' ||
// response.data.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
) {
return options.reductDataFormat ? response.data : response
} else if (response.data.code == 'A0202') {
if (!window.tokenRefreshing) {
window.tokenRefreshing = true
return refreshToken()
.then(res => {
adminInfo.setToken(res.data.access_token, 'auth')
window.requests.forEach(cb => cb(res.data.access_token))
window.requests = []
return Axios(response.config)
})
.catch(err => {
adminInfo.removeToken()
router.push({ name: 'login' })
return Promise.reject(err)
})
.finally(() => {
window.tokenRefreshing = false
})
} else {
return new Promise(resolve => {
// 用函数形式将 resolve 存入,等待刷新后再执行
window.requests.push((token: string) => {
response.headers.Authorization = `${token}`
resolve(Axios(response.config))
})
})
}
} else if (response.data.code == 'A0024') {
// // 登录失效
// 清除上一次的定时器
if (loginExpireTimer) {
clearTimeout(loginExpireTimer)
}
loginExpireTimer = setTimeout(() => {
ElNotification({
type: 'error',
message: response.data.message
})
adminInfo.removeToken()
router.push({ name: 'login' })
loginExpireTimer = null // 执行后清空定时器
}, 100) // 可根据实际情况调整延迟时间
return Promise.reject(response.data)
// // 登录失效
// ElMessage({
// type: 'error',
// message: response.data.message
// })
// adminInfo.removeToken()
// router.push({ name: 'login' })
// return Promise.reject(response.data)
} else {
if (options.showCodeMessage) {
if (response.config.url == '/access-boot/device/wlRegister') {
setTimeout(() => {
ElMessage.error(response.data.message || '未知错误')
}, 6000)
} else {
ElMessage.error(response.data.message || '未知错误')
}
}
return Promise.reject(response.data)
}
},
error => {
error.config && removePending(error.config)
options.loading && closeLoading(options) // 关闭loading
return Promise.reject(error) // 错误继续返回给到具体页面
}
)
return Axios(axiosConfig) as T
}
export default createAxios
/**
* 关闭Loading层实例
*/
function closeLoading(options: Options) {
if (options.loading && loadingInstance.count > 0) loadingInstance.count--
if (loadingInstance.count === 0) {
loadingInstance.target.close()
loadingInstance.target = null
}
}
/**
* 储存每个请求的唯一cancel回调, 以此为标识
*/
function addPending(config: AxiosRequestConfig) {
const pendingKey = getPendingKey(config)
config.cancelToken =
config.cancelToken ||
new axios.CancelToken(cancel => {
if (!pendingMap.has(pendingKey)) {
pendingMap.set(pendingKey, cancel)
}
})
}
/**
* 删除重复的请求
*/
function removePending(config: AxiosRequestConfig) {
const pendingKey = getPendingKey(config)
if (pendingMap.has(pendingKey)) {
const cancelToken = pendingMap.get(pendingKey)
cancelToken(pendingKey)
pendingMap.delete(pendingKey)
}
}
/**
* 生成每个请求的唯一key
*/
function getPendingKey(config: AxiosRequestConfig) {
let { data } = config
const { url, method, params, headers } = config
if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
return [
url,
method,
headers && (headers as anyObj).Authorization ? (headers as anyObj).Authorization : '',
headers && (headers as anyObj)['ba-user-token'] ? (headers as anyObj)['ba-user-token'] : '',
JSON.stringify(params),
JSON.stringify(data)
].join('&')
}
/**
* 根据请求方法组装请求数据/参数
*/
export function requestPayload(method: Method, data: anyObj, paramsPOST: boolean) {
if (method == 'GET') {
return {
params: data
}
} else if (method == 'POST') {
if (paramsPOST) {
return { params: data }
} else {
return { data: data }
}
}
}
// 适配器, 用于适配不同的请求方式
export function baseRequest(url, value = {}, method = 'post', options = {}) {
url = sysConfig?.API_URL + url
if (method === 'post') {
return service.post(url, value, options)
} else if (method === 'get') {
return service.get(url, { params: value, ...options })
} else if (method === 'formdata') {
// form-data表单提交的方式
return service.post(url, qs.stringify(value), {
headers: {
'Content-Type': 'multipart/form-data'
},
...options
})
} else {
// 其他请求方式例如put、delete
return service({
method: method,
url: url,
data: value,
...options
})
}
}
// 模块内的请求, 会自动加上模块的前缀
export const moduleRequest =
moduleUrl =>
(url, ...arg) => {
return baseRequest(moduleUrl + url, ...arg)
}
interface LoadingInstance {
target: any
count: number
}
interface Options {
// 是否开启取消重复请求, 默认为 true
CancelDuplicateRequest?: boolean
// 是否开启loading层效果, 默认为false
loading?: boolean
// 是否开启简洁的数据结构响应, 默认为true
reductDataFormat?: boolean
// 是否开启code不为A0000时的信息提示, 默认为true
showCodeMessage?: boolean
// 是否开启code为0时的信息提示, 默认为false
showSuccessMessage?: boolean
// 当前请求使用另外的用户token
anotherToken?: string
}

View File

@@ -34,6 +34,7 @@ export default class TableStore {
ref: null,
selection: [],
data: [],
copyData: [],
allData: [],
allFlag: false,
webPagingData: [],
@@ -93,6 +94,7 @@ export default class TableStore {
this.table.data = []
this.table.total = 0
}
this.table.copyData = filtration(this.table.data)
if (Array.isArray(res)) {
this.table.data = res
}
@@ -204,7 +206,7 @@ export default class TableStore {
this.table.allData = filtration(res.data.records || res.data)
this.table.allFlag = data.showAllFlag || true
})
},1500)
}, 1500)
}
]
])

View File

@@ -29,7 +29,7 @@ const tableStore = new TableStore({
{ title: '角色', field: 'roleName' },
// { title: '部门', field: 'deptId' },
{ title: '电话', field: 'phoneShow' },
{ title: '注册时间', field: 'registerTime' },
{ title: '注册时间', field: 'registerTime', sortable: true },
{ title: '类型', field: 'casualUserName' },
{ title: '状态', field: 'stateName' },
{

View File

@@ -53,8 +53,8 @@ const tableStore = new TableStore({
{ title: '角色', field: 'roleName', minWidth: '130' },
// { title: '部门', field: 'deptName', minWidth: '200' },
{ title: '电话', field: 'phoneShow', minWidth: '100' },
{ title: '注册时间', field: 'registerTime', minWidth: '130' },
{ title: '登录时间', field: 'loginTime', minWidth: '130' },
{ title: '注册时间', field: 'registerTime', minWidth: '130', sortable: true },
{ title: '登录时间', field: 'loginTime', minWidth: '130', sortable: true },
{ title: '类型', field: 'casualUserName', minWidth: '80' },
{
title: '状态',

View File

@@ -25,8 +25,13 @@
</template> -->
<template #select>
<el-form-item label="设备名称">
<el-input maxlength="32" clearable show-word-limit v-model.trim="tableStore.table.params.searchValue"
placeholder="请输入设备名称" />
<el-input
maxlength="32"
clearable
show-word-limit
v-model.trim="tableStore.table.params.searchValue"
placeholder="请输入设备名称"
/>
</el-form-item>
</template>
</TableHeader>
@@ -80,9 +85,16 @@ const tableStore = new TableStore({
exportName: '异常事件',
publicHeight: 65,
column: [
{
title: '序号',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'ndid', align: 'center' },
{ title: '告警代码', field: 'code', align: 'center' },
{ title: '异常时间', field: 'evtTime', align: 'center' }
{ title: '异常时间', field: 'evtTime', align: 'center', sortable: true },
{ title: '告警代码', field: 'code', align: 'center', sortable: true }
]
})
@@ -112,6 +124,6 @@ onMounted(() => {
setTimeout(() => {
tableStore.table.height = mainHeight(200).height as any
}, 0)
const addMenu = () => { }
const addMenu = () => {}
</script>
<style></style>

View File

@@ -2,15 +2,26 @@
<TableHeader datePicker ref="refheader" showExport>
<template v-slot:select>
<el-form-item label="数据来源">
<el-cascader v-model.trim="tableStore.table.params.cascader" placeholder="请选择数据来源"
@change="sourceChange" :options="deviceTreeOptions" :show-all-levels="false"
:props="{ checkStrictly: true }" clearable></el-cascader>
<el-cascader
v-model.trim="tableStore.table.params.cascader"
filterable
placeholder="请选择数据来源"
@change="sourceChange"
:options="deviceTreeOptions"
:show-all-levels="false"
:props="{ checkStrictly: true }"
clearable
></el-cascader>
<!-- <el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue" placeholder="请输入设备名称" /> -->
</el-form-item>
<el-form-item label="级别">
<el-select v-model.trim="tableStore.table.params.level" placeholder="请选择级别" clearable>
<el-option v-for="item in rankOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
<el-option
v-for="item in rankOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</template>
@@ -65,29 +76,64 @@ const tableStore = new TableStore({
exportName: '设备告警',
publicHeight: 65,
column: [
{
title: '序号',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'equipmentName', align: 'center' },
{ title: '工程名称', field: 'engineeringName', align: 'center' },
{ title: '项目名称', field: 'projectName', align: 'center' },
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 110, sortable: true },
{
title: '告警代码', field: 'code', align: 'center', formatter: (row: any) => {
title: '模块信息',
field: 'moduleNo',
align: 'center',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '事件描述', field: 'showName',
title: '告警代码',
field: 'code',
align: 'center',
formatter: (row: any) => {
return row.cellValue ? row.cellValue : '/'
},
sortable: true
},
{
title: '级别', field: 'level', formatter: (row: any) => {
return row.cellValue == 1 ? '1级' : row.cellValue == 2 ? '2级' : row.cellValue == 3 ? '3级' : '/'
}
title: '事件描述',
field: 'showName'
},
{ title: '发生时刻', field: 'startTime', align: 'center' }
],
beforeSearchFun: () => {
{
title: '级别',
field: 'level',
}
render: 'tag',
custom: {
1: 'danger',
2: 'warning',
3: 'success'
},
replaceValue: {
1: '1级',
2: '2级',
3: '3级'
}
}
// {
// title: '级别',
// field: 'level',
// formatter: (row: any) => {
// return row.cellValue == 1 ? '1级' : row.cellValue == 2 ? '2级' : row.cellValue == 3 ? '3级' : '/'
// }
// }
],
beforeSearchFun: () => {}
})
provide('tableStore', tableStore)
@@ -129,7 +175,6 @@ const sourceChange = (e: any) => {
tableStore.table.params.deviceTypeId = e[0] || ''
tableStore.table.params.engineeringid = e[1] || ''
tableStore.table.params.projectId = e[2] || ''
}
}
}
@@ -140,6 +185,6 @@ onMounted(() => {
setTimeout(() => {
// tableStore.table.height = mainHeight(200).height as any
}, 0)
const addMenu = () => { }
const addMenu = () => {}
</script>
<style></style>

View File

@@ -2,9 +2,16 @@
<TableHeader datePicker ref="refheader" showExport>
<template v-slot:select>
<el-form-item label="数据来源">
<el-cascader v-model.trim="tableStore.table.params.cascader" placeholder="请选择数据来源"
@change="sourceChange" :options="deviceTreeOptions" :show-all-levels="false"
:props="{ checkStrictly: true }" clearable></el-cascader>
<el-cascader
v-model.trim="tableStore.table.params.cascader"
filterable
placeholder="请选择数据来源"
@change="sourceChange"
:options="deviceTreeOptions"
:show-all-levels="false"
:props="{ checkStrictly: true }"
clearable
></el-cascader>
<!-- <el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue" placeholder="请输入设备名称" /> -->
</el-form-item>
<!-- <el-form-item label="级别">
@@ -69,15 +76,21 @@ const tableStore = new TableStore({
exportName: '稳态越限告警',
publicHeight: 65,
column: [
{
title: '序号',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'equipmentName', align: 'center' },
{ title: '工程名称', field: 'engineeringName', align: 'center' },
{ title: '项目名称', field: 'projectName', align: 'center' },
{ title: '事件描述', field: 'showName', align: 'center' },
{ title: '发生时刻', field: 'startTime', align: 'center' }
],
beforeSearchFun: () => {
{ title: '发生时刻', field: 'startTime', align: 'center', sortable: true },
}
{ title: '事件描述', field: 'showName', align: 'center' }
],
beforeSearchFun: () => {}
})
provide('tableStore', tableStore)
@@ -120,10 +133,8 @@ const sourceChange = (e: any) => {
tableStore.table.params.deviceTypeId = e[0] || ''
tableStore.table.params.engineeringid = e[1] || ''
tableStore.table.params.projectId = e[2] || ''
}
}
}
onMounted(() => {
tableStore.index()
@@ -131,6 +142,6 @@ onMounted(() => {
setTimeout(() => {
tableStore.table.height = mainHeight(200).height as any
}, 0)
const addMenu = () => { }
const addMenu = () => {}
</script>
<style></style>

View File

@@ -3,9 +3,16 @@
<TableHeader datePicker showExport>
<template v-slot:select>
<el-form-item label="数据来源">
<el-cascader placeholder="请选择数据来源" @change="sourceChange"
v-model.trim="tableStore.table.params.cascader" :options="deviceTreeOptions"
:show-all-levels="false" :props="{ checkStrictly: true }" clearable></el-cascader>
<el-cascader
placeholder="请选择数据来源"
@change="sourceChange"
filterable
v-model.trim="tableStore.table.params.cascader"
:options="deviceTreeOptions"
:show-all-levels="false"
:props="{ checkStrictly: true }"
clearable
></el-cascader>
<!-- <el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue" placeholder="请输入设备名称" /> -->
</el-form-item>
<!-- <el-form-item label="级别">
@@ -19,8 +26,13 @@
<Table></Table>
</div>
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false" :wp="wp" />
<waveFormAnalysis
v-loading="loading"
v-if="isWaveCharts"
ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false"
:wp="wp"
/>
<!-- <div style="height: 300px;"> -->
<!-- <div style="padding: 10px" v-if="!view" v-loading="loading">
@@ -61,7 +73,7 @@ import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import shushiboxi from '@/components/echarts/shushiboxi.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue';
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import rmsboxi from '@/components/echarts/rmsboxi.vue'
import { analyseWave } from '@/api/common'
import { mainHeight } from '@/utils/layout'
@@ -109,17 +121,24 @@ const tableStore = new TableStore({
method: 'POST',
publicHeight: 65,
exportName: '暂态事件',
column: [
column: [ {
title: '序号',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'equipmentName', align: 'center' },
{ title: '工程名称', field: 'engineeringName', align: 'center' },
{ title: '项目名称', field: 'projectName', align: 'center' },
{ title: '发生时刻', field: 'startTime', align: 'center', width: '240',sortable: true },
{ title: '监测点名称', field: 'lineName', align: 'center' },
{ title: '事件描述', field: 'showName', align: 'center' },
{ title: '事件发生位置', field: 'evtParamPosition', align: 'center' },
{ title: '相别', field: 'evtParamPhase', align: 'center' },
{ title: '持续时间(s)', field: 'evtParamTm', align: 'center' },
{ title: '暂降(聚升)幅值(%)',minWidth: 100, field: 'evtParamVVaDepth', align: 'center' },
{ title: '发生时刻', field: 'startTime', align: 'center', width: '240' },
{ title: '持续时间(s)', field: 'evtParamTm', align: 'center',sortable: true },
{ title: '暂降(聚升)幅值(%)', minWidth: 100, field: 'evtParamVVaDepth', align: 'center',sortable: true },
{
title: '操作',
align: 'center',
@@ -145,11 +164,10 @@ const tableStore = new TableStore({
row.loading1 = false
if (res != undefined) {
boxoList.value = row
boxoList.value.featureAmplitude = row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
boxoList.value.featureAmplitude =
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
boxoList.value.systemType = 'WX'
wp.value = res.data
}
loading.value = false
})
@@ -159,7 +177,8 @@ const tableStore = new TableStore({
})
nextTick(() => {
waveFormAnalysisRef.value && waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
waveFormAnalysisRef.value &&
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
// waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(200, 190)
})
// row.loading1 = true
@@ -206,7 +225,6 @@ const tableStore = new TableStore({
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
})
}
},
@@ -342,6 +360,6 @@ setTimeout(() => {
tableStore.table.height = mainHeight(200).height as any
}, 0)
const addMenu = () => { }
const addMenu = () => {}
</script>
<style scoped lang="scss"></style>

View File

@@ -1,37 +1,66 @@
<template>
<div class="default-main analyze-apf" :style="{ height: pageHeight.height }" v-loading="loading">
<DeviceTree @node-click="nodeClick" @init="nodeClick"></DeviceTree>
<DeviceTree @node-click="nodeClick" @init="nodeClick" @deviceTypeChange="deviceTypeChange"></DeviceTree>
<div class="analyze-apf-right" v-if="formInline.devId">
<el-form :inline="true">
<el-form-item label="时间:">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="统计指标:">
<el-select v-model.trim="formInline.statisticalId" filterable placeholder="请选择">
<el-option v-for="item in zblist" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="值类型:">
<el-select v-model.trim="formInline.valueType" filterable placeholder="请选择">
<el-option v-for="item in typelist" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item>
<div ref="headerRef">
<TableHeader :showSearch="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select>
<el-form-item label="时间:">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="统计指标:">
<el-select
style="width: 200px"
v-model.trim="formInline.statisticalId"
filterable
@change="frequencyFlag"
placeholder="请选择"
>
<el-option
v-for="item in zblist"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="谐波次数:" v-show="frequencyShow">
<el-select
v-model.trim="formInline.frequency"
filterable
placeholder="请选择"
style="width: 100px"
>
<el-option
v-for="item in 49"
:key="item + 1"
:label="item + 1"
:value="item + 1"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="值类型:">
<el-select v-model.trim="formInline.valueType" filterable placeholder="请选择">
<el-option
v-for="item in typelist"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button>
</template>
</TableHeader>
</div>
<el-form-item>
<el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button>
</el-form-item>
<el-form-item>
<div style="display: flex; align-items: center">
<Icon name="el-icon-InfoFilled" style="color: #ff9912"></Icon>
总输出电流阈值和总输出电流比较
</div>
</el-form-item>
</el-form>
<el-empty description="暂无数据" v-if="!echartsData" style="flex: 1"></el-empty>
<template v-else>
<MyEchart :options="echartsData" style="flex: 1" />
<div :style="echartHeight">
<MyEchart :options="echartsData" />
</div>
</template>
</div>
<el-empty v-else description="请选择设备" class="analyze-apf-right" />
@@ -48,10 +77,16 @@ import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable'
import DatePicker from '@/components/form/datePicker/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { yMethod } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue'
defineOptions({
name: 'govern/analyze/APF'
})
const tableHeaderRef = ref()
const headerRef = ref()
const pageHeight = mainHeight(20)
const echartHeight = ref(mainHeight(80))
const loading = ref(false)
const echartsData = ref<any>(null)
const datePickerRef = ref()
@@ -60,9 +95,13 @@ const formInline = reactive({
valueType: '',
startTime: '',
endTime: '',
devId: ''
devId: '',
frequency: ''
})
const timeFlag = ref(true)
const frequencyShow = ref(false)
const devCapacity = ref(0)
const flag = ref(false)
const typelist = [
{
label: '平均值',
@@ -85,7 +124,7 @@ const zblist = ref<any[]>([])
const init = () => {
return new Promise((resolve, reject) => {
queryByCode('Harmonic_Type').then(res => {
queryByCode('Web_Apf').then(res => {
queryCsDictTree(res.data?.id).then(res => {
zblist.value = res.data.map((item: any) => {
return {
@@ -101,191 +140,78 @@ const init = () => {
})
})
}
const deviceTypeChange = (val: any, obj: any) => {
flag.value = true
nodeClick(obj)
}
const nodeClick = async (e: anyObj) => {
if (e.level == 2) {
if (e.level == 2 && flag.value) {
formInline.devId = e.id
loading.value = true
if (zblist.value.length === 0) {
await init()
}
getDevCapacity(formInline.devId).then(res => {
devCapacity.value = res.data
search()
}).catch(() => {
loading.value = false
})
getDevCapacity(formInline.devId)
.then(res => {
devCapacity.value = res.data
search()
})
.catch(() => {
loading.value = false
})
}
}
const lineStyle = [
{ type: 'solid', width: 3 },
{ type: 'dotted', width: 3 },
{ type: 'dashed', width: 3 }
]
const search = () => {
if (timeFlag.value) {
datePickerRef.value && datePickerRef.value.setInterval(5)
timeFlag.value = false
}
loading.value = true
formInline.startTime = datePickerRef.value.timeValue[0]
formInline.endTime = datePickerRef.value.timeValue[1]
queryCommonStatisticalByTime(formInline).then(({ data }: { data: any[] }) => {
if (data.length) {
echartsData.value = {}
let legend: any[] = []
let xAxis: any[] = []
data.forEach(item => {
if (!xAxis.includes(item.time)) {
xAxis.push(item.time)
}
if (!legend.includes(item.anotherName)) {
legend.push(item.anotherName)
}
})
let aar = data
.map(item => {
if (item.statisticalName === 'Apf_RmsI_TolOut') {
return [item.time, item.statisticalData.toFixed(2)]
} else {
return ''
}
})
.filter(item => item !== '')
let aar1 = data
.map(item => {
if (item.statisticalName === 'Apf_ThdA_Load') {
return [item.time, item.statisticalData.toFixed(2)]
} else {
return ''
}
})
.filter(item => item !== '')
let aar2 = data
.map(item => {
if (item.statisticalName === 'Apf_ThdA_Sys') {
return [item.time, item.statisticalData.toFixed(2)]
} else {
return ''
}
})
.filter(item => item !== '')
if (!frequencyShow.value) {
formInline.frequency = ''
}
queryCommonStatisticalByTime(formInline)
.then(({ data }: { data: any[] }) => {
if (data.length) {
let list = processingOfData(data, 'unit')
let series = [
// 总输出电流
{
name: data.find(item => item.statisticalName === 'Apf_RmsI_TolOut').anotherName,
symbol: 'none',
smooth: true,
type: 'line',
//stack: 'Total',
data: aar,
markLine: {
symbol: 'none',
data: [
{
yAxis: devCapacity.value,
label: {
position: 'middle', // 表现内容展示的位置
formatter: '总输出电流阈值', // 标线展示的内容
color: '#daa569' // 展示内容颜色
}
}
]
},
yAxisIndex: 1
},
//负载电流畸变率
{
name: data.find(item => item.statisticalName === 'Apf_ThdA_Load').anotherName,
symbol: 'none',
smooth: true,
type: 'line',
data: aar1
},
// 电网电流畸变率
{
name: data.find(item => item.statisticalName === 'Apf_ThdA_Sys').anotherName,
symbol: 'none',
smooth: true,
type: 'line',
data: aar2
}
]
let [min, max] = yMethod(aar.map((item: any) => item[1]))
let [min1, max1] = yMethod([...aar1, ...aar2].map((item: any) => item[1]))
echartsData.value = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999'
}
echartsData.value = {}
let legend: any[] = []
let xAxis: any[] = []
let yAxis: any[] = []
let series: any[] = []
let color: any[] = []
let title = ''
data.forEach(item => {
if (!xAxis.includes(item.time)) {
xAxis.push(item.time)
}
},
legend: {
data: legend
},
grid: {
left: '20px',
right: '40px',
bottom: '50px',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
name: '',
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}',
},
},
// boundaryGap: false,
// data: xAxis,
// axisLabel: {
// formatter: function (value: string) {
// return value.split(' ').join('\n')
// }
// },
// axisLine: {
// show: true,
// // symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// if (!legend.includes(item.anotherName)) {
// legend.push(item.anotherName)
// }
},
yAxis: [
{
name: '畸变率:(%)',
})
let units = Object.keys(list)
// console.log('🚀 ~ .then ~ units:', units)
for (let unit in list) {
console.log('🚀 ~ .then ~ unit:', unit)
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
yAxis.push({
name: unit == 'null' ? '' : unit,
type: 'value',
// max: 10,
min: min1,
max: max1,
splitNumber: 5,
minInterval: 1,
axisLine: {
show: true,
//symbol: ["none", "arrow"],
lineStyle: {
color: '#333'
}
}
},
{
name: '电流:(A)',
type: 'value',
min: min,
max: max,
splitNumber: 5,
minInterval: 1,
splitLine: {
show: false,
},
// splitNumber: 5,
// minInterval: 1,
axisLine: {
show: true,
//symbol: ["none", "arrow"],
@@ -293,20 +219,211 @@ const search = () => {
color: '#333'
}
}
}
],
options: {
series: series
}
}
} else {
echartsData.value = null
}
loading.value = false
}).catch(() => {
loading.value = false
})
})
// processingOfData(list[unit], 'anotherName')
let anotherList = processingOfData(list[unit], 'anotherName')
for (let k in anotherList) {
title = k
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
let phaseList = processingOfData(anotherList[k], 'phase')
for (let j in phaseList) {
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
legend.push(
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
)
series.push({
name:
j == 'M'
? k
: j == 'A'
? `A相_${k}`
: j == 'B'
? `B相_${k}`
: j == 'C'
? `C相_${k}`
: j,
symbol: 'none',
smooth: true,
type: 'line',
data: phaseList[j].map(item => [
item.time,
Math.floor(item.statisticalData * 100) / 100,
unit,
lineName.type
]),
lineStyle: lineName,
yAxisIndex: unit.indexOf(units)
})
}
}
}
echartsData.value = {
title: {
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] != null
? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2])
: '-'
}<br>`
})
return str
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
top: 25
// data: legend
},
grid: {
left: '20px',
right: '40px',
bottom: '50px',
top: '80px',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
color: color,
xAxis: {
name: '',
type: 'time',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
// boundaryGap: false,
// data: xAxis,
// axisLabel: {
// formatter: function (value: string) {
// return value.split(' ').join('\n')
// }
// },
// axisLine: {
// show: true,
// // symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
},
yAxis: yAxis,
// [
// {
// name: '畸变率:(%)',
// type: 'value',
// // max: 10,
// min: min1,
// max: max1,
// splitNumber: 5,
// minInterval: 1,
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// },
// {
// name: '电流:(A)',
// type: 'value',
// min: min,
// max: max,
// splitNumber: 5,
// minInterval: 1,
// splitLine: {
// show: false
// },
// axisLine: {
// show: true,
// //symbol: ["none", "arrow"],
// lineStyle: {
// color: '#333'
// }
// }
// }
// ],
options: {
series: series
}
}
} else {
echartsData.value = null
}
loading.value = false
})
.catch(() => {
loading.value = false
})
}
const processingOfData = (data: any, type: string) => {
let groupedData: any = {}
data.forEach(item => {
if (!groupedData[item[type]]) {
groupedData[item[type]] = []
}
groupedData[item[type]].push(item)
})
return groupedData
}
const frequencyFlag = () => {
let name = zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
if (name.includes('含有率') || name.includes('幅值')) {
frequencyShow.value = true
formInline.frequency = 2
} else {
frequencyShow.value = false
}
tableHeaderRef.value && tableHeaderRef.value?.computedSearchRow()
}
const selectChange = (flag: boolean) => {
setTimeout(() => {
echartHeight.value = mainHeight(23 + headerRef.value.offsetHeight)
}, 100)
}
</script>
@@ -324,3 +441,8 @@ const search = () => {
}
}
</style>
<style lang="scss" scoped>
.el-select {
min-width: 100px;
}
</style>

View File

@@ -1,21 +1,36 @@
<template>
<div class="default-main">
<div class="analyze-dvr" v-show="!isWaveCharts" :style="{ height: pageHeight.height }" v-loading="loading">
<DeviceTree @node-click="nodeClick" @init="nodeClick"></DeviceTree>
<DeviceTree @node-click="nodeClick" @init="nodeClick" @deviceTypeChange="deviceTypeChange"></DeviceTree>
<div class="analyze-dvr-right" v-if="tableStore.table.params.deviceId">
<TableHeader datePicker showExport>
<template v-slot:select>
<el-form-item label="事件类型">
<el-select v-model.trim="tableStore.table.params.eventType" clearable placeholder="请选择事件类型">
<el-option v-for="item in eventList" :key="item.value" :label="item.label"
:value="item.value" />
<el-select
v-model.trim="tableStore.table.params.eventType"
clearable
placeholder="请选择事件类型"
>
<el-option
v-for="item in eventList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="位置">
<el-select v-model.trim="tableStore.table.params.location" clearable placeholder="请选择位置">
<el-option v-for="item in locationList" :key="item.value" :label="item.label"
:value="item.value" />
<el-select
v-model.trim="tableStore.table.params.location"
clearable
placeholder="请选择位置"
>
<el-option
v-for="item in locationList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template>
@@ -24,8 +39,14 @@
</div>
<el-empty v-else description="请选择设备" class="analyze-dvr-right" />
</div>
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false" :wp="wp" style="padding: 10px;" />
<waveFormAnalysis
v-loading="loading"
v-if="isWaveCharts"
ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false"
:wp="wp"
style="padding: 10px"
/>
<!-- <div :style="{ height: pageHeight.height }" style="padding: 10px; overflow: hidden" v-if="!view">
<el-row>
<el-col :span="12">
@@ -67,14 +88,14 @@ import { mainHeight } from '@/utils/layout'
import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue';
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import { analyseWave } from '@/api/common'
import TableHeader from '@/components/table/header/index.vue'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { ElMessage } from 'element-plus'
defineOptions({
name: 'analyze/DVR/index'
name: 'govern/analyze/DVR/index'
})
const pageHeight = mainHeight(20)
const loading = ref(false)
@@ -85,43 +106,49 @@ const isWaveCharts = ref(false)
const bxactiveName = ref('ssbx')
const boxoList: any = ref({})
const wp = ref({})
const eventList = ref([{
value: 'Evt_Sys_DipStr',
label: '电压暂降'
},
{
value: 'Evt_Sys_SwlStr',
label: '电压暂升'
},
{
value: 'Evt_Sys_IntrStr',
label: '电压中断'
}])
const locationList = ref([{
value: 'grid',
label: '电网侧'
},
{
value: 'load',
label: '负载侧'
}])
const eventList = ref([
{
value: 'Evt_Sys_DipStr',
label: '电压暂降'
},
{
value: 'Evt_Sys_SwlStr',
label: '电压暂升'
},
{
value: 'Evt_Sys_IntrStr',
label: '电压中断'
}
])
const locationList = ref([
{
value: 'grid',
label: '电网侧'
},
{
value: 'load',
label: '负载侧'
}
])
const waveFormAnalysisRef = ref()
const tableStore = new TableStore({
url: '/cs-harmonic-boot/eventUser/queryEventpageWeb',
method: 'POST',
column: [
{ title: '事件描述', field: 'showName', },
{ title: '事件描述', field: 'showName' },
{ title: '发生位置', field: 'evtParamPosition' },
{ title: '持续时间(s)', field: 'evtParamTm' },
{ title: '持续时间(s)', field: 'evtParamTm', sortable: true },
{
title: '暂降(聚升)幅值(%)', field: 'evtParamVVaDepth', formatter: (row: any) => {
title: '暂降(聚升)幅值(%)',
field: 'evtParamVVaDepth',
formatter: (row: any) => {
let a = row.cellValue.split('%')[0] - 0
console.log("🚀 ~ a:", a)
console.log('🚀 ~ a:', a)
return a ? a.toFixed(2) : '/'
}
}, sortable: true
},
{ title: '发生时刻', field: 'startTime' },
{ title: '发生时刻', field: 'startTime', sortable: true },
{
title: '操作',
align: 'center',
@@ -147,11 +174,10 @@ const tableStore = new TableStore({
row.loading1 = false
if (res != undefined) {
boxoList.value = row
boxoList.value.featureAmplitude = row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
boxoList.value.featureAmplitude =
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
// boxoList.value.systemType = 'WX'
wp.value = res.data
}
loading.value = false
})
@@ -161,7 +187,8 @@ const tableStore = new TableStore({
})
nextTick(() => {
waveFormAnalysisRef.value && waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
waveFormAnalysisRef.value &&
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(false, 150)
})
}
@@ -174,9 +201,7 @@ const tableStore = new TableStore({
render: 'basicButton',
disabled: row => {
return !(!row.wavePath && row.evtParamTm < 20)
},
}
},
{
name: 'edit',
@@ -199,10 +224,9 @@ const tableStore = new TableStore({
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link) //释放标签
})
}
},
}
]
}
],
@@ -210,17 +234,21 @@ const tableStore = new TableStore({
tableStore.table.data.forEach((item: any) => {
item.loading = false
item.evtParamTm = item.evtParamTm.split('s')[0]
})
}
})
const flag = ref(false)
tableStore.table.params.type = 0
tableStore.table.params.eventType = ''
tableStore.table.params.location = ''
provide('tableStore', tableStore)
const deviceTypeChange = (val: any, obj: any) => {
flag.value = true
nodeClick(obj)
}
const nodeClick = async (e: anyObj) => {
// console.log("🚀 ~ nodeClick ~ e:", e)
if (e.level == 2) {
if (e.level == 2&& flag.value) {
loading.value = false
tableStore.table.params.deviceId = e.id
nextTick(() => {

View File

@@ -58,8 +58,8 @@ const tableStore: any = new TableStore({
}
},
{ field: 'successCount', title: '成功解析数', minWidth: 150 },
{ field: 'startTime', title: '导入开始时间', minWidth: 170 },
{ field: 'endTime', title: '导入结束时间', minWidth: 170 },
{ field: 'startTime', title: '导入开始时间', minWidth: 170, sortable: true },
{ field: 'endTime', title: '导入结束时间', minWidth: 170 , sortable: true},
{
title: '解析状态',
field: 'status',

View File

@@ -42,9 +42,9 @@ const tableStore: any = new TableStore({
}
},
{ field: 'name', title: '文件名称', minWidth: 170 },
{ field: 'createTime', title: '导入时间', minWidth: 170 },
{ field: 'allCount', title: '数据总数(条)', minWidth: 170 },
{ field: 'realCount', title: '已入库总数(条)', minWidth: 170 },
{ field: 'createTime', title: '导入时间', minWidth: 170 , sortable: true},
{ field: 'allCount', title: '数据总数(条)', minWidth: 170 , sortable: true},
{ field: 'realCount', title: '已入库总数(条)', minWidth: 170, sortable: true },
{
title: '解析状态',
field: 'state',

View File

@@ -270,7 +270,7 @@ const init = () => {
}
}
if ((echartsData.value.legend = ['A相', 'B相', 'C相'])) {
echartsData.value.color = ['#FFCC00', '#009900', '#CC0000']
echartsData.value.color = ['#DAA520', '#2E8B57', '#A52a2a']
}
} else {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,676 @@
<template>
<!-- 运行 运行(中断) 运行(故障) 离线 -->
<div :style="height" style="overflow-y: auto" v-loading="loading">
<div class="container">
<div class="tabs-container">
<!-- 左侧标签头 -->
<div class="tab-list" :style="titleHeight" style="overflow-y: auto" v-loading="loadingLeft">
<button
v-for="(item, index) in list"
:key="index"
:class="{ 'tab-button active': activeTab === index, 'tab-button': activeTab !== index }"
@click="changeTab(index)"
>
<span>{{ item.moduleName }}</span>
<el-tag class="ml10" :type="getType(item.moduleState)" size="small" effect="dark">
{{ item.moduleState }}
</el-tag>
</button>
</div>
<!-- 右侧内容区域 -->
<div class="tab-content-container flex-1" :key="activeTab">
<div v-if="echartList?.dataList != null" style="position: relative">
<el-tabs v-model="activeName" type="card" @tab-change="changeDataType">
<el-tab-pane label="状态" name="0">
<div :style="echartHeight" class="pt10">
<MyEchart :options="echartList.options" />
</div>
</el-tab-pane>
<el-tab-pane label="数据" name="1">
<div :style="echartHeight" class="pt10">
<MyEchart style="height: 100%" :options="echartsData" :key="key" />
<!-- <MyEchart style="height: 50%" :options="echartList.loadList" />
<MyEchart style="height: 50%" :options="echartList.modOutList" /> -->
</div>
</el-tab-pane>
</el-tabs>
<el-select
v-if="activeName == '1'"
v-model="dataType"
class="select"
placeholder="请选择"
multiple
collapse-tags
style="width: 150px"
@change="changeDataType"
>
<el-option label="负载电流" :value="0" />
<el-option label="输入电流" :value="1" />
<el-option label="温度" :value="2" />
</el-select>
</div>
<el-empty description="暂无数据" style="width: 100%; height: 100%" v-else></el-empty>
</div>
</div>
</div>
<!-- <el-collapse v-model="activeNames" v-loading="loading">
<el-collapse-item v-for="(item, index) in list" :key="index" :name="index">
<template #title>
<div class="header">
{{ item.moduleName }}
<el-tag
class="ml10"
:type="item.moduleState == '离线' ? 'danger' : 'success'"
size="small"
effect="dark"
>
{{ item.moduleState }}
</el-tag>
</div>
</template>
<div :style="echartHeight" style="min-height: 150px">
<MyEchart :options="item.options" v-if="item.dataList != null" />
<el-empty description="暂无数据" style="height: 130px" v-else></el-empty>
</div>
</el-collapse-item>
</el-collapse> -->
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onBeforeUnmount } from 'vue'
import { mainHeight } from '@/utils/layout'
import { WarnTriangleFilled } from '@element-plus/icons-vue'
import { getModuleState } from '@/api/cs-device-boot/EquipmentDelivery'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { ElMessage } from 'element-plus'
import { yMethod } from '@/utils/echartMethod'
const list: any = ref([])
const loading = ref(false)
const loadingLeft = ref(false)
const height = ref(mainHeight(290))
const titleHeight = ref(mainHeight(302))
const echartHeight = ref(mainHeight(342))
const activeTab = ref(0)
const activeName = ref('0')
const echartList: any = ref({})
const dataType = ref([0])
const key = ref(0)
import * as echarts from 'echarts' // 全引入
import { max } from 'lodash'
const echartsData: any = ref({
title: {
show: false
},
xAxis: {
type: 'time',
name: '',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter(params: any) {
const xname = params[0].value[0]
let str = `${xname}<br>`
params.forEach((el: any, index: any) => {
let marker = ''
if (el.value[3] == 'dashed') {
for (let i = 0; i < 3; i++) {
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
}
} else {
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
}
str += `${marker}${el.seriesName.split('(')[0]}${
el.value[1] != null ? el.value[1] + ' ' + (el.value[2] || '') : '-'
}<br>`
})
return str
}
},
legend: {
itemWidth: 20,
itemHeight: 20,
itemStyle: { opacity: 0 }, //去圆点
type: 'scroll', // 开启滚动分页
right: 70
},
grid: {
top: '80px',
right: '50px',
},
yAxis: [{}],
options: {
// yAxis: [{}],
series: []
}
})
const setData = (data: any) => {
// activeTab.value = 0
// echartHeight.value = mainHeight(292 + data.length * 49, data.length)
data.forEach((item: any) => {
// console.log('🚀 ~ setData ~ data:', data)
if (item.dataList == null) return
item.dataList.map((k: any, i: any) => {
k.endtime = item.dataList[i + 1]?.time
})
item.options = {
// 鼠标提示
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
formatter: function (params) {
// console.log("🚀 ~ data.forEach ~ params:", params)
let tip = ''
for (let i = 0; i < params.length; i++) {
if (params[i].seriesName != '事件标记') {
tip +=
params[i].marker +
params[i].name +
'<br/>' +
'开始时间:' +
params[i].value[1] +
'<br/>' +
'结束时间:' +
(params[i].value[2] || '-') +
'<br/>'
if (params[i].value[3] == 1) {
tip += '事件:' + params[i].value[4] + '<br/>'
}
} else {
// if (params[i].value[3] == 1) {
// tip += '事件:' + params[i].value[1] + '<br/>'
// }
}
}
return tip
}
},
legend: {
// data: ['运行', '停止', '离线','事件标记']
data: [
{ name: '运行' },
{ name: '停止' },
{ name: '离线' },
{
name: '事件标记',
icon: 'path://M0,10 L10,10 L5,0 Z', // 自定义三角形路径
textStyle: {
color: '#333',
fontSize: 14
}
}
]
},
xAxis: {
type: 'time',
name: '时间',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: {
show: false,
axisPointer: {
show: false // 隐藏Y轴上的指示器
}
},
color: ['#67c23a', '#e6a23c', '#f56c6c', '#ccc'],
series: [
{
name: '运行',
type: 'custom',
renderItem: renderItem,
encode: {
x: [1, 2],
y: 0
},
data: item.dataList
.filter((k: any, i: number) => k.stateDesc == '运行')
.map((p: any) => {
return {
name: '运行',
value: [0, p.time, p.endtime, p.dataType, p.eventName],
itemStyle: {
normal: {
color: '#67c23a'
}
}
}
})
},
{
name: '停止',
type: 'custom',
renderItem: renderItem,
encode: {
x: [1, 2],
y: 0
},
data: item.dataList
.filter((k: any, i: number) => k.stateDesc != '离线' && k.stateDesc != '运行')
.map((p: any) => {
return {
name: '停止',
value: [0, p.time, p.endtime, p.dataType, p.eventName],
itemStyle: {
normal: {
color: '#e6a23c'
}
}
}
})
},
{
name: '离线',
type: 'custom',
renderItem: renderItem,
encode: {
x: [1, 2],
y: 0
},
data: item.dataList
.filter((k: any, i: number) => k.stateDesc == '离线')
.map((p: any) => {
return {
name: '离线',
value: [0, p.time, p.endtime, p.dataType, p.eventName],
itemStyle: {
normal: {
color: '#f56c6c'
}
}
}
})
// [
// {
// name: '离线',
// value: [0, '2025-07-16 01:03:00', '2025-07-16 01:06:00', 353249],
// itemStyle: {
// normal: {
// color: '#f56c6c'
// }
// }
// }
// ]
},
{
name: '事件标记',
type: 'custom',
renderItem: renderMarker,
encode: {
x: 0,
y: 1
},
data: item.dataList
.filter((k: any) => k.dataType === 1)
.map((k: any) => [
k.time,
k.eventName,
k.stateDesc == '离线' ? '#f56c6c' : k.stateDesc == '运行' ? '#67c23a' : '#e6a23c',
k.dataType
]),
// data: [['2025-07-16 01:00:00','故障发生','#bd6d6c']],
z: 10 // 确保标记显示在甘特图上方
}
]
}
})
list.value = data
echartList.value = list.value[activeTab.value]
changeDataType()
// echarts.connect('group')
}
const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
const changeDataType = () => {
// loadList 负载电流
// modOutList 输入电流
// console.log('🚀 ~ changeDataType ~ val:', list.value[activeTab.value])
echartsData.value.yAxis = [{}]
echartsData.value.options.series = []
let flag = dataType.value.includes(0) || dataType.value.includes(1)
if (flag) {
let data1 = dataType.value.includes(0)
? list.value[activeTab.value].loadList.map(k => (k.data == 3.14159 ? 0 : k.data))
: [0]
let data2 = dataType.value.includes(1)
? list.value[activeTab.value].modOutList.map(k => (k.data == 3.14159 ? 0 : k.data))
: [0]
let [modOuMin, modOuMax] = yMethod([...data1, ...data2])
console.log("🚀 ~ changeDataType ~ modOuMin:", modOuMin,modOuMax)
echartsData.value.yAxis[0] = {
name: 'A',
yAxisIndex: 0,
max: modOuMax,
min: modOuMin,
splitNumber: 5,
minInterval: 1
}
if (dataType.value.includes(0)) {
echartsData.value.options.series.push(
{
name: 'A相负载电流',
type: 'line',
data: list.value[activeTab.value].loadList
.filter((k: any) => k.phasicType == 'A')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[0].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#DAA520',
lineStyle: lineStyle[0],
yAxisIndex: 0
},
{
name: 'B相负载电流',
type: 'line',
data: list.value[activeTab.value].loadList
.filter((k: any) => k.phasicType == 'B')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[0].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#2E8B57',
lineStyle: lineStyle[0],
yAxisIndex: 0
},
{
name: 'C相负载电流',
type: 'line',
data: list.value[activeTab.value].loadList
.filter((k: any) => k.phasicType == 'C')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[0].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#A52a2a',
lineStyle: lineStyle[0],
yAxisIndex: 0
}
)
}
if (dataType.value.includes(1)) {
echartsData.value.options.series.push(
{
name: 'A相输入电流',
type: 'line',
data: list.value[activeTab.value].modOutList
.filter((k: any) => k.phasicType == 'A')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[1].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#DAA520',
lineStyle: lineStyle[1],
yAxisIndex: 0
},
{
name: 'B相输入电流',
type: 'line',
data: list.value[activeTab.value].modOutList
.filter((k: any) => k.phasicType == 'B')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[1].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#2E8B57',
lineStyle: lineStyle[1],
yAxisIndex: 0
},
{
name: 'C相输入电流',
type: 'line',
data: list.value[activeTab.value].modOutList
.filter((k: any) => k.phasicType == 'C')
.map((k: any) => [k.time, k.data == 3.14159 ? null : k.data, 'A', lineStyle[1].type]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#A52a2a',
lineStyle: lineStyle[1],
yAxisIndex: 0
}
)
}
}
if (dataType.value.includes(2)) {
let [temperatureMin, temperatureMax] = yMethod(
list.value[activeTab.value].temperatureList.map(k => (k.data == 3.14159 ? 0 : k.data))
)
echartsData.value.yAxis[flag ? 1 : 0] = {
name: '℃',
yAxisIndex: flag ? 1 : 0,
splitNumber: 5,
max: temperatureMax,
min: temperatureMin,
minInterval: 1
}
echartsData.value.options.series.push({
name: '温度',
type: 'line',
data: list.value[activeTab.value].temperatureList.map((k: any) => [
k.time,
k.data == 3.14159 ? null : k.data,
'℃',
lineStyle[2].type
]),
smooth: true, //让线变得平滑
symbol: 'none',
color: '#DAA520',
lineStyle: lineStyle[2],
yAxisIndex: flag ? 1 : 0
})
}
key.value += 1
}
function renderItem(params, api) {
var categoryIndex = api.value(0)
var start = api.coord([api.value(1), categoryIndex])
var end = api.coord([api.value(2), categoryIndex])
var height = api.size([0, 1])[1] * 0.9
var rectShape = echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height - 50
}
)
return (
rectShape && {
type: 'rect',
shape: rectShape,
style: api.style()
}
)
}
// 三角形标记渲染函数
function renderMarker(params, api) {
var point = api.coord([api.value(0), 0])
var symbolSize = 8
var offsetY = 40
// 计算三角形的三个点坐标
var points = [
[point[0], point[1] - symbolSize - offsetY], // 上顶点
[point[0] - symbolSize, point[1] + symbolSize - offsetY], // 左下顶点
[point[0] + symbolSize, point[1] + symbolSize - offsetY] // 右下顶点
]
return {
type: 'polygon',
shape: {
points: points
},
style: {
fill: api.value(2),
stroke: '#fff',
lineWidth: 1
},
label: {
position: [point[0] + symbolSize + 5, point[1]],
formatter: api.value(1),
fontSize: 12
}
}
}
const getModule = async (id: string) => {
loadingLeft.value = true
await getModuleState({ id: id }).then(res => {
res.data.forEach((item: any) => {
list.value.forEach((k: any) => {
if (k.moduleName === item.moduleName) {
k.moduleState = item.moduleState
}
})
})
ElMessage.success('刷新成功')
})
loadingLeft.value = false
}
const changeTab = (e: any) => {
echartList.value = list.value[e]
activeTab.value = e
changeDataType()
}
const getType = (type: string) => {
switch (type) {
case '运行':
return 'success'
case '离线':
return 'danger'
default:
return 'warning'
}
}
defineExpose({ setData, getModule })
onBeforeUnmount(() => {
echarts.disconnect('group')
})
</script>
<style lang="scss" scoped>
.container {
margin: 10px 10px 0 10px;
background-color: white;
border-radius: 0.5rem;
// box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
overflow: hidden;
}
.tabs-container {
display: flex;
flex-direction: column;
height: 100%;
}
@media (min-width: 768px) {
.tabs-container {
flex-direction: row;
}
}
.tab-list {
width: 100%;
border-bottom: 1px solid #e2e8f0;
background-color: #f8fafc;
}
@media (min-width: 768px) {
.tab-list {
width: 140px;
border-right: 1px solid #e2e8f0;
border-bottom: none;
}
}
.tab-button {
display: flex;
align-items: center;
width: 100%;
padding: 15px 20px;
text-align: left;
border: none;
background: none;
cursor: pointer;
font-size: 14px;
color: #64748b;
border-right: 4px solid transparent;
transition: all 0.2s ease;
}
.tab-button:hover {
background-color: #f1f5f9;
color: #475569;
}
.tab-button.active {
background-color: #e2e8f0;
color: #000;
border-right-color: var(--el-color-primary);
font-weight: 700;
}
.tab-button i {
width: 1.25rem;
margin-right: 0.75rem;
}
.tab-content-container {
flex: 1;
padding: 0 10px;
}
.select {
position: absolute;
top: 7px;
left: 150px;
}
</style>

View File

@@ -1,273 +1,281 @@
<template>
<TableHeader ref="refheader" :showSearch="false">
<template #select>
<el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item>
<el-checkbox-group style="width: 150px" v-model.trim="checkList">
<el-checkbox label="稳态" :value="0" />
<el-checkbox label="暂态" :value="1" />
</el-checkbox-group>
</el-form-item>
</template>
<template #operation>
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
<el-button type="primary" :icon="Setting" @click="handleUpDevice">补召</el-button>
<el-button :icon="Back" @click="go(-1)">返回</el-button>
</template>
</TableHeader>
<!-- 设备补召 -->
<div class=" current_device" v-loading="loading">
<div class="current_body" ref="tbodyRef">
<vxe-table border ref="tableRef" :data="dirList" align="center" height="auto"
:style="{ height: tableHeight }" @radio-change="radioChangeEvent">
<vxe-column type="radio" width="60">
<template #header>
<vxe-button mode="text" @click="clearRadioRowEvent" :disabled="!selectRow">取消</vxe-button>
</template>
</vxe-column>
<!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
<vxe-column field="name" title="名称"></vxe-column>
<vxe-column field="status" title="补召进度">
<template #default="{ row }">
<div class="finish" v-if="row.status == 100">
<SuccessFilled style="width: 16px;" /><span class="ml5">补召完成</span>
</div>
<el-progress v-model.trim="row.status" v-else :class="row.status == 100 ? 'progress' : ''"
:format="format" :stroke-width="10" striped :percentage="row.status" :duration="30"
striped-flow />
</template>
</vxe-column>
<vxe-column field="startTime" title="起始时间"></vxe-column>
<vxe-column field="endTime" title="结束时间"></vxe-column>
</vxe-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineExpose, onBeforeUnmount, inject } from 'vue'
import { getMakeUpData, getAskDirOrFile, offlineDataUploadMakeUp } from '@/api/cs-harmonic-boot/recruitment.ts'
import DatePicker from '@/components/form/datePicker/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useRouter, useRoute } from 'vue-router'
import { mainHeight } from '@/utils/layout'
import { VxeUI, VxeTableInstance, VxeTableEvents } from 'vxe-table'
import { SuccessFilled } from '@element-plus/icons-vue'
import {
Back,
Setting, Search
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import mqtt from 'mqtt'
defineOptions({
name: 'supplementaryRecruitment'
})
const checkList: any = ref([])
// const props = defineProps(['lineId'])
const { go } = useRouter() // 路由
const selectRow: any = ref(null)
const loading = ref(false)
const dirList = ref([])
const route: any = ref({})
const datePickerRef = ref()
const format = (percentage) => (percentage === 100 ? '完成' : `${percentage}%`)
const getMakeUpDataList = (row: any) => {
route.value = row
loading.value = true
getMakeUpData(row.id).then(res => {
res.data.map((item: any) => {
item.name = item.prjName
? item.prjDataPath.replace('/bd0/cmn/', item.prjName + '-')
: item.prjDataPath.replace('/bd0/cmn/', '')
item.startTime = item.startTime ? item.startTime : '/'
item.endTime = item.endTime ? item.endTime : '/'
item.status = 0
})
dirList.value = res.data
loading.value = false
})
}
// 进入文件夹
const dirCheckedList: any = ref([])
const tbodyRef = ref()
const tableHeight = mainHeight(85).height
const routes = useRoute()
const tableRef = ref()
const selectRowCopy: any = ref(null)
const handleUpDevice = () => {
let proList = tableRef.value.getCheckboxRecords().map((item: any) => {
return item.prjDataPath
})
if (checkList.value.length == 0) {
return ElMessage.warning('请选择暂态稳态')
}
if (selectRow.value == null) {
return ElMessage.warning('请选择工程')
}
selectRowCopy.value = JSON.parse(JSON.stringify(selectRow.value))
let form = {
dataTypeList: checkList.value,
startTime: datePickerRef.value && datePickerRef.value.timeValue[0],
endTime: datePickerRef.value && datePickerRef.value.timeValue[1],
lineId: routes.query.id,
ndid: routes.query.ndid,
proList: [selectRow.value?.prjDataPath]
}
ElMessage.warning('补召中, 请稍等...')
offlineDataUploadMakeUp(form)
.then((res: any) => {
if (res.code == 'A0000') {
// ElMessage.success(res.data)
dirList.value.map((item: any) => {
// checkedList.map((vv: any) => {
if (item.name == selectRowCopy.value?.name) {
item.status = 5
}
// })
})
// loading.value = false
}
})
.catch(() => {
// loading.value = false
})
}
const radioChangeEvent: VxeTableEvents.RadioChange = ({ row }) => {
selectRow.value = row
// console.log('单选事件')
}
const clearRadioRowEvent = () => {
const $table = tableRef.value
if ($table) {
selectRow.value = null
$table.clearRadioRow()
}
}
const mqttRef = ref()
const url: any = window.localStorage.getItem('MQTTURL')
const connectMqtt = () => {
if (mqttRef.value) {
if (mqttRef.value.connected) {
return
}
}
const options = {
protocolId: 'MQTT',
qos: 2,
clean: true,
connectTimeout: 30 * 1000,
clientId: 'mqttjs' + Math.random(),
username: 't_user',
password: 'njcnpqs'
}
mqttRef.value = mqtt.connect(url, options)
}
const handleSearch = () => {
getMakeUpDataList(route.value)
}
connectMqtt()
mqttRef.value.on('connect', () => {
// ElMessage.success('连接mqtt服务器成功!')
console.log('mqtt客户端已连接....')
// mqttRef.value.subscribe('/Web/Progress')
// mqttRef.value.subscribe('/Web/Progress/+')
mqttRef.value.subscribe('/dataOnlineRecruitment/Progress/' + route.value.id)
})
const mqttMessage = ref<any>({})
mqttRef.value.on('message', (topic: any, message: any) => {
// console.log('mqtt接收到消息', JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message)))))
loading.value = false
let str = JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message))))
let regex1 = /allStep:(.*?),nowStep/
let regex2 = /nowStep:(.*?)}/
mqttMessage.value = {
allStep: str.match(regex1)[1],
nowStep: str.match(regex2)[1]
}
// console.log(mqttMessage.value)
let checkedList = tableRef.value.getCheckboxRecords().map((item: any) => {
return item.name
})
dirList.value.map((item: any) => {
// checkedList.map((vv: any) => {
if (item.name == selectRowCopy.value?.name) {
let percentage = parseInt(Number((mqttMessage.value.nowStep / mqttMessage.value.allStep) * 100)) || 0
if (percentage > 5) {
item.status = percentage
}
}
// })
})
})
mqttRef.value.on('error', (error: any) => {
console.log('mqtt连接失败...', error)
mqttRef.value.end()
})
mqttRef.value.on('close', function () {
console.log('mqtt客户端已断开连接.....')
})
onMounted(() => {
})
onBeforeUnmount(() => {
if (mqttRef.value) {
mqttRef.value.end()
}
})
defineExpose({ getMakeUpDataList })
</script>
<style lang="scss" scoped>
// .current_device {
// width: 100%;
// display: flex;
// flex-direction: column;
// .current_header {
// width: 100%;
// height: 60px;
// padding: 15px;
// display: flex;
// align-items: center;
// box-sizing: border-box;
// .el-form-item {
// display: flex;
// align-items: center;
// margin-bottom: 0;
// }
// }
// .current_body {
// flex: 1;
// }
// }
:deep(.el-progress-bar__inner--striped) {
background-image: linear-gradient(45deg, rgba(255, 255, 255, .3) 25%, transparent 0, transparent 50%, rgba(255, 255, 255, .3) 0, rgba(255, 255, 255, .3) 75%, transparent 0, transparent);
}
:deep(.progress) {
.el-progress__text {
color: green;
}
}
.finish {
display: flex;
justify-content: center;
font-weight: 550;
color: #009688
}
</style>
<template>
<TableHeader ref="refheader" :showSearch="false">
<template #select>
<el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item>
<el-checkbox-group style="width: 150px" v-model.trim="checkList">
<el-checkbox label="稳态" :value="0" />
<el-checkbox label="暂态" :value="1" />
</el-checkbox-group>
</el-form-item>
</template>
<template #operation>
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
<el-button type="primary" :icon="Setting" @click="handleUpDevice">补召</el-button>
<el-button :icon="Back" @click="go(-1)">返回</el-button>
</template>
</TableHeader>
<!-- 设备补召 -->
<div class=" current_device" v-loading="loading">
<div class="current_body" ref="tbodyRef">
<vxe-table border ref="tableRef" :data="dirList" align="center" height="auto"
:style="{ height: tableHeight }" @radio-change="radioChangeEvent">
<vxe-column type="radio" width="60">
<template #header>
<vxe-button mode="text" @click="clearRadioRowEvent" :disabled="!selectRow">取消</vxe-button>
</template>
</vxe-column>
<!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
<vxe-column field="name" title="名称"></vxe-column>
<vxe-column field="status" title="补召进度">
<template #default="{ row }">
<div class="finish" v-if="row.status == 100">
<SuccessFilled style="width: 16px;" /><span class="ml5">补召完成</span>
</div>
<el-progress v-model.trim="row.status" v-else :class="row.status == 100 ? 'progress' : ''"
:format="format" :stroke-width="10" striped :percentage="row.status" :duration="30"
striped-flow />
</template>
</vxe-column>
<vxe-column field="startTime" title="起始时间"></vxe-column>
<vxe-column field="endTime" title="结束时间"></vxe-column>
</vxe-table>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, defineExpose, onBeforeUnmount, inject } from 'vue'
import { getMakeUpData, getAskDirOrFile, offlineDataUploadMakeUp } from '@/api/cs-harmonic-boot/recruitment.ts'
import DatePicker from '@/components/form/datePicker/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { useRouter, useRoute } from 'vue-router'
import { mainHeight } from '@/utils/layout'
import { VxeUI, VxeTableInstance, VxeTableEvents } from 'vxe-table'
import { SuccessFilled } from '@element-plus/icons-vue'
import {
Back,
Setting, Search
} from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import mqtt from 'mqtt'
defineOptions({
name: 'supplementaryRecruitment'
})
const checkList: any = ref([])
// const props = defineProps(['lineId'])
const { go } = useRouter() // 路由
const selectRow: any = ref(null)
const loading = ref(false)
const dirList = ref([])
const route: any = ref({})
const datePickerRef = ref()
const format = (percentage) => (percentage === 100 ? '完成' : `${percentage}%`)
const getMakeUpDataList = (row: any) => {
route.value = row
loading.value = true
getMakeUpData(row.id).then(res => {
res.data.map((item: any) => {
item.name = item.prjName
? item.prjDataPath.replace('/bd0/cmn/', item.prjName + '-')
: item.prjDataPath.replace('/bd0/cmn/', '')
item.startTime = item.startTime ? item.startTime : '/'
item.endTime = item.endTime ? item.endTime : '/'
item.status = 0
})
dirList.value = res.data
loading.value = false
})
}
// 进入文件夹
const dirCheckedList: any = ref([])
const tbodyRef = ref()
const tableHeight = mainHeight(85).height
const routes = useRoute()
const tableRef = ref()
const selectRowCopy: any = ref(null)
const handleUpDevice = () => {
let proList = tableRef.value.getCheckboxRecords().map((item: any) => {
return item.prjDataPath
})
if (checkList.value.length == 0) {
return ElMessage.warning('请选择暂态稳态')
}
if (selectRow.value == null) {
return ElMessage.warning('请选择工程')
}
selectRowCopy.value = JSON.parse(JSON.stringify(selectRow.value))
let form = {
dataTypeList: checkList.value,
startTime: datePickerRef.value && datePickerRef.value.timeValue[0],
endTime: datePickerRef.value && datePickerRef.value.timeValue[1],
lineId: routes.query.id,
ndid: routes.query.ndid,
proList: [selectRow.value?.prjDataPath]
}
ElMessage.warning('补召中, 请稍等...')
offlineDataUploadMakeUp(form)
.then((res: any) => {
if (res.code == 'A0000') {
// ElMessage.success(res.data)
dirList.value.map((item: any) => {
// checkedList.map((vv: any) => {
if (item.name == selectRowCopy.value?.name) {
item.status = 5
}
// })
})
// loading.value = false
}
})
.catch(() => {
// loading.value = false
})
}
const radioChangeEvent: VxeTableEvents.RadioChange = ({ row }) => {
selectRow.value = row
// console.log('单选事件')
}
const clearRadioRowEvent = () => {
const $table = tableRef.value
if ($table) {
selectRow.value = null
$table.clearRadioRow()
}
}
const mqttRef = ref()
const url: any = window.localStorage.getItem('MQTTURL')
const connectMqtt = () => {
if (mqttRef.value) {
if (mqttRef.value.connected) {
return
}
}
const options = {
protocolId: 'MQTT',
qos: 2,
clean: true,
connectTimeout: 30 * 1000,
clientId: 'mqttjs' + Math.random(),
username: 't_user',
password: 'njcnpqs'
}
mqttRef.value = mqtt.connect(url, options)
}
const handleSearch = () => {
getMakeUpDataList(route.value)
}
function parseStringToObject(str:string) {
const content = str.replace(/^{|}$/g, '')
const pairs = content.split(',')
const result:any = {}
pairs.forEach(pair => {
const [key, value] = pair.split(':')
// 尝试将数字转换为Number类型
result[key.trim()] = isNaN(Number(value)) ? value.trim() : Number(value)
})
return result
}
connectMqtt()
mqttRef.value.on('connect', () => {
// ElMessage.success('连接mqtt服务器成功!')
console.log('mqtt客户端已连接....')
// mqttRef.value.subscribe('/Web/Progress')
// mqttRef.value.subscribe('/Web/Progress/+')
mqttRef.value.subscribe('/dataOnlineRecruitment/Progress/' + route.value.id)
})
const mqttMessage = ref<any>({})
mqttRef.value.on('message', (topic: any, message: any) => {
// console.log('mqtt接收到消息', JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message)))))
loading.value = false
let str = JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message))))
let regex1 = /allStep:(.*?),nowStep/
let regex2 = /nowStep:(.*?)}/
mqttMessage.value = parseStringToObject(str)
// console.log(mqttMessage.value)
let checkedList = tableRef.value.getCheckboxRecords().map((item: any) => {
return item.name
})
dirList.value.map((item: any) => {
// checkedList.map((vv: any) => {
if (item.name == selectRowCopy.value?.name) {
let percentage = parseInt(Number((mqttMessage.value.nowStep / mqttMessage.value.allStep) * 100)) || 0
if (percentage > 5) {
item.status = percentage
}
}
// })
})
})
mqttRef.value.on('error', (error: any) => {
console.log('mqtt连接失败...', error)
mqttRef.value.end()
})
mqttRef.value.on('close', function () {
console.log('mqtt客户端已断开连接.....')
})
onMounted(() => {
})
onBeforeUnmount(() => {
if (mqttRef.value) {
mqttRef.value.end()
}
})
defineExpose({ getMakeUpDataList })
</script>
<style lang="scss" scoped>
// .current_device {
// width: 100%;
// display: flex;
// flex-direction: column;
// .current_header {
// width: 100%;
// height: 60px;
// padding: 15px;
// display: flex;
// align-items: center;
// box-sizing: border-box;
// .el-form-item {
// display: flex;
// align-items: center;
// margin-bottom: 0;
// }
// }
// .current_body {
// flex: 1;
// }
// }
:deep(.el-progress-bar__inner--striped) {
background-image: linear-gradient(45deg, rgba(255, 255, 255, .3) 25%, transparent 0, transparent 50%, rgba(255, 255, 255, .3) 0, rgba(255, 255, 255, .3) 75%, transparent 0, transparent);
}
:deep(.progress) {
.el-progress__text {
color: green;
}
}
.finish {
display: flex;
justify-content: center;
font-weight: 550;
color: #009688
}
</style>

View File

@@ -210,7 +210,7 @@ const tableStore = new TableStore({
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'cloud' ? 'CLD' : row.cellValue
}
},
{ title: '录入时间', field: 'createTime' },
{ title: '录入时间', field: 'createTime', sortable: true },
{ title: '网络设备ID', field: 'ndid' },
{
title: '状态',

View File

@@ -40,7 +40,7 @@ const tableStore: any = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '发生时刻', minWidth: 170 },
{ field: 'startTime', title: '发生时刻', minWidth: 170, sortable: true },
{ field: 'showName', title: '事件描述', minWidth: 170 },
{
field: 'phaseType',
@@ -58,7 +58,7 @@ const tableStore: any = new TableStore({
formatter: (row: any) => {
row.cellValue = row.cellValue ? row.cellValue.toFixed(2) : '/'
return row.cellValue
}
}, sortable: true
},
{
field: 'featureAmplitude',

View File

@@ -273,21 +273,21 @@ const initRadioCharts = () => {
value: 0,
name: 'A相',
itemStyle: {
color: '#FFCC00'
color: '#DAA520'
}
},
{
value: 0,
name: 'B相',
itemStyle: {
color: '#009900'
color: '#2E8B57'
}
},
{
value: 0,
name: 'C相',
itemStyle: {
color: '#CC0000'
color: '#A52a2a'
}
}
]
@@ -373,21 +373,21 @@ const initRadioCharts = () => {
value: 0,
name: 'A相',
itemStyle: {
color: '#FFCC00'
color: '#DAA520'
}
},
{
value: 0,
name: 'B相',
itemStyle: {
color: '#009900'
color: '#2E8B57'
}
},
{
value: 0,
name: 'C相',
itemStyle: {
color: '#CC0000'
color: '#A52a2a'
}
}
]

View File

@@ -341,7 +341,7 @@ const init = async () => {
return str
}
},
color: ['#FFCC00', '#009900', '#CC0000', ...color],
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
@@ -461,7 +461,7 @@ const init = async () => {
: kk[0].anotherName,
type: 'line',
smooth: true,
color: colorName == 'A' ? '#FFCC00' : colorName == 'B' ? '#009900' : colorName == 'C' ? '#CC0000' : '',
color: colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
symbol: 'none',
data: seriesList,
lineStyle: lineStyle[lineS],

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,7 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ field: 'startTime', title: '发生时刻', minWidth: 170 },
{ field: 'startTime', title: '发生时刻', minWidth: 170, sortable: true },
{ field: 'showName', title: '事件描述', minWidth: 170 },
{
field: 'phaseType',
@@ -62,7 +62,7 @@ const tableStore = new TableStore({
formatter: (row: any) => {
row.cellValue = row.cellValue ? row.cellValue.toFixed(2) : '/'
return row.cellValue
}
}, sortable: true
},
{
field: 'featureAmplitude',
@@ -74,7 +74,7 @@ const tableStore = new TableStore({
row.cellValue = String(row.cellValue).split('.')[0]
}
return row.cellValue
}
}, sortable: true
},
{
title: '操作',

View File

@@ -431,7 +431,7 @@ const refreshTree = () => {
const range = (start: any, end: any, step: any) => {
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
}
const colors = ['#FFCC00', '#009900', '#CC0000']
const colors = ['#DAA520', '#2E8B57', '#A52a2a']
const lineStyle = [{ type: 'solid', }, { type: 'dashed', }, { type: 'dotted', }]
const titleList: any = ref('')
@@ -627,7 +627,7 @@ const init = (flag: boolean) => {
return str
}
},
// color: ['#FFCC00', '#009900', '#CC0000', ...color],
// color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
xAxis: {
type: 'time',
axisLabel: {
@@ -714,7 +714,7 @@ const init = (flag: boolean) => {
? kk[0].phase + '相' + kk[0].anotherName
: kk[0].anotherName,
type: 'line',
color: colorName == 'A' ? '#FFCC00' : colorName == 'B' ? '#009900' : colorName == 'C' ? '#CC0000' : '',
color: colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
smooth: true,
symbol: 'none',
lineStyle: lineStyle[lineS],

View File

@@ -32,8 +32,8 @@ const tableStore = new TableStore({
return row.cellValue == 1 ? '设备登记' : row.cellValue == 2 ? '功能调试' : row.cellValue == 3 ? '出厂调试' : row.cellValue == 4 ? '设备投运' : ''
}
},
{ title: '开始时间', field: 'startTime', align: 'center' },
{ title: '结束时间', field: 'endTime', align: 'center' }
{ title: '开始时间', field: 'startTime', align: 'center', sortable: true },
{ title: '结束时间', field: 'endTime', align: 'center', sortable: true }
],
loadCallback: () => {

View File

@@ -18,10 +18,10 @@ const tableStore = new TableStore({
url: '/cs-device-boot/cslog/queryLog',
method: 'POST',
column: [
{ title: '操作日期', field: 'createTime', align: 'center' },
{ title: '操作日期', field: 'createTime', align: 'center', sortable: true },
{ title: '操作描述', field: 'operate', align: 'center', width: '300' },
{ title: '用户名称', field: 'userName', align: 'center' },
{ title: '更新时间', field: 'updateTime', align: 'center' },
{ title: '更新时间', field: 'updateTime', align: 'center', sortable: true },
{ title: '失败原因', field: 'failReason', align: 'center' },
{ title: '状态', field: 'result', align: 'center' },
{ title: '登录名', field: 'loginName', align: 'center' }

View File

@@ -20,7 +20,7 @@ const tableStore = new TableStore({
column: [
{ title: '推送用户', field: 'userName', align: 'center' },
{ title: '推送内容', field: 'showName', align: 'center' },
{ title: '推送时间', field: 'sendTime', align: 'center' },
{ title: '推送时间', field: 'sendTime', align: 'center', sortable: true },
]
})

View File

@@ -61,6 +61,7 @@ const tableStore = new TableStore({
{ title: '数据名称', field: 'name', minWidth: 220 },
{ title: '别名', field: 'otherName', minWidth: 220 },
{ title: '展示名称', field: 'showName', minWidth: 170 },
{ title: '告警码', field: 'defaultValue', minWidth: 170 },
{ title: '相别', field: 'phaseName', minWidth: 80 },
{ title: '单位', field: 'unit', minWidth: 80 },
{ title: '基础数据类型', field: 'type', minWidth: 170 },

View File

@@ -82,52 +82,52 @@
<el-divider content-position="center">拓展数据</el-divider>
</div>
<el-form class="form-two" :model="form" label-width="140px" ref="formRef2" :rules="rules">
<el-form-item label="参数缺省值:" prop="defaultValue">
<el-form-item label="告警码(缺省值):" >
<el-input maxlength="32" show-word-limit v-model.trim="form.defaultValue" autocomplete="off"
placeholder="请输入参数缺省值"></el-input>
placeholder="请输入告警码(缺省值)"></el-input>
</el-form-item>
<el-form-item label="事件类别:" prop="eventType">
<el-form-item label="事件类别:" >
<el-input maxlength="32" show-word-limit v-model.trim="form.eventType" autocomplete="off"
placeholder="请输入事件类别"></el-input>
</el-form-item>
<el-form-item label="设置最大值:" prop="maxNum">
<el-form-item label="设置最大值:" >
<el-input maxlength="32" show-word-limit type="number" v-model.trim="form.maxNum" autocomplete="off"
placeholder="请输入设置最大值"></el-input>
</el-form-item>
<el-form-item label="设置最小值:" prop="minNum">
<el-form-item label="设置最小值:" >
<el-input maxlength="32" show-word-limit type="number" v-model.trim="form.minNum" autocomplete="off"
placeholder="请输入设置最小值"></el-input>
</el-form-item>
<el-form-item label="枚举序列:" prop="setValue">
<el-form-item label="枚举序列:">
<el-input maxlength="32" show-word-limit v-model.trim="form.setValue" autocomplete="off"
placeholder="请输入枚举序列"></el-input>
</el-form-item>
<el-form-item label="字符串长度上限:" prop="strlen">
<el-form-item label="字符串长度上限:" >
<el-input maxlength="32" show-word-limit type="number" v-model.trim="form.strlen" autocomplete="off"
placeholder="请输入字符串长度上限"></el-input>
</el-form-item>
<el-form-item label="上送规则:" prop="tranRule">
<el-form-item label="上送规则:" >
<el-input maxlength="32" show-word-limit v-model.trim="form.tranRule" autocomplete="off"
placeholder="请输入上送规则"></el-input>
</el-form-item>
<el-form-item label="是否可远程控制:" prop="ctlSts">
<el-form-item label="是否可远程控制:" >
<el-radio v-model.trim="form.ctlSts" :label="1"></el-radio>
<el-radio v-model.trim="form.ctlSts" :label="0"></el-radio>
</el-form-item>
<el-form-item label="是否需遥控校验:" prop="curSts">
<el-form-item label="是否需遥控校验:" >
<el-radio v-model.trim="form.curSts" :label="1"></el-radio>
<el-radio v-model.trim="form.curSts" :label="0"></el-radio>
</el-form-item>
<el-form-item label="是否存储:" prop="storeFlag">
<el-form-item label="是否存储:" >
<el-radio v-model.trim="form.storeFlag" :label="1"></el-radio>
<el-radio v-model.trim="form.storeFlag" :label="0"></el-radio>
</el-form-item>
<el-form-item label="是否加密:" prop="storeFlag">
<el-form-item label="是否加密:" >
<el-radio v-model.trim="form.storeFlag" :label="1"></el-radio>
<el-radio v-model.trim="form.storeFlag" :label="0"></el-radio>
</el-form-item>
<el-form-item label="数据是否上送:" prop="tranFlag">
<el-form-item label="数据是否上送:" >
<el-radio v-model.trim="form.tranFlag" :label="1"></el-radio>
<el-radio v-model.trim="form.tranFlag" :label="0"></el-radio>
</el-form-item>

View File

@@ -51,7 +51,7 @@ const tableStore = new TableStore({
{ title: '装置型号', field: 'devTypeName' },
{ title: '模板名称', field: 'name' },
{ title: '版本号', field: 'versionNo' },
{ title: '版本时间', field: 'versionDate' },
{ title: '版本时间', field: 'versionDate', sortable: true },
{
title: '操作',
align: 'center',

View File

@@ -1,8 +1,15 @@
<template>
<div class="default-main" :style="{ height: pageHeight.height }">
<vxe-table v-loading="tableStore.table.loading" height="auto" auto-resize ref="tableRef"
v-bind="defaultAttribute" :data="tableStore.table.data" :column-config="{ resizable: true }"
:tree-config="{ expandAll: true }">
<vxe-table
v-loading="tableStore.table.loading"
height="auto"
auto-resize
ref="tableRef"
v-bind="defaultAttribute"
:data="tableStore.table.data"
:column-config="{ resizable: true }"
:tree-config="{ expandAll: true }"
>
<vxe-column field="name" align="left" title="名称" tree-node></vxe-column>
<vxe-column field="area" title="区域">
<template #default="{ row }">
@@ -14,9 +21,16 @@
{{ row.remark || '/' }}
</template>
</vxe-column>
<vxe-column field="remark" title="操作" width="100px">
<vxe-column field="remark" title="操作" width="150px">
<template #default="{ row }">
<el-popconfirm title="确定删除吗?" confirm-button-type='danger' @confirm="deletes(row)" v-if="!row.path">
<el-button type="primary" link @click="edit(row)" v-if="!row.path">编辑</el-button>
<el-popconfirm
title="确定删除吗?"
confirm-button-type="danger"
@confirm="deletes(row)"
v-if="!row.path"
>
<template #reference>
<el-button type="danger" link>删除</el-button>
</template>
@@ -24,21 +38,55 @@
</template>
</vxe-column>
</vxe-table>
<el-dialog v-model="dialogVisible" title="编辑" width="500">
<el-form :model="form" ref="ruleFormRef" label-width="80px" :rules="rules">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" clearable placeholder="请输入名称" />
</el-form-item>
<el-form-item label="区域" :prop="form.pid == '0' ? 'city' : 'area'">
<!-- <el-input v-model="form.city" clearable placeholder="请输入区域" /> -->
<el-cascader
v-model="form.city"
v-if="form.pid == '0'"
style="width: 100%"
:options="areaTree"
:props="props"
clearable
filterable
placeholder="请输入区域"
/>
<el-input v-else v-model="form.area" clearable placeholder="请输入区域" />
</el-form-item>
<el-form-item label="备注" prop="description">
<el-input v-model="form.description" :rows="2" type="textarea" clearable placeholder="请输入备注" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="save">保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import { useDictData } from '@/stores/dictData'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { mainHeight } from '@/utils/layout'
import { ElMessageBox, ElMessage } from 'element-plus'
import { auditEngineering } from '@/api/cs-device-boot/edData';
import { auditEngineering, updateProject } from '@/api/cs-device-boot/edData'
import { activateUser, deluser, passwordConfirm } from '@/api/user-boot/user'
import tree from '@/assets/map/area.json'
defineOptions({
name: 'govern/manage/engineering'
})
const dictData = useDictData()
const tableRef = ref()
const dialogVisible = ref(false)
const pageHeight = mainHeight(20)
const tableStore = new TableStore({
url: '/cs-device-boot/csLedger/getProjectTree',
@@ -51,7 +99,30 @@ const tableStore = new TableStore({
}, 500)
}
})
const ruleFormRef = ref()
const rules = ref({
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
city: [{ required: true, message: '请输入区域', trigger: 'blur' }],
area: [{ required: true, message: '请输入区域', trigger: 'blur' }],
description: [{ required: true, message: '请输入描述', trigger: 'blur' }]
})
console.log("🚀 ~ dictData.state.areaTree:", dictData.state)
const areaTree: any = tree
const props = {
label: 'text',
value: 'value',
children: 'children',
checkStrictly: true
}
const form = ref({
id: '',
pid: '',
area: '',
name: '',
city: '',
description: ''
})
provide('tableStore', tableStore)
onMounted(() => {
@@ -67,18 +138,16 @@ const deletes = (row: any) => {
customClass: 'customInput',
inputType: 'text',
beforeClose: (action, instance, done) => {
if (action === 'confirm') {
if (instance.inputValue == null) {
return ElMessage.warning('请输入密码')
} else if (instance.inputValue?.length > 32) {
return ElMessage.warning('密码长度不能超过32位,当前密码长度为' + instance.inputValue.length)
} else {
done();
done()
}
} else {
done();
done()
}
}
}).then(({ value }) => {
@@ -92,11 +161,48 @@ const deletes = (row: any) => {
})
})
})
}
const addMenu = () => { }
// 编辑
const edit = (row: any) => {
form.value = {
id: row.id,
pid: row.pid,
name: row.name,
city: row.cityId,
area: row.area,
description: row.remark
}
dialogVisible.value = true
}
const save = () => {
ruleFormRef.value.validate((valid: any) => {
if (valid) {
if (form.value.pid == '0') {
auditEngineering({ ...form.value, city: form.value.city[form.value.city.length - 1] }).then(
(res: any) => {
ElMessage.success('保存成功')
dialogVisible.value = false
tableStore.index()
}
)
} else {
let params = new FormData()
params.append('id', form.value.id)
params.append('area', form.value.area)
params.append('description', form.value.description)
params.append('name', form.value.name)
updateProject(form.value).then((res: any) => {
ElMessage.success('保存成功')
dialogVisible.value = false
tableStore.index()
})
}
}
})
}
</script>
<style lang="scss">
.customInput {

View File

@@ -3,11 +3,37 @@
<TableHeader>
<template v-slot:select>
<el-form-item label="关键字筛选">
<el-input v-model.trim="tableStore.table.params.searchValue" style="width: 200px" clearable placeholder="请输入设备名称/网络设备ID" />
<el-input
v-model.trim="tableStore.table.params.searchValue"
style="width: 200px"
clearable
placeholder="请输入设备名称/网络设备ID"
/>
</el-form-item>
<el-form-item label="设备类型">
<!-- <el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue" placeholder="请输入设备类型" /> -->
<el-form-item label="流程阶段">
<el-select v-model.trim="tableStore.table.params.process" clearable placeholder="请选择状态">
<el-option label="功能调试" :value="2"></el-option>
<el-option label="出厂调试" :value="3"></el-option>
<el-option label="正式投运" :value="4"></el-option>
</el-select>
</el-form-item>
<el-form-item label="物联状态">
<el-select
v-model.trim="tableStore.table.params.connectStatus"
clearable
placeholder="请选择物联状态"
>
<el-option label="已连接" :value="1"></el-option>
<el-option label="未连接" :value="0"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备状态">
<el-select v-model.trim="tableStore.table.params.runStatus" clearable placeholder="请选择状态">
<el-option label="在线" :value="2"></el-option>
<el-option label="离线" :value="1"></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item label="设备类型">
<el-select
v-model.trim="tableStore.table.params.devType"
clearable
@@ -46,7 +72,7 @@
<el-option label="MQTT" value="MQTT"></el-option>
<el-option label="CLD" value="CLD"></el-option>
</el-select>
</el-form-item>
</el-form-item>-->
<!-- <el-form-item label="状态">
<el-select v-model.trim="tableStore.table.params.status" clearable placeholder="请选择状态">
<el-option label="未注册" :value="1"></el-option>
@@ -76,7 +102,7 @@
class="ml10"
icon="el-icon-Download"
@click="downLoadQrCode"
v-if="showQrCode"
:disabled="!showQrCode"
>
批量下载二维码
</el-button>
@@ -273,6 +299,7 @@ const formDevModelOptionsFilter = computed(() => {
const tableStore = new TableStore({
url: '/cs-device-boot/EquipmentDelivery/list',
method: 'POST',
isWebPaging: true,
column: [
{
width: '60',
@@ -285,15 +312,16 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'name' },
{ title: '网络设备ID', field: 'ndid' },
{ title: '设备名称', field: 'name', minWidth: 120 },
{ title: '网络设备ID', field: 'ndid', minWidth: 120 },
{
title: '设备类型',
field: 'devType',
formatter: row => {
return devTypeOptions.value.find((item: any) => item.value == row.cellValue).label
}
},
minWidth: 120
},
{
@@ -301,16 +329,18 @@ const tableStore = new TableStore({
field: 'devModel',
formatter: row => {
return devModelOptions.value.find((item: any) => item.value == row.cellValue).label
}
},
minWidth: 120
},
{
title: '通讯协议',
field: 'devAccessMethod',
formatter: row => {
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'CLD' ? 'CLD' : row.cellValue
}
},
minWidth: 120
},
{ title: '录入时间', field: 'createTime', sortable: true },
{ title: '录入时间', field: 'createTime', sortable: true, minWidth: 150 },
{
title: '使用状态',
@@ -359,7 +389,7 @@ const tableStore = new TableStore({
},
// { title: 'MQTT状态', field: 'connectStatus', width: 100, },
{
title: 'MQTT状态',
title: '物联状态',
field: 'connectStatus',
width: 100,
render: 'tag',
@@ -370,10 +400,12 @@ const tableStore = new TableStore({
replaceValue: {
未连接: '未连接',
已连接: '已连接'
}
},
minWidth: 80
},
{
title: '通讯状态',
title: '设备状态',
field: 'runStatus',
width: 100,
render: 'tag',
@@ -384,13 +416,30 @@ const tableStore = new TableStore({
replaceValue: {
1: '离线',
2: '在线'
}
},
minWidth: 80
},
{
title: '流程阶段',
field: 'process',
width: 100,
render: 'tag',
custom: {
2: 'warning',
3: 'warning',
4: 'success'
},
replaceValue: {
2: '功能调试',
3: '出厂调试',
4: '正式投运'
},
minWidth: 80
},
{
title: '操作',
align: 'center',
width: '220',
width: 220,
render: 'buttons',
buttons: [
//直连装置注册
@@ -647,11 +696,14 @@ const tableStore = new TableStore({
tableStore.table.params.orderBy = 'desc'
tableStore.table.params.devType = ''
tableStore.table.params.devModel = ''
tableStore.table.params.process = 2
tableStore.table.params.devAccessMethod = ''
tableStore.table.params.status = ''
tableStore.table.params.sortBy = ''
tableStore.table.params.orderBy = ''
tableStore.table.params.searchValue=''
tableStore.table.params.searchValue = ''
tableStore.table.params.connectStatus = ''
tableStore.table.params.runStatus = ''
// 设备类型
const devTypeChange = (e: any) => {

View File

@@ -28,7 +28,7 @@ const tableStore = new TableStore({
column: [
{ title: '标题', field: 'title', align: 'center' },
{ title: '描述', field: 'description', align: 'center' },
{ title: '发布时间', field: 'createTime', align: 'center' },
{ title: '发布时间', field: 'createTime', align: 'center' , sortable: true},
{
title: '状态',
field: 'status',

View File

@@ -0,0 +1,202 @@
<template>
<div class="default-main">
<TableHeader datePicker ref="refheader" >
<template v-slot:select>
<el-form-item label="关键字筛选">
<el-input
v-model.trim="tableStore.table.params.name"
placeholder="请输入关键字"
clearable
></el-input>
</el-form-item>
<el-form-item label="流程阶段">
<el-select v-model.trim="tableStore.table.params.process" clearable placeholder="请选择">
<el-option label="功能调试" :value="2"></el-option>
<el-option label="出厂调试" :value="3"></el-option>
<el-option label="正式投运" :value="4"></el-option>
</el-select>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" icon="el-icon-Download" @click="exportTab">导出</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
defineOptions({
name: 'manage/monthly'
})
const refheader = ref()
const devModelOptions: any = ref([])
queryByCode('Device_Type').then(res => {
queryByid(res.data.id).then(res => {
devModelOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
tableStore.index()
})
const tableStore = new TableStore({
url: '/cs-harmonic-boot/statisticsData/halfMonthReport',
method: 'POST',
isWebPaging: true,
exportName: '半月报功能',
column: [
{
title: '序号',
width: 80,
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '工程名称', field: 'engineeringName', minWidth: 150 },
{ title: '项目名称', field: 'projectName', minWidth: 130 },
{ title: '设备名称', field: 'devName', minWidth: 130 },
{ title: '监测点名称', field: 'lineName', minWidth: 130 },
{
title: '投运时间',
field: 'operationalTime',
width: 180,
sortable: true
},
{
title: '数据更新时间',
field: 'latestTime',
width: 180,
sortable: true
// formatter: (row: any) => {
// return row.cellValue || '/'
// }
},
{
title: '设备型号',
field: 'devType',
width: 130,
formatter: row => {
return devModelOptions.value.filter((item: any) => item.value == row.cellValue)[0]?.label
}
},
{ title: 'Mac地址', field: 'mac', width: 140 },
{
title: '流程阶段',
field: 'process',
width: 100,
fixed: 'right',
render: 'tag',
custom: {
2: 'warning',
3: 'warning',
4: 'success'
},
replaceValue: {
2: '功能调试',
3: '出厂调试',
4: '正式投运'
},
minWidth: 80
},
{
title: '运行状态',
field: 'operationalStatus',
render: 'tag',
fixed: 'right',
width: 100,
custom: {
停运: 'danger',
在运: 'success'
},
replaceValue: {
在运: '在运',
停运: '停运'
}
},
{
title: '通讯状态',
field: 'communicationStatus',
width: 100,
fixed: 'right',
render: 'tag',
custom: {
离线: 'danger',
在线: 'success'
},
replaceValue: {
离线: '离线',
在线: '在线'
}
},
{ title: '在线率(%)', fixed: 'right',width: 100, field: 'onlineRate', sortable: true },
{ title: '完整性(%)', fixed: 'right',width: 100, field: 'integrity', sortable: true }
],
beforeSearchFun: () => {},
loadCallback: () => {
let name = tableStore.table.params.name
let data = tableStore.table.copyData.filter(item => {
// 处理latestTime默认值
item.latestTime = item.latestTime || '/'
// 需要检查的字段列表
const fieldsToCheck = ['projectName', 'engineeringName', 'mac', 'devName', 'lineName']
console.log(
'🚀 ~ fieldsToCheck.some(field => item[field]?.includes(name)):',
fieldsToCheck.some(field => item[field]?.includes(name))
)
// 检查任何一个字段包含搜索名称
return fieldsToCheck.some(field => item[field]?.includes(name))
})
tableStore.table.copyData = JSON.parse(JSON.stringify(data))
tableStore.table.total = tableStore.table.copyData.length
if (data.length == 0) {
tableStore.table.data = []
} else {
tableStore.table.data = JSON.parse(
JSON.stringify(
window.XEUtils.chunk(data, tableStore.table.params.pageSize)[tableStore.table.params.pageNum - 1]
)
)
}
}
})
provide('tableStore', tableStore)
tableStore.table.params.process = 4
tableStore.table.params.name = ''
const tableRef = ref()
const exportTab = () => {
tableRef.value.getRef()?.exportData({
filename: '半月报功能', // 文件名字
sheetName: 'Sheet1',
type: 'xlsx', //导出文件类型 xlsx 和 csv
useStyle: true,
data: tableStore.table.copyData, // 数据源 // 过滤那个字段导出
columnFilterMethod: function (column: any) {
return !(
column.column.title === undefined ||
column.column.title === '序号' ||
column.column.title === '操作'
)
}
})
}
onMounted(() => {})
setTimeout(() => {
// tableStore.table.height = mainHeight(200).height as any
}, 0)
const addMenu = () => {}
</script>
<style></style>

View File

@@ -1,24 +1,57 @@
<template>
<el-dialog draggable :title="title" v-model.trim="dialogVisible" width="500px" :before-close="handleClose"
:close-on-click-modal="false">
<el-dialog
draggable
:title="title"
v-model.trim="dialogVisible"
width="500px"
:before-close="handleClose"
:close-on-click-modal="false"
>
<el-form ref="formRef" :rules="rules" :model="form" label-width="90px" class="form">
<el-form-item label="项目名称:" prop="name">
<el-input maxlength="32" show-word-limit v-model.trim="form.name" placeholder="请输入项目名称"></el-input>
<el-input
maxlength="32"
show-word-limit
v-model.trim="form.name"
placeholder="请输入项目名称"
></el-input>
</el-form-item>
<el-form-item label="工程项目:" class="top" prop="projectIds">
<el-tree-select v-model.trim="form.projectIds" default-expand-all show-checkbox node-key="id"
:props="defaultProps" multiple :data="Engineering" collapse-tags style="width: 100%" />
<el-tree-select
v-model.trim="form.projectIds"
default-expand-all
show-checkbox
node-key="id"
:props="defaultProps"
multiple
:data="Engineering"
collapse-tags
style="width: 100%"
/>
<!-- <el-cascader v-model.trim="form.projectIds" :options="Engineering" :props="defaultProps"
:show-all-levels="false" collapse-tags collapse-tags-tooltip clearable style="width: 100%;"/> -->
</el-form-item>
<el-form-item label="项目排序:" prop="orderBy">
<el-input maxlength="32" show-word-limit-number v-model.trim="form.orderBy" :min="0" :step="1"
step-strictly style="width: 100%" />
<el-input
maxlength="32"
show-word-limit-number
v-model.trim="form.orderBy"
:min="0"
:step="1"
step-strictly
style="width: 100%"
/>
</el-form-item>
<el-form-item label="备注:" class="top">
<el-input maxlength="300" show-word-limit type="textarea" :rows="2" placeholder="请输入内容"
v-model.trim="form.remark"></el-input>
<el-input
maxlength="300"
show-word-limit
type="textarea"
:rows="2"
placeholder="请输入内容"
v-model.trim="form.remark"
></el-input>
</el-form-item>
</el-form>
@@ -58,6 +91,8 @@ const rules = {
orderBy: [{ required: true, message: '请输入排序', trigger: 'blur' }]
}
const addFn = () => {
console.log('🚀 ~ add ~ form:', form)
formRef.value.validate((valid: boolean) => {
if (valid) {
if (title.value == '新增项目') {
@@ -144,7 +179,7 @@ const open = ref((row: any) => {
})
}
})
Engineering.value = res.data
Engineering.value = removeData(res.data)
})
title.value = row.title
dialogVisible.value = true
@@ -160,6 +195,17 @@ const open = ref((row: any) => {
form.id = row.row.id
}
})
const removeData = arr => {
return arr
.map(item => {
if (item.children) {
item.children = removeData(item.children)
}
return item.level <= 1 ? item : {}
})
.filter(item => Object.keys(item).length > 0)
}
const handleClose = () => {
dialogVisible.value = false
}

View File

@@ -1,261 +1,254 @@
<template>
<div class="default-main">
<TableHeader>
<template v-slot:select>
<el-form-item label="项目名称">
<el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue"
placeholder="请输入项目名称"></el-input>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" @click="onSubmitadd" icon="el-icon-Plus">新增</el-button>
</template>
</TableHeader>
<!-- <Table ref="tableRef" /> -->
<div style="overflow-x: hidden; overflow-y: scroll;padding: 0 10px;" v-loading="tableStore.table.loading"
:style="{ height: tableStore.table.height }">
<el-row :gutter="12">
<el-col :span="6" v-for="item in tableStore.table.data" :key="item.id" class="mt10">
<el-card class="box-card" @click="querdata(item)" shadow="hover">
<div slot="header" class="clearfix">
<span style="display: flex;align-items: center">{{ item.name }}
<el-tooltip class="item" effect="dark" content="修改项目" placement="top">
<Edit style="margin-left: 5px;width: 16px;" class=" xiaoshou color"
@click="editd(item)" />
</el-tooltip></span>
<div style="display: flex;justify-content: end;">
<el-button class="color" icon="el-icon-Share" style="padding: 3px 0" type="text"
@click="Aclick(item)">设计</el-button>
<!-- <el-button icon="el-icon-share" style="padding: 3px 0; color: green"
type="text" @click="shejid(item)">设计</el-button> -->
<!-- <el-button icon="el-icon-edit" style="padding: 3px 0; color: blue" type="text"
@click="shejid(item)">编辑</el-button> -->
<el-button icon="el-icon-Delete" style="padding: 3px 0; color: red" type="text"
@click="deleted(item)">删除</el-button>
</div>
</div>
<img :src="item.fileContent" class="image xiaoshou" @click="imgData(item)" />
</el-card>
</el-col>
</el-row>
</div>
<div class="table-pagination">
<el-pagination :currentPage="tableStore.table.params!.pageNum"
:page-size="tableStore.table.params!.pageSize" :page-sizes="[10, 20, 50, 100]" background
:layout="'sizes,total, ->, prev, pager, next, jumper'" :total="tableStore.table.total"
@size-change="onTableSizeChange" @current-change="onTableCurrentChange"></el-pagination>
</div>
<popup ref="popupRef" @submit="tableStore.index()" />
</div>
</template>
<script setup lang="ts">
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, provide } from 'vue'
import TableStore from '@/utils/tableStore'
// import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { deleteTopoTemplate, uploadTopo } from '@/api/cs-device-boot/topologyTemplate'
import { ElMessage, ElMessageBox } from 'element-plus'
import { audit, add } from '@/api/cs-harmonic-boot/mxgraph';
import { Edit } from '@element-plus/icons-vue'
import popup from './components/popup.vue'
defineOptions({
name: 'mxgraph/graph-list'
})
const tableRef = ref()
const popupRef = ref()
let DOMIN = window.location.origin
let STATIC_URL = DOMIN + '/api/system-boot/file/download?filePath='
localStorage.setItem('STATIC_URL', STATIC_URL)
const tableStore = new TableStore({
showPage: false,
url: '/cs-harmonic-boot/csconfiguration/queryPage',
method: 'POST',
publicHeight: 60,
column: [
],
loadCallback: () => {
}
})
provide('tableStore', tableStore)
tableStore.table.params.searchValue = ''
onMounted(() => {
tableStore.table.ref = tableRef.value
tableStore.index()
tableStore.table.loading = false
})
// 查询
const onSubmitadd = () => {
popupRef.value.open({
title: '新增项目'
})
}
const querdata = (e: any) => { }
const editd = (e: any) => {
popupRef.value.open({
title: '修改项目',
row: e
})
}
// 设计
const Aclick = (e: any) => {
window.open(window.location.origin + `/zutai/?id=${e.id}&&name=decodeURI(${e.name})&&flag=false`)
// const link = document.createElement("a"); //创建下载a标签
// link.target = `_blank`;
// link.href = `http://192.168.1.128:3001/zutai/?id=${e.id}&&name=decodeURI(${e.name})&&flag=false`;
// link.style.display = "none"; //默认隐藏元素
// document.body.appendChild(link); // body中添加元素
// link.click(); // 执行点击事件
}
const shejid = (e: any) => { }
// 删除
const deleted = (e: any) => {
ElMessageBox.confirm("此操作将永久删除该项目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
let data = {
id: e.id,
name: e.name,
status: "0",
};
audit(data).then((res: any) => {
if (res.code == "A0000") {
ElMessage({
type: "success",
message: "删除项目成功!",
});
}
tableStore.index()
});
})
.catch(() => {
ElMessage({
type: "info",
message: "已取消删除",
});
});
}
const imgData = (e: any) => {
window.open(window.location.origin + `/zutai/?id=${e.id}&&name=decodeURI(${e.name})&&flag=true`)
// const link = document.createElement("a"); //创建下载a标签
// link.target = `_blank`;
// link.href = `http://192.168.1.128:3001/zutai/#/?id=${e.id}&&name=decodeURI(${e.name})&&flag=true`;
// link.style.display = "none"; //默认隐藏元素
// document.body.appendChild(link); // body中添加元素
// link.click(); // 执行点击事件
}
const onTableSizeChange = (val: number) => {
tableStore.onTableAction('page-size-change', { size: val })
}
const onTableCurrentChange = (val: number) => {
tableStore.onTableAction('current-page-change', { page: val })
}
</script>
<style lang="scss" scoped>
.text {
font-size: 14px;
}
span {
font-size: 16px;
}
.item {
margin-bottom: 18px;
}
.image {
display: block;
width: 100%;
height: 220px;
}
.clearfix::before,
.clearfix::after {
display: table;
content: "";
}
.clearfix::after {
clear: both;
}
.box-card {
width: 100%;
// border: 1px solid #000;
box-shadow: var(--el-box-shadow-light)
}
.xiaoshou {
cursor: pointer;
}
.setstyle {
min-height: 200px;
padding: 0 !important;
margin: 0;
overflow: auto;
cursor: default !important;
}
.color {
color: var(--el-color-primary);
}
:deep(.el-select-dropdown__wrap) {
max-height: 300px;
}
:deep(.el-tree) {
padding-top: 15px;
padding-left: 10px;
// 不可全选样式
.el-tree-node {
.is-leaf+.el-checkbox .el-checkbox__inner {
display: inline-block;
}
.el-checkbox .el-checkbox__inner {
display: none;
}
}
}
:deep(.el-card__header) {
padding: 13px 20px;
height: 44px;
}
.table-pagination {
height: 58px;
box-sizing: border-box;
width: 100%;
max-width: 100%;
background-color: var(--ba-bg-color-overlay);
padding: 13px 15px;
border-left: 1px solid #e4e7e9;
border-right: 1px solid #e4e7e9;
border-bottom: 1px solid #e4e7e9;
}
:deep(.el-pagination__sizes) {
.el-select {
min-width: 128px;
}
}
</style>
<template>
<div class="default-main">
<TableHeader>
<template v-slot:select>
<el-form-item label="项目名称">
<el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue"
placeholder="请输入项目名称"></el-input>
</el-form-item>
</template>
<template v-slot:operation>
<el-button type="primary" @click="onSubmitadd" icon="el-icon-Plus">新增</el-button>
</template>
</TableHeader>
<!-- <Table ref="tableRef" /> -->
<div style="overflow-x: hidden; overflow-y: scroll;padding: 0 10px;" v-loading="tableStore.table.loading"
:style="{ height: tableStore.table.height }">
<el-row :gutter="12">
<el-col :span="6" v-for="item in tableStore.table.data" :key="item.id" class="mt10">
<el-card class="box-card" @click="querdata(item)" shadow="hover">
<div slot="header" class="clearfix">
<span style="display: flex;align-items: center">{{ item.name }}
<el-tooltip class="item" effect="dark" content="修改项目" placement="top">
<Edit style="margin-left: 5px;width: 16px;" class=" xiaoshou color"
@click="editd(item)" />
</el-tooltip></span>
<div style="display: flex;justify-content: end;">
<el-button class="color" icon="el-icon-Share" style="padding: 3px 0" type="text"
@click="Aclick(item)">设计</el-button>
<!-- <el-button icon="el-icon-share" style="padding: 3px 0; color: green"
type="text" @click="shejid(item)">设计</el-button> -->
<!-- <el-button icon="el-icon-edit" style="padding: 3px 0; color: blue" type="text"
@click="shejid(item)">编辑</el-button> -->
<el-button icon="el-icon-Delete" style="padding: 3px 0; color: red" type="text"
@click="deleted(item)">删除</el-button>
</div>
</div>
<img v-if="item.fileContent" :src="item.fileContent" class="image xiaoshou" @click="imgData(item)" />
<el-empty v-else description="暂无设计" style="height: 220px;"/>
</el-card>
</el-col>
</el-row>
</div>
<div class="table-pagination">
<el-pagination :currentPage="tableStore.table.params!.pageNum"
:page-size="tableStore.table.params!.pageSize" :page-sizes="[10, 20, 50, 100]" background
:layout="'sizes,total, ->, prev, pager, next, jumper'" :total="tableStore.table.total"
@size-change="onTableSizeChange" @current-change="onTableCurrentChange"></el-pagination>
</div>
<popup ref="popupRef" @submit="tableStore.index()" />
</div>
</template>
<script setup lang="ts">
import { Plus } from '@element-plus/icons-vue'
import { ref, onMounted, provide } from 'vue'
import TableStore from '@/utils/tableStore'
// import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { deleteTopoTemplate, uploadTopo } from '@/api/cs-device-boot/topologyTemplate'
import { ElMessage, ElMessageBox } from 'element-plus'
import { audit, add } from '@/api/cs-harmonic-boot/mxgraph';
import { Edit } from '@element-plus/icons-vue'
import popup from './components/popup.vue'
defineOptions({
name: 'mxgraph/graph-list'
})
const tableRef = ref()
const popupRef = ref()
let DOMIN = window.location.origin
let STATIC_URL = DOMIN + '/api/system-boot/file/download?filePath='
localStorage.setItem('STATIC_URL', STATIC_URL)
const tableStore = new TableStore({
showPage: false,
url: '/cs-harmonic-boot/csconfiguration/queryPage',
method: 'POST',
publicHeight: 60,
column: [
],
loadCallback: () => {
}
})
provide('tableStore', tableStore)
tableStore.table.params.searchValue = ''
onMounted(() => {
tableStore.table.ref = tableRef.value
tableStore.index()
tableStore.table.loading = false
})
// 查询
const onSubmitadd = () => {
popupRef.value.open({
title: '新增项目'
})
}
const querdata = (e: any) => { }
const editd = (e: any) => {
popupRef.value.open({
title: '修改项目',
row: e
})
}
// 设计
const Aclick = (e: any) => {
window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false`)
// window.open('http://192.168.1.128:4001' + `/zutai/?id=${e.id}&&name=${e.name}&&preview=false`)
}
const shejid = (e: any) => { }
// 删除
const deleted = (e: any) => {
ElMessageBox.confirm("此操作将永久删除该项目, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
let data = {
id: e.id,
name: e.name,
status: "0",
};
audit(data).then((res: any) => {
if (res.code == "A0000") {
ElMessage({
type: "success",
message: "删除项目成功!",
});
}
tableStore.index()
});
})
.catch(() => {
ElMessage({
type: "info",
message: "已取消删除",
});
});
}
const imgData = (e: any) => {
window.open(window.location.origin + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true#/preview`)
// window.open('http://192.168.1.128:4001' + `/zutai/?id=${e.id}&&name=${e.name}&&preview=true#/preview`)
}
const onTableSizeChange = (val: number) => {
tableStore.onTableAction('page-size-change', { size: val })
}
const onTableCurrentChange = (val: number) => {
tableStore.onTableAction('current-page-change', { page: val })
}
</script>
<style lang="scss" scoped>
.text {
font-size: 14px;
}
span {
font-size: 16px;
}
.item {
margin-bottom: 18px;
}
.image {
display: block;
width: 100%;
height: 220px;
}
.clearfix::before,
.clearfix::after {
display: table;
content: "";
}
.clearfix::after {
clear: both;
}
.box-card {
width: 100%;
// border: 1px solid #000;
box-shadow: var(--el-box-shadow-light)
}
.xiaoshou {
cursor: pointer;
}
.setstyle {
min-height: 200px;
padding: 0 !important;
margin: 0;
overflow: auto;
cursor: default !important;
}
.color {
color: var(--el-color-primary);
}
:deep(.el-select-dropdown__wrap) {
max-height: 300px;
}
:deep(.el-tree) {
padding-top: 15px;
padding-left: 10px;
// 不可全选样式
.el-tree-node {
.is-leaf+.el-checkbox .el-checkbox__inner {
display: inline-block;
}
.el-checkbox .el-checkbox__inner {
display: none;
}
}
}
:deep(.el-card__header) {
padding: 13px 20px;
height: 44px;
}
.table-pagination {
height: 58px;
box-sizing: border-box;
width: 100%;
max-width: 100%;
background-color: var(--ba-bg-color-overlay);
padding: 13px 15px;
border-left: 1px solid #e4e7e9;
border-right: 1px solid #e4e7e9;
border-bottom: 1px solid #e4e7e9;
}
:deep(.el-pagination__sizes) {
.el-select {
min-width: 128px;
}
}
</style>

View File

@@ -9,6 +9,9 @@
<pane :size="(100 - size)" style="background: #fff" :style="height">
<TableHeader ref="TableHeaderRef" :showReset="false">
<template v-slot:select>
<el-form-item label="时间:">
<DatePicker ref="datePickerRef"></DatePicker>
</el-form-item>
<el-form-item label="模板策略">
<el-select v-model.trim="Template" @change="changetype" placeholder="请选择模版" value-key="id">
<el-option v-for="item in templatePolicy" :key="item.id" :label="item.name"
@@ -40,6 +43,7 @@ import { mainHeight } from '@/utils/layout'
import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel'
import { exportExcel } from '@/views/system/reportForms/export.js'
import 'splitpanes/dist/splitpanes.css'
import DatePicker from '@/components/form/datePicker/time.vue'
import { Splitpanes, Pane } from 'splitpanes'
// import data from './123.json'
defineOptions({
@@ -52,7 +56,7 @@ const TableHeaderRef = ref()
const dotList: any = ref({})
const Template: any = ref({})
const reportForm: any = ref('')
const datePickerRef = ref()
const templatePolicy: any = ref([])
const tableStore = new TableStore({
@@ -62,6 +66,11 @@ const tableStore = new TableStore({
beforeSearchFun: () => {
tableStore.table.params.tempId = Template.value.id
tableStore.table.params.lineId = dotList.value.id
tableStore.table.params.startTime = datePickerRef.value.timeValue[0],
tableStore.table.params.endTime = datePickerRef.value.timeValue[1],
delete tableStore.table.params.searchBeginTime
delete tableStore.table.params.searchEndTime
delete tableStore.table.params.timeFlag
},
loadCallback: () => {
tableStore.table.data.forEach((item: any) => {

View File

@@ -44,8 +44,8 @@ const tableStore: any = new TableStore({
return row.cellValue == 1 ? '电能质量报表类型' : row.cellValue == 2 ? '用能报表类型' : ''
} },
{ field: 'updateBy', title: '更新用户' },
{ field: 'createTime', title: '创建时间' },
{ field: 'updateTime', title: '更新时间' },
{ field: 'createTime', title: '创建时间' , sortable: true},
{ field: 'updateTime', title: '更新时间', sortable: true },
{
title: '操作',
width: '220',

View File

@@ -203,7 +203,7 @@ const tableStore = new TableStore({
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'cloud' ? 'CLD' : row.cellValue
}
},
{ title: '录入时间', field: 'createTime' },
{ title: '录入时间', field: 'createTime' , sortable: true},
{ title: '网络设备ID', field: 'ndid' },
{
title: '状态',

View File

@@ -204,7 +204,7 @@ const tableStore = new TableStore({
return row.cellValue === 'MQTT' ? 'MQTT' : row.cellValue === 'cloud' ? 'CLD' : row.cellValue
}
},
{ title: '录入时间', field: 'createTime' },
{ title: '录入时间', field: 'createTime', sortable: true },
{ title: '网络设备ID', field: 'ndid' },
{
title: '状态',

View File

@@ -252,9 +252,9 @@ const histogram = (res: any) => {
} else if (0.4 < params.value && params.value <= 0.8 && params.value !== 0.05) {
return '#FF9900'
} else if (0 < params.value && params.value <= 0.4 && params.value !== 0.05) {
return '#CC0000'
return '#A52a2a'
} else if (params.value == 0.05) {
return '#CC0000'
return '#A52a2a'
}
}
}
@@ -276,13 +276,13 @@ const histogram = (res: any) => {
name: '',
yAxis: 0.4,
lineStyle: {
color: '#CC0000'
color: '#A52a2a'
},
label: {
// position: "middle",
formatter: '{b}',
textStyle: {
color: '#CC0000'
color: '#A52a2a'
}
}
},

View File

@@ -163,7 +163,7 @@ const map = (res: any) => {
}
],
inRange: {
color: ['#ccc', '#CC0000', '#FF9900', '#3399CC', '#339966']
color: ['#ccc', '#A52a2a', '#FF9900', '#3399CC', '#339966']
}
},
@@ -284,9 +284,9 @@ const histogram = (res: any) => {
} else if (0.4 < params.value && params.value <= 0.8 && params.value !== 0.05) {
return '#FF9900'
} else if (0 < params.value && params.value <= 0.4 && params.value !== 0.05) {
return '#CC0000'
return '#A52a2a'
} else if (params.value == 0.05) {
return '#CC0000'
return '#A52a2a'
}
}
}
@@ -308,13 +308,13 @@ const histogram = (res: any) => {
name: '',
yAxis: 0.4,
lineStyle: {
color: '#CC0000'
color: '#A52a2a'
},
label: {
// position: "middle",
formatter: '{b}',
textStyle: {
color: '#CC0000'
color: '#A52a2a'
}
}
},

View File

@@ -33,7 +33,7 @@ const tableStore = new TableStore({
url: '/system-boot/audit/getAuditLog',
method: 'POST',
column: [
{ title: '操作时间', field: 'time', align: 'center', width: 200 },
{ title: '操作时间', field: 'time', align: 'center', width: 200 , sortable: true},
{ title: '操作人员', field: 'userName', align: 'center', width: 120 },
{ title: '操作类型', field: 'operate', align: 'center', width: 220 },
{ title: '事件描述', field: 'describe', align: 'center', showOverflow: true, minWidth: 200 },

View File

@@ -61,14 +61,14 @@ const tableStore = new TableStore({
{ title: '供电公司', field: 'gdName', align: 'center', width: 120 },
{ title: '变电站', field: 'bdName', align: 'center', showOverflow: true, minWidth: 100 },
{ title: '终端编号', field: 'devName', align: 'center', width: 160 },
{ title: '投运时间', field: 'loginTime', align: 'center', width: 200 },
{ title: '投运时间', field: 'loginTime', align: 'center', width: 200 , sortable: true},
{ title: '厂家', field: 'manufacturer', align: 'center', width: 160 },
{ title: '型号', field: 'devType', align: 'center', width: 200 },
{ title: '网络参数', field: 'ip', align: 'center', width: 200 },
{ title: '端口', field: 'port', align: 'center', width: 100 },
{ title: '终端状态', field: 'runFlag', align: 'center', width: 100 },
{ title: '通讯状态', field: 'comFlag', align: 'center', width: 100 },
{ title: '最新数据', field: 'updateTime', align: 'center', width: 200 },
{ title: '最新数据', field: 'updateTime', align: 'center', width: 200, sortable: true },
{
title: '评价',
field: 'onlineEvaluate',

View File

@@ -18,8 +18,8 @@
<span class="smallBlock" style="background: #996600"></span>
热备用
</span>
<span style="color: #cc0000">
<span class="smallBlock" style="background: #cc0000"></span>
<span style="color: #A52a2a">
<span class="smallBlock" style="background: #A52a2a"></span>
停运
</span>
</span>
@@ -33,8 +33,8 @@
<span style="color: #daa520">
<span class="smallBlock" style="background: #daa520"></span>
{{ '60 %≤在线率 < 90 %' }} </span>
<span style="color: #cc0000">
<span class="smallBlock" style="background: #cc0000"></span>
<span style="color: #A52a2a">
<span class="smallBlock" style="background: #A52a2a"></span>
{{ '在线率 < 60 %' }} </span>
</span>
</div>
@@ -174,7 +174,7 @@ const tableStore = new TableStore({
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 1,
color: '#cc0000'
color: '#A52a2a'
}
])
} else if ((params.value = 3.14159)) {
@@ -216,7 +216,7 @@ const tableStore = new TableStore({
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 1,
color: '#CC0000'
color: '#A52a2a'
}
])
} else if ((params.value = 3.14159)) {
@@ -309,7 +309,7 @@ const tableStore = new TableStore({
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 1,
color: '#cc0000'
color: '#A52a2a'
}
])
} else if ((params.value = 3.14159)) {
@@ -351,7 +351,7 @@ const tableStore = new TableStore({
return new echarts.graphic.LinearGradient(0, 1, 0, 0, [
{
offset: 1,
color: '#CC0000'
color: '#A52a2a'
}
])
} else if ((params.value = 3.14159)) {

View File

@@ -46,8 +46,8 @@ const tableStore = new TableStore({
{ title: '开启等级', field: 'openLevelName' },
{ title: '开启算法', field: 'openDescribeName' },
{ title: '字典描述', field: 'remark' },
{ title: '创建时间', field: 'createTime' },
{ title: '更新时间', field: 'updateTime' },
{ title: '创建时间', field: 'createTime', sortable: true },
{ title: '更新时间', field: 'updateTime', sortable: true},
{
title: '状态',
field: 'stateName',

View File

@@ -78,7 +78,7 @@ const tableStore = new TableStore({
},
{ title: '版本号', field: 'versionName', width: '150' },
{ title: '创建时间', field: 'createTime', width: '220' },
{ title: '创建时间', field: 'createTime', width: '220', sortable: true },
{
title: '发布类型', field: 'sev', formatter: (row,) => {
return row.cellValue == 0 ? '优化' : 'bug调整'

View File

@@ -42,8 +42,8 @@ const tableStore: any = new TableStore({
{ field: 'name', title: '模板名称' },
{ field: 'createBy', title: '创建用户' },
{ field: 'updateBy', title: '更新用户' },
{ field: 'createTime', title: '创建时间' },
{ field: 'updateTime', title: '更新时间' },
{ field: 'createTime', title: '创建时间', sortable: true },
{ field: 'updateTime', title: '更新时间', sortable: true },
{
title: '操作',
width: '220',

1
types/table.d.ts vendored
View File

@@ -8,6 +8,7 @@ declare global {
interface CnTable {
ref: VxeTableInstance | null
data: TableRow[] | any
copyData: TableRow[] | any
allData: TableRow[] | any
allFlag: Boolean
// 前端分页数据