<template>
|
<TableLayout :permissions="['business:ywconditioner:query']">
|
<el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
|
<el-form-item label="设备信息" prop="devKeyword">
|
<el-input v-model="searchForm.devKeyword" placeholder="名称/编号/房间" clearable @keypress.enter.native="search" />
|
</el-form-item>
|
<el-form-item label="在线状态" prop="onlineFilter">
|
<el-select v-model="searchForm.onlineFilter" clearable placeholder="全部" style="min-width: 120px">
|
<el-option label="在线" value="在线" />
|
<el-option label="离线" value="离线" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="开关状态" prop="pwrFilter">
|
<el-select v-model="searchForm.pwrFilter" clearable placeholder="全部" style="min-width: 120px">
|
<el-option label="开机" :value="1" />
|
<el-option label="关机" :value="0" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="网关MAC" prop="wgMacFilter">
|
<el-select v-model="searchForm.wgMacFilter" clearable filterable placeholder="全部" style="min-width: 180px">
|
<el-option v-for="item in gatewayOptions" :key="item.wgMac" :label="item.wgMac" :value="item.wgMac" />
|
</el-select>
|
</el-form-item>
|
<section>
|
<el-button type="primary" icon="el-icon-search" @click="search">查询</el-button>
|
<el-button icon="el-icon-refresh" @click="reset">重置</el-button>
|
</section>
|
</el-form>
|
<template v-slot:table-wrap>
|
<ul class="toolbar">
|
<li>
|
<el-button
|
type="primary"
|
:loading="isSyncingAll"
|
v-permissions="['business:ywconditioner:sync']"
|
@click="handleSyncAll"
|
>一键同步空调多联机</el-button>
|
</li>
|
<li>
|
<el-button
|
type="primary"
|
:loading="isSyncingDevices"
|
v-permissions="['business:ywconditioner:sync']"
|
@click="handleSyncDevices"
|
>同步设备和状态</el-button>
|
</li>
|
</ul>
|
<div v-loading="isWorking.search" class="card-grid-wrap">
|
<div v-if="!tableData.list.length && !isWorking.search" class="empty-tip">暂无设备数据,请先同步内机</div>
|
<div class="card-grid">
|
<YwConditionerCard
|
v-for="item in tableData.list"
|
:key="item.id"
|
:device="item"
|
:power-loading="powerLoadingId === item.id"
|
:lock-loading="lockLoadingId === item.id"
|
@history="openHistory"
|
@lock="openLock"
|
@unlock="unlockDevice"
|
@toggle-power="togglePower"
|
@set-mode="setMode"
|
@set-fan="setFan"
|
@set-temp="setTemp"
|
/>
|
</div>
|
</div>
|
<pagination
|
@size-change="handleSizeChange"
|
@current-change="handlePageChange"
|
:pagination="paginationConfig"
|
/>
|
</template>
|
<YwConditionerLockWindow ref="lockWindow" @success="refreshList" />
|
<YwConditionerHistoryWindow ref="historyWindow" />
|
</TableLayout>
|
</template>
|
|
<script>
|
import BaseTable from '@/components/base/BaseTable'
|
import TableLayout from '@/layouts/TableLayout'
|
import Pagination from '@/components/common/Pagination'
|
import * as conditionerApi from '@/api/business/ywconditioner'
|
import YwConditionerCard from './components/YwConditionerCard'
|
import YwConditionerLockWindow from './components/YwConditionerLockWindow'
|
import YwConditionerHistoryWindow from './components/YwConditionerHistoryWindow'
|
|
const ADJUST_OPERATE_INTERVAL_MS = 2000
|
const ADJUST_ACTION_TYPES = [2, 3, 4]
|
const OFFLINE_TIP = '设备离线了,请检查对应设备网络'
|
|
export default {
|
name: 'YwConditioner',
|
extends: BaseTable,
|
components: {
|
TableLayout,
|
Pagination,
|
YwConditionerCard,
|
YwConditionerLockWindow,
|
YwConditionerHistoryWindow
|
},
|
data () {
|
return {
|
searchForm: {
|
devKeyword: '',
|
onlineFilter: '',
|
pwrFilter: null,
|
wgMacFilter: ''
|
},
|
gatewayOptions: [],
|
isSyncingAll: false,
|
isSyncingDevices: false,
|
powerLoadingId: null,
|
lockLoadingId: null,
|
deviceAdjustOperateAt: {}
|
}
|
},
|
computed: {
|
paginationConfig () {
|
return {
|
...this.tableData.pagination,
|
pageSizes: [15, 30, 45, 60]
|
}
|
}
|
},
|
created () {
|
this.api = conditionerApi
|
this.module = '空调内机'
|
this.configData['field.id'] = 'id'
|
this.configData['field.main'] = 'name'
|
this.tableData.pagination.pageSize = 15
|
this.loadGatewayOptions()
|
this.search()
|
},
|
methods: {
|
loadGatewayOptions () {
|
conditionerApi.gatewayOptions()
|
.then(list => { this.gatewayOptions = list || [] })
|
.catch(() => {})
|
},
|
buildSearchModel () {
|
const model = {}
|
if (this.searchForm.devKeyword) model.devKeyword = this.searchForm.devKeyword
|
if (this.searchForm.onlineFilter) model.onlineFilter = this.searchForm.onlineFilter
|
if (this.searchForm.pwrFilter !== null && this.searchForm.pwrFilter !== '') {
|
model.pwrFilter = this.searchForm.pwrFilter
|
}
|
if (this.searchForm.wgMacFilter) model.wgMacFilter = this.searchForm.wgMacFilter
|
return model
|
},
|
handlePageChange (pageIndex) {
|
const page = Number(pageIndex)
|
if (page > 0) {
|
this.tableData.pagination.pageIndex = page
|
}
|
this.isWorking.search = true
|
conditionerApi.fetchCardPage({
|
page: this.tableData.pagination.pageIndex,
|
capacity: this.tableData.pagination.pageSize,
|
model: this.buildSearchModel(),
|
sorts: this.tableData.sorts
|
})
|
.then(data => {
|
this.tableData.list = data.records || []
|
this.tableData.pagination.total = data.total || 0
|
})
|
.catch(() => {})
|
.finally(() => { this.isWorking.search = false })
|
},
|
refreshList () {
|
this.handlePageChange(this.tableData.pagination.pageIndex)
|
},
|
patchDeviceInList (id, patch) {
|
const idx = this.tableData.list.findIndex(item => item.id === id)
|
if (idx === -1) return
|
this.$set(this.tableData.list, idx, { ...this.tableData.list[idx], ...patch })
|
},
|
isDeviceOnline (row) {
|
const o = row && row.online
|
if (o === '在线' || o === '1' || o === 1) return true
|
if (o === 88 || o === 66 || o === '88' || o === '66') return true
|
if (typeof o === 'string' && o.toLowerCase() === 'online') return true
|
return false
|
},
|
ensureDeviceOnline (row) {
|
if (!this.isDeviceOnline(row)) {
|
this.$tip.warning(OFFLINE_TIP)
|
return false
|
}
|
return true
|
},
|
reserveAdjustOperate (deviceId) {
|
const last = this.deviceAdjustOperateAt[deviceId]
|
const now = Date.now()
|
if (last && now - last < ADJUST_OPERATE_INTERVAL_MS) {
|
const waitSec = ((ADJUST_OPERATE_INTERVAL_MS - (now - last)) / 1000).toFixed(1)
|
this.$tip.warning(`操作过于频繁,请 ${waitSec} 秒后再试`)
|
return false
|
}
|
this.$set(this.deviceAdjustOperateAt, deviceId, now)
|
return true
|
},
|
reset () {
|
this.searchForm = { devKeyword: '', onlineFilter: '', pwrFilter: null, wgMacFilter: '' }
|
this.search()
|
},
|
handleSyncAll () {
|
this.$dialog.actionConfirm('确认同时全量同步更新 网关、电表、计费系数、内机数据信息吗?', '一键同步空调多联机')
|
.then(() => {
|
this.isSyncingAll = true
|
conditionerApi.syncAll()
|
.then(res => {
|
this.$tip.apiSuccess(res || '同步成功')
|
this.loadGatewayOptions()
|
this.search()
|
})
|
.catch(e => this.$tip.apiFailed(e))
|
.finally(() => { this.isSyncingAll = false })
|
})
|
.catch(() => {})
|
},
|
handleSyncDevices () {
|
this.$dialog.actionConfirm('确认从智精灵平台同步设备信息和最新设备状态吗?', '同步设备和状态')
|
.then(() => {
|
this.isSyncingDevices = true
|
conditionerApi.syncDevicesAndStatus()
|
.then(res => {
|
this.$tip.apiSuccess(res || '同步成功')
|
this.search()
|
})
|
.catch(e => this.$tip.apiFailed(e))
|
.finally(() => { this.isSyncingDevices = false })
|
})
|
.catch(() => {})
|
},
|
openHistory (row) {
|
this.$refs.historyWindow.open(row)
|
},
|
openLock (row) {
|
if (!this.ensureDeviceOnline(row)) return
|
this.$refs.lockWindow.open(row)
|
},
|
unlockDevice (row) {
|
if (!this.ensureDeviceOnline(row)) return
|
this.$dialog.actionConfirm('确认解锁该设备的锁定设置吗?', '设备解锁')
|
.then(() => {
|
this.lockLoadingId = row.id
|
conditionerApi.lock({
|
id: row.id,
|
lockPwr: 0,
|
pwr: -1,
|
mode: -1,
|
fan: -1,
|
minTemp: -1,
|
maxTemp: -1,
|
source: 'admin'
|
})
|
.then(res => {
|
this.$tip.apiSuccess(res || '解锁成功')
|
this.patchDeviceInList(row.id, { ktLock: 0, lockPwr: 0 })
|
this.refreshList()
|
})
|
.catch(e => this.$tip.apiFailed(e))
|
.finally(() => { this.lockLoadingId = null })
|
})
|
.catch(() => {})
|
},
|
togglePower (row) {
|
if (!this.ensureDeviceOnline(row)) return
|
const next = row.pwr === 1 ? 0 : 1
|
const msg = next === 1 ? '确认开机吗?' : '确认关机吗?'
|
this.$dialog.actionConfirm(msg, '设备控制')
|
.then(() => {
|
this.powerLoadingId = row.id
|
conditionerApi.operate({
|
id: row.id,
|
actionType: 1,
|
setVal: next,
|
source: 'admin'
|
})
|
.then(res => {
|
this.$tip.apiSuccess(res || '操作成功')
|
this.patchDeviceInList(row.id, { pwr: next })
|
this.refreshList()
|
})
|
.catch(e => this.$tip.apiFailed(e))
|
.finally(() => { this.powerLoadingId = null })
|
})
|
.catch(() => {})
|
},
|
doOperate (row, actionType, setVal, label, patch) {
|
if (!this.ensureDeviceOnline(row)) return
|
if (ADJUST_ACTION_TYPES.includes(actionType) && !this.reserveAdjustOperate(row.id)) {
|
return
|
}
|
conditionerApi.operate({
|
id: row.id,
|
actionType,
|
setVal,
|
source: 'admin'
|
})
|
.then(res => {
|
this.$tip.apiSuccess(res || label + '成功')
|
if (patch) {
|
this.patchDeviceInList(row.id, patch)
|
}
|
})
|
.catch(e => this.$tip.apiFailed(e))
|
},
|
setMode (row, mode) {
|
if (row.mode === mode) return
|
this.doOperate(row, 2, mode, '模式设置', { mode })
|
},
|
setFan (row, fan) {
|
const cur = row.fanSet != null ? row.fanSet : row.fan
|
if (cur === fan) return
|
this.doOperate(row, 3, fan, '风速设置', { fanSet: fan, fan })
|
},
|
setTemp (row, delta) {
|
let cur = Number(row.tempSet)
|
if (isNaN(cur)) cur = 260
|
if (cur > 100) cur = cur / 10
|
const next = Math.max(16, Math.min(32, cur + delta))
|
this.doOperate(row, 4, next, '温度设置', { tempSet: next * 10 })
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.card-grid-wrap { min-height: 120px; }
|
.card-grid {
|
display: grid;
|
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
gap: 16px;
|
padding: 8px 0 16px;
|
}
|
.empty-tip {
|
text-align: center;
|
color: #909399;
|
padding: 48px 0;
|
}
|
</style>
|