| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- <template>
- <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 slot="footer" class="dialog-footer">
- <el-button v-no-more-click @click="cancel">关 闭</el-button>
- </div>
- </el-dialog>
- </div>
- </template>
- <script>
- import Konva from 'konva'
- import { getIsSystemAttributeByKey } from '@/api/system/configuration'
- import { getIsLockCabinetSlotsPage } from '@/api/mes/lockCabinet/slots'
- export default {
- data() {
- return {
- stage: null,
- layer: null,
- cachedResults: {},
- cachedImages: {}, // 缓存已加载的图片节点
- slotData: [],
- dialogVisible: false,
- errorInfo: ''
- }
- },
- mounted() {
- this.initKonva()
- this.getData()
- },
- methods: {
- cancel() {
- this.dialogVisible = false
- },
- async getData() {
- const data = {
- current: 1,
- size: -1,
- cabinetId: this.$route.query.cabinetId
- }
- try {
- const res = await getIsLockCabinetSlotsPage(data)
- this.slotData = res.data?.records || []
- const icons = [
- 'icon.locker.normal',
- 'icon.locker.out',
- 'icon.padlock.normal',
- 'icon.padlock.out',
- 'icon.locker.exception'
- ]
- const results = await Promise.all(icons.map(key => getIsSystemAttributeByKey(key)))
- this.cachedResults = icons.reduce((map, key, idx) => {
- map[key] = results[idx].data?.sysAttrValue || ''
- return map
- }, {})
- await this.preloadImages()
- this.renderSlots()
- } catch (err) {
- console.error('获取数据失败:', err)
- }
- },
- showErrorDialog(slot) {
- this.errorInfo = slot.remark || '未知异常'
- this.dialogVisible = true
- },
- initKonva() {
- this.stage = new Konva.Stage({
- container: this.$refs.container,
- width: 1800,
- height: 400
- })
- this.layer = new Konva.Layer()
- this.stage.add(this.layer)
- },
- async preloadImages() {
- const urls = Object.values(this.cachedResults)
- const promises = urls.map(url => this.loadImageOnce(url))
- await Promise.all(promises)
- },
- async renderSlots() {
- this.layer.destroyChildren()
- const keySlots = this.slotData.filter(item => item.slotType === '0')
- const lockSlots = this.slotData.filter(item => item.slotType === '1')
- await this.renderSlotRow(keySlots, 50)
- await this.renderSlotRow(lockSlots, 170)
- this.layer.draw()
- },
- async renderSlotRow(slots, boxTopY) {
- const padding = 20
- const boxWidth = 700
- const boxHeight = 120
- const centerX = this.stage.width() / 2
- const boxStartX = centerX - boxWidth / 2
- const box = new Konva.Rect({
- x: boxStartX,
- y: boxTopY,
- width: boxWidth,
- height: boxHeight,
- stroke: 'black',
- strokeWidth: 2
- })
- this.layer.add(box)
- const loadedImages = []
- for (const slot of slots) {
- const { slotType, isOccupied } = slot
- let baseKey = ''
- if (slotType === '0') {
- baseKey = isOccupied === '1' ? 'icon.locker.normal' : 'icon.locker.out'
- } else {
- baseKey = isOccupied === '1' ? 'icon.padlock.normal' : 'icon.padlock.out'
- }
- const baseUrl = this.cachedResults[baseKey]
- if (!baseUrl || !this.cachedImages[baseUrl]) continue
- const imageNode = this.cachedImages[baseUrl].clone()
- const width = slotType === '0' ? 110 : 40
- const height = 90
- imageNode.setAttrs({ width, height })
- loadedImages.push({ imageNode, slot, width, height })
- }
- const totalSlots = loadedImages.length
- const spacing = totalSlots > 1
- ? (boxWidth - 2 * padding - totalSlots * loadedImages[0].width) / (totalSlots - 1)
- : 0
- let currentX = boxStartX + padding
- for (const { imageNode, slot, width, height } of loadedImages) {
- imageNode.setAttrs({
- x: currentX,
- y: boxTopY + (boxHeight - height) / 2
- })
- this.layer.add(imageNode)
- if (slot.status === '1') {
- const exUrl = this.cachedResults['icon.locker.exception']
- if (exUrl && this.cachedImages[exUrl]) {
- const exImage = this.cachedImages[exUrl].clone()
- const exWidth = 30
- const exHeight = 30
- exImage.setAttrs({
- x: currentX + (width - exWidth) / 2,
- y: boxTopY + (boxHeight - exHeight) / 2,
- width: exWidth,
- height: exHeight
- })
- exImage.on('click', () => {
- this.showErrorDialog(slot)
- })
- this.layer.add(exImage)
- }
- }
- currentX += width + spacing
- }
- },
- loadImageOnce(url) {
- if (this.cachedImages[url]) return Promise.resolve(this.cachedImages[url])
- return new Promise((resolve, reject) => {
- const img = new window.Image()
- img.crossOrigin = 'Anonymous'
- img.src = url
- img.onload = () => {
- const konvaImage = new Konva.Image({ image: img })
- this.cachedImages[url] = konvaImage
- resolve(konvaImage)
- }
- img.onerror = reject
- })
- }
- }
- }
- </script>
- <style scoped lang="scss">
- </style>
|