Files
intc-iot-web/src/views/light/lightMonitor/index.vue
2025-04-30 12:12:10 +08:00

647 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="app-container">
<el-row :gutter="20">
<!--层级数据-->
<el-col :span="4" :xs="24">
<div class="head-container">
<el-input v-model="buildingName" placeholder="请输入层级名称" clearable prefix-icon="Search" style="margin-bottom: 20px" />
</div>
<div class="head-container">
<el-scrollbar>
<el-tree
:data="buildingOptions"
:props="{ label: 'label', children: 'children' }"
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="buildingTreeRef"
node-key="id"
:highlight-current="false"
default-expand-all
show-checkbox
:check-on-click-node="true"
:check-strictly="false"
@check="handleCheckClick"
/>
</el-scrollbar>
</div>
</el-col>
<el-col :span="20" :xs="24">
<div class="search-con">
<div class="title">查询条件</div>
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="所属产品" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择所属产品" clearable>
<el-option v-for="dict in lamp_product" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="灯具名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入灯具名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="网络状态" prop="networkStatus">
<el-select v-model="queryParams.networkStatus" placeholder="请选择网络状态" clearable>
<el-option v-for="dict in is_online" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-form>
<div class="search-btn-con">
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button type="info" icon="Refresh" @click="resetQuery">重置</el-button>
</div>
</div>
<div class="main-con">
<div class="title-con">
<div class="title">基本信息</div>
<div class="operate-btn-con">
<el-button :disabled="multiple" @click="handleAdjust(1)" icon="Open" v-hasPermi="['light:lamp:add']">开灯</el-button>
<el-button :disabled="multiple" @click="handleAdjust(0)" icon="TurnOff" v-hasPermi="['light:lamp:export']">关灯</el-button>
<el-button :disabled="multiple" @click="handleAdjust(2)" icon="Sunny" v-hasPermi="['light:lamp:export']">调光</el-button>
<el-button :disabled="multiple" @click="handleCreateGroups" icon="Connection" v-hasPermi="['light:lamp:export']">创建分组</el-button>
<el-button :disabled="multiple" @click="handleConfig" icon="FolderChecked" v-hasPermi="['light:lamp:export']">策略配置</el-button>
<el-button :disabled="multiple" @click="handleClear" icon="FolderDelete" v-hasPermi="['light:lamp:export']">清除策略</el-button>
</div>
</div>
<div class="content-con" v-loading="loading">
<el-table v-loading="loading" :data="lampList" height="calc(100% - 60px)" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="所属产品" align="center" prop="type">
<template #default="scope">
<dict-tag :options="lamp_product" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="IMEI号" align="center" prop="code" />
<el-table-column label="灯具名称" align="center" prop="name" />
<el-table-column label="所属场所" align="center" prop="poleName" />
<el-table-column label="层级名称" align="center" prop="buildingName" />
<el-table-column label="灯具状态" align="center" prop="lampStatus">
<template #default="scope">
<dict-tag :options="switch_status" :value="scope.row.lampStatus" />
</template>
</el-table-column>
<el-table-column label="亮度(%)" align="center" prop="brightness" width="100" />
<el-table-column label="网络状态" align="center" prop="networkStatus">
<template #default="scope">
<dict-tag :options="is_online" :value="scope.row.networkStatus" />
</template>
</el-table-column>
<el-table-column label="数据最后更新时间" align="center" prop="lastUpdatedTime" width="180"></el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<div class="ctrl-btn d-flex">
<el-tooltip v-for="item in operateList" :key="item.id" class="item" effect="dark" :content="item.title" placement="top">
<el-button :icon="item.icon" :v-hasPermi="item.hasPermi" circle @click="handleOperate(item.id, scope.row)"></el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination small background layout="total, prev, pager, next" :total="total" @current-change="handleCurrentChange" />
</div>
</div>
</el-col>
</el-row>
<el-dialog title="历史数据" v-model="openHis" width="1100px" append-to-body destroy-on-close>
<el-form :model="queryHisParams" ref="queryHisRef" inline>
<el-form-item label="选择时间" prop="startTime">
<el-date-picker v-model="queryHisParams.time" type="daterange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" />
</el-form-item>
<el-form-item label="">
<el-button type="primary" icon="Search" @click="handleHisQuery">搜索</el-button>
<el-button type="info" icon="Refresh" @click="resetHisQuery">重置</el-button>
</el-form-item>
</el-form>
<el-table v-loading="loadingHis" :data="tableHisData">
<el-table-column label="" align="center" width="55">
<template #default="scope">
<el-checkbox v-model="scope.row.isSelect" @change="selectHandler(scope)"></el-checkbox>
</template>
</el-table-column>
<el-table-column label="上报时间" property="dataReportingTime" width="200px" />
<el-table-column label="能耗(kwh)" property="energyConsumption" />
<el-table-column label="电压(V)" property="voltage" />
<el-table-column label="电流(mA)" property="currentValue" />
<el-table-column label="有功功率(W)" property="power" />
<el-table-column label="温度(°C)" align="center" prop="temperature"> </el-table-column>
<el-table-column label="信号强度(dbm)" property="signalStrength" />
</el-table>
<el-pagination small background layout="total, prev, pager, next" :total="historyTotal" @current-change="handleCurrentHisChange" />
<template #footer>
<span class="dialog-footer">
<div class="search-btn-con">
<el-button type="primary" @click="cancelHis">确定</el-button>
</div>
</span>
</template>
</el-dialog>
<el-dialog :title="detailTitle" v-model="detailOpen" width="1150px" append-to-body>
<el-radio-group v-model="activeName" style="margin-bottom: 20px">
<el-radio-button label="first">基本信息</el-radio-button>
<el-radio-button label="second">上传信息</el-radio-button>
<el-radio-button label="third">当前策略</el-radio-button>
</el-radio-group>
<div v-if="activeName === 'first'" class="basic-information">
<el-row :gutter="20">
<el-col :span="8">
<span class="title">所属产品</span
><span class="content"> <dict-tag style="display: inline" :options="lamp_product" :value="basicInformation.type" /></span>
</el-col>
<el-col :span="8">
<span class="title">IMEI号</span><span class="content">{{ basicInformation.imeiCode }}</span>
</el-col>
<el-col :span="8">
<span class="title">灯具名称</span><span class="content">{{ basicInformation.name }}</span>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<span class="title">所属场所</span><span class="content">{{ basicInformation.poleName }}</span>
</el-col>
<el-col :span="8">
<span class="title">所属层级</span><span class="content">{{ basicInformation.buildingName }}</span>
</el-col>
<el-col :span="8">
<span class="title">所属集控</span><span class="content">{{ basicInformation.centralizedControlName }}</span>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<span class="title">调光类型</span
><span class="content"><dict-tag style="display: inline" :options="dimmer_type" :value="basicInformation.dimmerType" /></span>
</el-col>
<el-col :span="8">
<span class="title">项目经纬度</span><span class="content">{{ basicInformation.lampLonLat }}</span>
</el-col>
<el-col :span="8">
<span class="title">灯控经纬度</span><span class="content">{{ basicInformation.lampLonLat }}</span>
</el-col>
</el-row>
</div>
<div v-if="activeName === 'second'" class="basic-information">
<el-row :gutter="20">
<el-col :span="8">
<span class="title">数据上报时间</span><span class="content">{{ uploadInformation.dataReportingTime }}</span>
</el-col>
<el-col :span="8">
<span class="title">网络状态</span>
<span class="content"><dict-tag style="display: inline" :options="is_online" :value="uploadInformation.networkStatus" /></span>
</el-col>
<el-col :span="8">
<span class="title">最后在线时间</span><span class="content">{{ uploadInformation.lastUpdatedTime }}</span>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<span class="title">电压(v)</span><span class="content">{{ uploadInformation.voltage }}</span>
</el-col>
<el-col :span="8">
<span class="title">电流(mA)</span><span class="content">{{ uploadInformation.currentValue }}</span>
</el-col>
<el-col :span="8">
<span class="title">功率(W)</span><span class="content">{{ uploadInformation.power }}</span>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<span class="title">能耗(kwh)</span><span class="content">{{ uploadInformation.energyConsumption }}</span>
</el-col>
<el-col :span="8">
<span class="title">温度()</span><span class="content">{{ uploadInformation.temperature }}</span>
</el-col>
<el-col :span="8">
<span class="title">当前亮灯时长(h)</span><span class="content">{{ uploadInformation.lightingUpTimeph }}</span>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<span class="title">累计亮灯时长(h)</span><span class="content">{{ uploadInformation.lightingUpTotalTimeph }}</span>
</el-col>
</el-row>
</div>
<div v-if="activeName === 'third'" class="basic-information">
<div class="main-con">
<div class="content-con">
<el-table v-loading="lampStrategyLoading" :data="lampStrategyList">
<el-table-column label="策略名称" align="center" prop="name" />
<el-table-column label="开始时间" align="center" prop="beginDate" />
<el-table-column label="结束时间" align="center" prop="endDate" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<div class="ctrl-btn d-flex">
<el-tooltip v-for="item in operateListStrategy" :key="item.id" class="item" effect="dark" :content="item.title" placement="top">
<el-button :icon="item.icon" :v-hasPermi="item.hasPermi" circle @click="handleOperateLampStrategy(item.id, scope.row)"></el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<template #footer> </template>
</el-dialog>
<el-dialog title="调光" v-model="dimmingOpen" width="500px" append-to-body>
<el-slider v-model="dimmingValue" show-input />
<template #footer>
<span class="dialog-footer">
<div class="search-btn-con">
<el-button @click="cancelDimming">取消</el-button>
<el-button type="primary" @click="submitDimming">确定</el-button>
</div>
</span>
</template>
</el-dialog>
<el-dialog title="新增分组" v-model="groupOpen" width="800px" append-to-body @close="handleGroupCancel">
<div class="search-con">
<el-form ref="groupRef" :model="groupForm" :inline="true" :rules="groupRules" label-width="80px">
<el-form-item label="分组用途" prop="purpose">
<el-select v-model="groupForm.purpose" placeholder="请选择分组用途" clearable>
<el-option v-for="dict in light_group_purpose" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="分组名称" prop="name">
<el-input v-model="groupForm.name" placeholder="请输入分组名称" />
</el-form-item>
<el-form-item label="分组描述" prop="remark">
<el-input type="textarea" v-model="groupForm.remark" placeholder="请输入备注信息" />
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleGroupSubmit"> </el-button>
<el-button @click="handleGroupCancel"> </el-button>
</div>
</template>
</el-dialog>
<LampStrategyConfig :currentIds="ids" :lampStrategyOpen="lampStrategyOpen" @update-open="handleUpdateOpen" type="1" />
<lampStrategyDialog :open="openStrategy" :strategyId="strategyId" />
</div>
</template>
<script setup name="Lamp">
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import lampStrategyDialog from '@/views/components/light/lampStrategyDialog'
import LampStrategyConfig from '@/views/components/light/lampStrategyConfig.vue'
import { addGroup } from '@/api/light/group'
import { listLamp, getLamp, getLampUploadInfo, getLampHistory, getLampStrategy } from '@/api/light/lamp'
import { updateLampControl } from '@/api/light/lightMonitor'
import { clearLampStrategy } from '@/api/light/lampStrategy'
import { buildingTree } from '@/api/building/buildingInfo'
// eslint-disable-next-line no-unused-vars
import { require } from '@/utils/require'
import { nextTick, reactive, toRefs } from 'vue'
import { treeFilterNode } from '@/utils/utils'
const { proxy } = getCurrentInstance()
const { is_online, switch_status, lamp_product, dimmer_type, light_group_purpose } = proxy.useDict(
'is_online',
'switch_status',
'lamp_product',
'dimmer_type',
'light_group_purpose'
)
const lampList = ref([])
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const buildingOptions = ref(undefined)
const basicInformation = ref(null)
const detailTitle = ref('')
const detailOpen = ref(false)
const uploadInformation = ref(null)
const activeName = ref('first')
const openHis = ref(false)
const currentHisId = ref(false)
const loadingHis = ref(false)
const tableHisData = ref([])
const historyTotal = ref(0)
const dimmingOpen = ref(false)
const dimmingValue = ref(0)
const lampStrategyOpen = ref(false)
const openStrategy = ref(false)
const strategyId = ref('')
const currentId = ref('')
const lampStrategyObj = reactive({
lampStrategyLoading: false,
lampStrategyList: []
})
const { lampStrategyLoading, lampStrategyList } = toRefs(lampStrategyObj)
const operateListStrategy = ref([
{ id: 'view', icon: 'View', title: '详情', hasPermi: ['light:group:query'] },
{ id: 'clear', icon: 'FolderDelete', title: '清除', hasPermi: ['light:group:remove'] }
])
const queryHisParams = ref({
time: '',
pageNum: 1
})
const operateList = ref([
{ id: 'view', icon: 'Document', title: '详情', hasPermi: ['light:lamp:query'] },
{ id: 'history', icon: 'Histogram', title: '历史数据', hasPermi: ['light:lamp:query'] }
])
const data = reactive({
form: {},
formHis: {},
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
buildingId: null,
buildingIdList: null,
code: null,
type: null,
networkStatus: null
},
rules: {
name: [{ required: true, message: '灯具名称不能为空', trigger: 'blur' }],
position: [{ required: true, message: '灯具位置不能为空', trigger: 'change' }],
code: [{ required: true, message: '灯具编号不能为空', trigger: 'change' }]
}
})
const { queryParams, formHis } = toRefs(data)
const groupData = reactive({
groupOpen: false,
groupForm: {
purpose: '',
name: '',
remark: ''
},
groupRules: {
purpose: [{ required: true, message: '分组用途不能为空', trigger: 'change' }],
name: [{ required: true, message: '分组名称不能为空', trigger: 'blur' }]
}
})
const { groupOpen, groupForm, groupRules } = toRefs(groupData)
const handleOperate = (operate, row) => {
switch (operate) {
case 'view':
handleView(row)
break
case 'history':
handleHis(row)
break
default:
break
}
}
const buildingName = ref('')
/** 通过条件过滤节点 */
const filterNode = (value, data, node) => {
return treeFilterNode(value, data, node)
}
/** 根据名称筛选层级树 */
watch(buildingName, (val) => {
// eslint-disable-next-line dot-notation
proxy.$refs['buildingTreeRef'].filter(val)
})
/** 查询灯具信息列表 */
function getList() {
loading.value = true
listLamp(queryParams.value).then((response) => {
lampList.value = response.rows
total.value = response.total
loading.value = false
})
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm('queryRef')
queryParams.value.buildingIdList = null
proxy.$refs.buildingTreeRef.setCheckedKeys([])
handleQuery()
}
// 分页
const handleCurrentChange = (val) => {
queryParams.value.pageNum = val
getList()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map((item) => item.id)
single.value = selection.length !== 1
multiple.value = !selection.length
}
const handleAdjust = (type) => {
if (type === 2) {
dimmingOpen.value = true
} else {
updateLampControl(ids.value, type, type).then((res) => {
ElMessage.success(type === 1 ? '开灯成功' : '关灯成功')
getList()
})
}
}
const submitDimming = () => {
updateLampControl(ids.value, '2', dimmingValue.value).then((res) => {
ElMessage.success('调光成功')
cancelDimming()
getList()
})
}
const cancelDimming = () => {
dimmingOpen.value = false
dimmingValue.value = 0
}
// 查看
const handleView = (row) => {
const _id = row.id || ids.value
currentId.value = _id
activeName.value = 'first'
getLamp(_id).then((response) => {
basicInformation.value = response.data
detailOpen.value = true
detailTitle.value = '查看灯具信息'
})
getLampUploadInfo(_id).then((response) => {
uploadInformation.value = response.data
})
getLampStrategy(_id).then((res) => {
lampStrategyList.value = res.data
})
}
/** 历史数据操作 */
function handleHis(row) {
const _id = row.id || ids.value
currentHisId.value = _id
getHisList(1)
openHis.value = true
}
// 取消按钮
function cancelHis() {
queryHisParams.value.time = ''
openHis.value = false
}
const handleCurrentHisChange = (num) => {
getHisList(num)
}
const handleHisQuery = () => {
getHisList(1)
}
const resetHisQuery = () => {
queryHisParams.value.time = ''
historyTotal.value = 0
getHisList(1)
}
const getHisList = (num) => {
loadingHis.value = true
const timeRange = queryHisParams.value.time
let st = ''
let et = ''
if (timeRange && timeRange.length === 2) {
st = dayjs(timeRange[0]).format('YYYY-MM-DD')
et = dayjs(timeRange[1]).format('YYYY-MM-DD')
}
getLampHistory({ lampId: currentHisId.value, startTime: st, endTime: et, pageNum: num, pageSize: 10 }).then((res) => {
loadingHis.value = false
tableHisData.value = res.rows
historyTotal.value = res.total
formHis.value = res.data
})
}
/** 查询层级下拉树结构 */
function getBuildingTree() {
buildingTree().then((response) => {
buildingOptions.value = response.data
})
}
/** 节点复选框事件 */
function handleCheckClick(data) {
const checkNodes = proxy.$refs.buildingTreeRef.getCheckedNodes()
const buildingIdArray = []
// 遍历
for (let i = 0; i < checkNodes.length; i++) {
const node = checkNodes[i]
buildingIdArray.push(node.id)
}
const halfCheckNodes = proxy.$refs.buildingTreeRef.getHalfCheckedNodes()
// 遍历
for (let i = 0; i < halfCheckNodes.length; i++) {
const node = halfCheckNodes[i]
buildingIdArray.push(node.id)
}
queryParams.value.buildingIdList = buildingIdArray
handleQuery()
}
const resetGroup = () => {
groupForm.value = {
name: '',
purpose: '',
remark: ''
}
}
const handleCreateGroups = () => {
groupOpen.value = true
console.log(ids.value)
}
const handleGroupSubmit = () => {
proxy.$refs.groupRef.validate((valid) => {
if (valid) {
const { name, purpose, remark } = groupForm.value
addGroup({ ids: ids.value, name, purpose, remark, type: '1' }).then((response) => {
proxy.$modal.msgSuccess('添加分组成功')
groupOpen.value = false
resetGroup()
getList()
})
}
})
}
const handleGroupCancel = () => {
groupOpen.value = false
resetGroup()
}
const handleConfig = () => {
lampStrategyOpen.value = false
nextTick(() => {
lampStrategyOpen.value = true
})
}
const handleUpdateOpen = () => {
lampStrategyOpen.value = false
getList()
}
const handleClear = () => {
proxy.$modal
.confirm('确认清除所有灯具策略?')
.then(function () {
clearLampStrategy({ ids: ids.value.join(','), lampStrategyId: '', type: '1' }).then((res) => {
proxy.$modal.msgSuccess('清除成功')
getList()
})
})
.catch(() => {})
}
const handleOperateLampStrategy = (operate, row) => {
switch (operate) {
case 'view':
console.log(row.id)
strategyId.value = ''
nextTick(() => {
strategyId.value = row.id
openStrategy.value = true
})
break
case 'clear':
proxy.$modal
.confirm('确认清除该灯具的当前策略?')
.then(function () {
clearLampStrategy({ ids: currentId.value, lampStrategyId: row.id, type: '1' }).then((res) => {
proxy.$modal.msgSuccess('清除成功')
getLampStrategy(currentId.value).then((res) => {
lampStrategyList.value = res.data
})
})
})
.catch(() => {})
break
default:
break
}
}
getBuildingTree()
getList()
</script>