|
@@ -1,17 +1,20 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div>
|
|
<div>
|
|
|
- <div ref="container" style="width: 900px; height: 400px;"></div>
|
|
|
|
|
- <el-dialog
|
|
|
|
|
- title="异常信息"
|
|
|
|
|
- :visible.sync="dialogVisible"
|
|
|
|
|
- width="400px"
|
|
|
|
|
- >
|
|
|
|
|
- <h4 style="text-align: center;font-weight: bolder">{{ errorInfo }}</h4>
|
|
|
|
|
|
|
+ <div class="time-card">
|
|
|
|
|
+ <i class="el-icon-time"></i>
|
|
|
|
|
+ <div class="time-content">
|
|
|
|
|
+ <div class="label">最后更新</div>
|
|
|
|
|
+ <div class="time">{{ updateTime }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div ref="container" style="width: 900px; height: 400px;margin: 0 auto"></div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog title="异常信息" :visible.sync="dialogVisible" width="400px">
|
|
|
|
|
+ <h4 style="text-align: center; font-weight: bolder">{{ errorInfo }}</h4>
|
|
|
<div slot="footer" class="dialog-footer">
|
|
<div slot="footer" class="dialog-footer">
|
|
|
<el-button v-no-more-click @click="cancel">关 闭</el-button>
|
|
<el-button v-no-more-click @click="cancel">关 闭</el-button>
|
|
|
</div>
|
|
</div>
|
|
|
</el-dialog>
|
|
</el-dialog>
|
|
|
-
|
|
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
@@ -26,10 +29,11 @@ export default {
|
|
|
stage: null,
|
|
stage: null,
|
|
|
layer: null,
|
|
layer: null,
|
|
|
cachedResults: {},
|
|
cachedResults: {},
|
|
|
- cachedImages: {}, // 缓存已加载的图片节点
|
|
|
|
|
|
|
+ cachedImages: {},
|
|
|
slotData: [],
|
|
slotData: [],
|
|
|
dialogVisible: false,
|
|
dialogVisible: false,
|
|
|
- errorInfo: ''
|
|
|
|
|
|
|
+ errorInfo: '',
|
|
|
|
|
+ updateTime: null
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
mounted() {
|
|
mounted() {
|
|
@@ -46,9 +50,9 @@ export default {
|
|
|
size: -1,
|
|
size: -1,
|
|
|
cabinetId: this.$route.query.cabinetId
|
|
cabinetId: this.$route.query.cabinetId
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
const res = await getIsLockCabinetSlotsPage(data)
|
|
const res = await getIsLockCabinetSlotsPage(data)
|
|
|
|
|
+ this.updateTime = res.data.records[0].updateTime
|
|
|
this.slotData = res.data?.records || []
|
|
this.slotData = res.data?.records || []
|
|
|
|
|
|
|
|
const icons = [
|
|
const icons = [
|
|
@@ -58,7 +62,6 @@ export default {
|
|
|
'icon.padlock.out',
|
|
'icon.padlock.out',
|
|
|
'icon.locker.exception'
|
|
'icon.locker.exception'
|
|
|
]
|
|
]
|
|
|
-
|
|
|
|
|
const results = await Promise.all(icons.map(key => getIsSystemAttributeByKey(key)))
|
|
const results = await Promise.all(icons.map(key => getIsSystemAttributeByKey(key)))
|
|
|
this.cachedResults = icons.reduce((map, key, idx) => {
|
|
this.cachedResults = icons.reduce((map, key, idx) => {
|
|
|
map[key] = results[idx].data?.sysAttrValue || ''
|
|
map[key] = results[idx].data?.sysAttrValue || ''
|
|
@@ -78,8 +81,8 @@ export default {
|
|
|
initKonva() {
|
|
initKonva() {
|
|
|
this.stage = new Konva.Stage({
|
|
this.stage = new Konva.Stage({
|
|
|
container: this.$refs.container,
|
|
container: this.$refs.container,
|
|
|
- width: 1800,
|
|
|
|
|
- height: 400
|
|
|
|
|
|
|
+ width: 900,
|
|
|
|
|
+ height: 800
|
|
|
})
|
|
})
|
|
|
this.layer = new Konva.Layer()
|
|
this.layer = new Konva.Layer()
|
|
|
this.stage.add(this.layer)
|
|
this.stage.add(this.layer)
|
|
@@ -91,19 +94,28 @@ export default {
|
|
|
},
|
|
},
|
|
|
async renderSlots() {
|
|
async renderSlots() {
|
|
|
this.layer.destroyChildren()
|
|
this.layer.destroyChildren()
|
|
|
|
|
+ const grouped = {}
|
|
|
|
|
+ for (const slot of this.slotData) {
|
|
|
|
|
+ const key = `${slot.row}`
|
|
|
|
|
+ if (!grouped[key]) grouped[key] = []
|
|
|
|
|
+ grouped[key].push(slot)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const keySlots = this.slotData.filter(item => item.slotType === '0')
|
|
|
|
|
- const lockSlots = this.slotData.filter(item => item.slotType === '1')
|
|
|
|
|
|
|
+ const rows = Object.keys(grouped).sort((a, b) => Number(a) - Number(b))
|
|
|
|
|
+ const startY = 20
|
|
|
|
|
+ const rowHeight = 120
|
|
|
|
|
+ const rowGap = 20
|
|
|
|
|
|
|
|
- await this.renderSlotRow(keySlots, 50)
|
|
|
|
|
- await this.renderSlotRow(lockSlots, 170)
|
|
|
|
|
|
|
+ for (let i = 0; i < rows.length; i++) {
|
|
|
|
|
+ const rowSlots = grouped[rows[i]]
|
|
|
|
|
+ await this.renderSlotRow(rowSlots, startY + i * (rowHeight + rowGap), rowHeight)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
this.layer.draw()
|
|
this.layer.draw()
|
|
|
},
|
|
},
|
|
|
- async renderSlotRow(slots, boxTopY) {
|
|
|
|
|
|
|
+ async renderSlotRow(slots, boxTopY, boxHeight) {
|
|
|
const padding = 20
|
|
const padding = 20
|
|
|
- const boxWidth = 700
|
|
|
|
|
- const boxHeight = 120
|
|
|
|
|
|
|
+ const boxWidth = 860
|
|
|
const centerX = this.stage.width() / 2
|
|
const centerX = this.stage.width() / 2
|
|
|
const boxStartX = centerX - boxWidth / 2
|
|
const boxStartX = centerX - boxWidth / 2
|
|
|
|
|
|
|
@@ -118,7 +130,6 @@ export default {
|
|
|
this.layer.add(box)
|
|
this.layer.add(box)
|
|
|
|
|
|
|
|
const loadedImages = []
|
|
const loadedImages = []
|
|
|
-
|
|
|
|
|
for (const slot of slots) {
|
|
for (const slot of slots) {
|
|
|
const { slotType, isOccupied } = slot
|
|
const { slotType, isOccupied } = slot
|
|
|
let baseKey = ''
|
|
let baseKey = ''
|
|
@@ -127,7 +138,6 @@ export default {
|
|
|
} else {
|
|
} else {
|
|
|
baseKey = isOccupied === '1' ? 'icon.padlock.normal' : 'icon.padlock.out'
|
|
baseKey = isOccupied === '1' ? 'icon.padlock.normal' : 'icon.padlock.out'
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
const baseUrl = this.cachedResults[baseKey]
|
|
const baseUrl = this.cachedResults[baseKey]
|
|
|
if (!baseUrl || !this.cachedImages[baseUrl]) continue
|
|
if (!baseUrl || !this.cachedImages[baseUrl]) continue
|
|
|
|
|
|
|
@@ -193,6 +203,31 @@ export default {
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
-
|
|
|
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
|
|
|
+.time-card {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 12px 20px;
|
|
|
|
|
+ background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+ transition: all 0.3s;
|
|
|
|
|
+}
|
|
|
|
|
+.time-card.glow {
|
|
|
|
|
+ box-shadow: 0 0 15px rgba(64, 158, 255, 0.5);
|
|
|
|
|
+}
|
|
|
|
|
+.time-card i {
|
|
|
|
|
+ font-size: 24px;
|
|
|
|
|
+ color: #409EFF;
|
|
|
|
|
+ margin-right: 12px;
|
|
|
|
|
+}
|
|
|
|
|
+.time-content .label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ color: #909399;
|
|
|
|
|
+}
|
|
|
|
|
+.time-content .time {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ color: #303133;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|