|
|
<template> <div class="app-container"> <div class="venue-header"> <h4 @click="handleToGrids"><i class="iconfont icon-shuju" />书架总览</h4> <span class="bookshelf-area">{{ floorName }} - {{ regionName }}</span> <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> </div> <div class="venue-content"> <crudOperation :permission="permission"> <template v-slot:middle> <el-select v-model="layerVal" clearable size="small" placeholder="楼层" class="filter-item" style="width: 100px; margin-right: 20px;"> <el-option v-for="item in layerOptions" :key="item.id" :label="item.name" :value="item.id" /> </el-select> <el-button v-permission="permission.add" size="mini" @click="crud.toAdd"> <i class="iconfont icon-shengchengpandiandan" /> 书架盘点 </el-button> </template> <template v-slot:right> <el-button :loading="crud.downloadLoading" size="mini" @click="doExport(crud.selections)"> <i class="iconfont icon-daochu" /> 导出 </el-button> </template> </crudOperation> <div class="venue-left"> <div class="container-right tab-content"> <span class="right-top-line" /> <span class="left-bottom-line" />
<!-- <div style="display: flex;justify-content: flex-start; align-items: center;"> --> <swiper ref="swiperTitle" class="swiper-title" :options="swiperOptionTitle" :auto-update="true" :auto-destroy="true" :delete-instance-on-destroy="true" :cleanup-styles-on-destroy="true" > <swiper-slide v-for="(item, index) of tabListData" ref="swiperSlideItem" :key="'name' + index" :iname="item.name" class="swiper-slide-title" > <div class="tab-name" :class="{ active: index === swiperActiveIndex }" @click="handleSlidClickFun(index)" > {{ item.name }} </div> </swiper-slide> </swiper> <div class="tag-info"> <p>错序:1</p> <p>错架:1</p> <p>在架:20</p> </div> <!-- </div> --> <swiper ref="swiperContent" class="swiper-content" :options="swiperOptionContent" :auto-update="true" :auto-destroy="true" :delete-instance-on-destroy="true" :cleanup-styles-on-destroy="true" > <swiper-slide v-for="(item, index) of tabListData" :key="'content' + index" class="swiper-slide-content" >
<ul class="cabinet-row"> <li v-for="(cell,i) in booShelfGrid" :key="i" class="cabinet-cell" :style="cellStyle" :class="{ active: i === cellIndex }" @click="handleCellCurrent(cell,i)" @mouseenter="showPopover(i)" @mouseleave="hidePopover" > <span class="cell-name">{{ removeAreaPrefix(cell.gridName) }}</span> <!-- v-if="popoverIndex === i" --> <el-popover v-if="popoverIndex === i" ref="popover" :visible="popoverVisible[i]" width="400" :style="popoverStyles[i]" trigger="manual" > <div slot="reference" class="popover-content"> <div class="tooltip-top"> <h4>层位概况</h4> <i class="update-time">2024-11-28 09:46</i> </div> <ul> <li><p>层位</p><em class="percentage"><i style="color: #fff;">{{ removeAreaPrefix(cell.gridName) }}</i></em></li> <li><p>在架</p><em><i>15000</i>册</em></li> <li><p>错架</p><em><i>300</i>层</em> <em class="percentage">(2.00%)</em></li> <li><p>错序</p><em><i>0</i>层</em><em class="percentage">(0.00%)</em></li> </ul> </div> </el-popover> </li> </ul> </swiper-slide> </swiper> </div> </div> <div class="venue-right"> <div class="lib-right-item lib-info"> <h4>本架概况</h4> <ul class="data-right-list"> <li><p>书架</p><span><i>001排</i></span></li> <li><p>规则</p><span><i>双面 6 x 5</i></span></li> </ul> </div> <div class="lib-right-item"> <h4>本架盘点概况</h4> <div class="refresh-date">2024-11-28 09:46</div> <ul class="data-right-list"> <li><p>在架</p><span><i>15000</i>册</span></li> <li><p>错架</p><span><i>300</i>层</span> <span class="percentage">(2.00%)</span></li> <li><p>错序</p><span><i>0</i>层</span><span class="percentage">(0.00%)</span></li> </ul> </div> </div> </div>
<!-- form --> <el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title"> <span class="dialog-right-top" /> <span class="dialog-left-bottom" /> <div class="setting-dialog"> <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="80px"> <el-form-item label="盘点单号" prop="taskName"> <el-input v-model="form.taskName" /> </el-form-item> <el-form-item label="盘点类型" prop="taskType"> <el-input v-model="form.taskType" /> </el-form-item> <el-form-item label="目标位置" prop="location"> <el-input v-model="form.location" /> </el-form-item> <el-form-item label="目标数量" prop="number"> <el-input v-model="form.number" /> </el-form-item> <el-row> <el-form-item label="备注" prop="remark"> <el-input v-model="form.remark" type="textarea" style="width: 572px;" :rows="4" /> </el-form-item> </el-row> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="text" @click="crud.cancelCU">取消</el-button> <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">保存</el-button> </div> </div> </el-dialog> </div> </template>
<script> import { FetchInitShelfGridByShelfId, FetchBookShelfDetails } from '@/api/shelf/index' import crudRegion from '@/api/area/index' import CRUD, { presenter, header, form, crud } from '@crud/crud' import crudOperation from '@crud/CRUD.operation' import { mapGetters } from 'vuex' import { swiper, swiperSlide } from 'vue-awesome-swiper' import 'swiper/dist/css/swiper.css'
const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null } export default { name: 'DataScreening', components: { swiper, swiperSlide, crudOperation }, cruds() { return CRUD({ title: '架位总览', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: { add: false, edit: false, del: false, download: false, group: false, reset: false }, queryOnPresenterCreated: false }) }, mixins: [presenter(), header(), form(defaultForm), crud()], data() { const _this = this return { floorName: null, regionName: null, bookShelfDetails: null, booShelfGrid: null, cellInfo: { gridName: null, startSortmark: null, endSortmark: null, cameraId: null }, callNumVisible: false, layerNum: 0, rackNum: 0, swiperActiveIndex: 0, cellIndex: null, swiperOptionContent: { slidesPerView: 'auto', on: { slideChangeTransitionStart: function() { _this.cellIndex = null _this.swiperActiveIndex = this.activeIndex console.log('activeIndexffff', this.swiperActiveIndex) _this.swiperTitle.slideTo(this.activeIndex, 500, false) } } }, swiperOptionTitle: { slidesPerView: 'auto', freeMode: true }, layerVal: '001排', layerOptions: [{ id: 1, name: '001排' }], tabListData: [], permission: { add: ['admin', 'floor:add'], edit: ['admin', 'floor:edit'], del: ['admin', 'floor:del'] }, rules: { taskName: [ { required: true, message: '请输入盘点单号', trigger: 'blur' } ], taskType: [ { required: true, message: '请输入盘点类型', trigger: 'blur' } ], location: [ { required: true, message: '请输入目标位置', trigger: 'blur' } ], number: [ { required: true, message: '请输入目标数量', trigger: 'blur' } ] }, popoverIndex: 1, popoverVisible: [], popoverStyles: [] } }, computed: { ...mapGetters([ 'user', 'baseApi' ]), swiperContent() { return this.$refs.swiperContent.$el.swiper }, swiperTitle() { return this.$refs.swiperTitle.$el.swiper }, cellStyle: function() { // const h = '100%/' + this.layerNum
// const w = '100%/' + this.rackNum
const h = '70px' const w = '100%/' + this.rackNum return { width: `calc(${w} - 4px )`, height: `calc(${h} - 2px)` } } }, async created() { if (localStorage.getItem('dataScreenRegion')) { const dataScreenRegion = JSON.parse(localStorage.getItem('dataScreenRegion')) this.floorName = dataScreenRegion.floorName this.regionName = dataScreenRegion.regionName // 单面/双面
this.tabListData = dataScreenRegion.rowType === 1 ? dataScreenRegion.toward === 1 ? [{ name: 'A面' }] : [{ name: 'B面' }] : [{ name: 'A面' }, { name: 'B面' }]
FetchBookShelfDetails({ 'shelfId': dataScreenRegion.id }).then(res => { this.layerNum = res.shelfFloor this.rackNum = res.shelfShelf this.bookShelfDetails = res this.getInitShelfGridByShelfId(this.bookShelfDetails.toward) }).catch(() => { }) } }, methods: { handleToGrids() { this.$router.push({ path: '/dataScreening/gird', query: { }}) }, [CRUD.HOOK.beforeRefresh]() { }, [CRUD.HOOK.afterRefresh](crud) { }, // 提交前的验证
[CRUD.HOOK.afterValidateCU](crud) { return true }, removeAreaPrefix(gridNames) { const index = gridNames.indexOf('区') if (index !== -1) { return gridNames.substring(index + 1) } return gridNames }, getInitShelfGridByShelfId(toward) { // rowType 1 单 2 双
// toward 1 A面 2 B面
// shelfType 1 '始终最左边为第1架(S型排架)'
// shelfType 2 'A面最左为第1架(B面最左为最后1架)'
// shelfType 3 'B面最左为第1架(A面最左为最后1架)'
// floorType 1 '最顶层为第一层(从上至下)'
// floorType 2 '最底层为第一层(从下至上)'
FetchInitShelfGridByShelfId({ 'shelfId': this.bookShelfDetails.id, 'toward': toward }).then(res => { const sortFunction = toward === 1 ? { 1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, 2: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, 3: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' } } : { 1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }, 2: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' }, 3: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' } } const shelfType = this.bookShelfDetails.shelfType const floorType = this.bookShelfDetails.floorType const sortMethod = sortFunction[shelfType][floorType] this.booShelfGrid = this[sortMethod](res)
this.popoverVisible = Array(this.booShelfGrid.length).fill(false) // this.popoverStyles = new Array(this.booShelfGrid.length).fill({ position: 'absolute', left: '20%', top: '48px' })
}).catch(() => { }) }, // 最左为第一架, 最顶层为第一层 从上往下
sortBookshelvesLeftTop(data) { const sortedData = [] const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1))))
for (let i = 1; i <= maxFloor; i++) { for (let j = 1; j <= maxShelf; j++) { const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j) if (currentShelf) { sortedData.push(currentShelf) } } } return sortedData }, // 最右为第一架,最左为最后一架, 最顶层为第一层 从上往下
sortBookshelvesRightTop(data) { const sortedData = [] // 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0]))) for (let i = 1; i <= maxFloor; i++) { // 从最大的书架层数开始,向下排序
for (let j = maxShelf; j >= 1; j--) { const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j) if (currentShelf) { sortedData.push(currentShelf) } } } return sortedData }, // 最左为第一架, 最底层为第一层 从下往上
sortBookshelvesLeftBottom(data) { const sortedData = [] // 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) // 获取最大的书架层数
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1)))) for (let i = maxFloor; i >= 1; i--) { for (let j = 1; j <= maxShelf; j++) { const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j) if (currentShelf) { sortedData.push(currentShelf) } } } return sortedData }, // 最左为最后一架, 最底层为第一层 从下往上
sortBookshelvesRightBottom(data) { const sortedData = [] // 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor))) const maxShelfPerFloor = data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0])) .reduce((acc, curr, index, arr) => { const floor = parseInt(data[index].gridFloor) if (!acc[floor]) acc[floor] = 1 if (acc[floor] < curr) acc[floor] = curr return acc }, {}) // 从最大的楼层开始向下遍历
for (let i = maxFloor; i >= 1; i--) { // 从最大的书架编号开始向左遍历
for (let j = maxShelfPerFloor[i] || 1; j >= 1; j--) { const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j) if (currentShelf) { sortedData.push(currentShelf) } } } return sortedData }, handleSlidClickFun(index) { this.cellIndex = null this.handleSlideToFun(index) if (localStorage.getItem('bookShelfDetails')) { this.getInitShelfGridByShelfId(index + 1) } }, handleSlideToFun(index) { this.swiperActiveIndex = index this.swiperContent.slideTo(index, 500, false) this.swiperTitle.slideTo(index, 500, false) }, handleCellCurrent(item, index) { console.log('index', index) this.cellIndex = index this.cellInfo = { id: item.id, gridName: item.gridName, startSortmark: item.startSortmark, endSortmark: item.endSortmark, cameraId: item.cameraId, check: item.isCheck, order: item.isOrder } }, showPopover(index) { this.popoverIndex = index // 显示对应的 popover
if (!this.popoverVisible[index]) { this.$set(this.popoverVisible, index, true) }
const lastColumnIndexes = [] const secondLastColumnIndexes = []
for (let i = 0; i < this.booShelfGrid.length; i++) { // 计算当前数据项的列索引
const columnIndex = i % this.rackNum // 如果是最后一列(第5列)
if (columnIndex === this.rackNum - 1) { lastColumnIndexes.push(i) // 更新最后一列的样式
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-140px', top: '48px' }) } // 如果是倒数第二列(第4列)
if (columnIndex === this.rackNum - 2) { secondLastColumnIndexes.push(i) // 更新倒数第二列的样式
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '48px' }) } } }, hidePopover() { this.popoverIndex = null // 隐藏所有的popover
this.popoverVisible.forEach((isVisible, index) => { if (isVisible) { this.$set(this.popoverVisible, index, false) } }) } } } </script>
<style lang="scss" scoped> .container-right{ min-height: calc(100vh - 232px) !important; } .venue-content{ position: relative; }
.crud-opts{ position: absolute; right: 20px; top: 10px; } .venue-left{ flex: 1; margin-right: 0 !important; .venue-preview{ height: 633px !important; } } .venue-right{ display: flex; flex-direction: column; width: 400px; padding: 50px 10px 20px 10px !important; .lib-right-item{ position: relative; padding-bottom: 10px; margin-bottom: 10px; border: 1px solid #E8F2FF; border-radius: 4px; h4{ padding: 6px 10px; background-color: #E8F2FF; color: #000; line-height: 30px; border-bottom: 1px solid #edeff3; } .refresh-date{ position: absolute; right: 14px; top: 10px; font-size: 12px; line-height: 30px; } } }
.data-right-list { padding-top: 10px; li{ display: flex; justify-content: flex-start; align-items: center; line-height: 36px;
p{ width: 80px; font-weight: bold; text-align: right; } span{ width: 140px; display: block; text-align: right; i{ font-style: normal; font-weight: bold; padding: 0 10px; color: #0348f3; } &.percentage{ width: auto; } } } } .swiper-title{ ::v-deep .swiper-wrapper{ margin: 10px 0; border-bottom: 1px solid #EDEFF3; } } .swiper-slide-title { width: auto !important; margin-right: 20px; cursor: pointer; .tab-name { padding: 10px; &.active { color: #0348F3; border-bottom: 3px solid #0348F3; } } }
.swiper-content{ height: 610px; } .tag-info{ position: absolute; right: 20px; top: 34px; display: flex; justify-content: flex-start; padding-left: 100px; p{ margin-left: 20px; margin-top: -4px; font-size: 14px; } } .cabinet-row .cabinet-cell{ background: url('~@/assets/images/shelf02.png') repeat-x left top; background-size: 100% 100%; border: none; overflow: inherit; cursor: pointer; &::before{ content: ""; position: absolute; left: 0; top: 0; width: 6px; height: 68px; background: url('~@/assets/images/shelf01.png') no-repeat left top; background-size: 100% 100%; } &::after{ content: ""; position: absolute; right: -4px; top: 0; width: 6px; height: 68px; background: url('~@/assets/images/shelf01.png') no-repeat left top; background-size: 100% 100%; } span.cell-name{ position: initial !important; transform: none; line-height: 68px; } } ::v-deep .cabinet-row .cabinet-cell span.el-popover__reference-wrapper{ position: absolute !important; left: 50% !important; top: 20px !important; transform: none; width: 300px; height: 210px; background:rgba(0,0,0,.8); color: #fff; border-radius: 6px; z-index: 99999999;
.popover-content{ .tooltip-top{ display: flex; justify-content: space-between; align-items: center; height: 40px; line-height: 40px; padding: 0 10px; border-bottom: 1px solid #fff; } .tooltip-top i{ font-style: normal; font-size: 12px; } ul{ padding: 10px; } ul li{ display: flex; justify-content: flex-start; align-items: center; line-height: 36px; font-style: normal; }
ul li p{ width: 80px; font-weight: bold; text-align: right; } ul li em{ width: 100px; display: block; text-align: right; font-style: normal; } ul li i{ font-style: normal; font-weight: bold; padding: 0 10px; color: #0348f3; } ul li em.percentage{ width: auto; } } } </style>
|