|
|
<template> <div class="app-container"> <div class="venue-header dataScreening-header"> <h4 @click="handleToGrids"><i class="iconfont icon-shuju" />书架总览</h4> <div class="bookshelf-area"> <!-- <span> {{ floorName }} - {{ regionName }}</span> --> <router-link :to="{ path: '/check/check/dataScreening', query: {floorTabIndex: floorTabIndex }}"> {{ floorName }} </router-link> <span>-</span> <router-link :to="{ path: '/dataScreening/regions', query: {regionTabIndex: regionTabIndex }}"> {{ regionName }} </router-link> </div> <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" /> <ul class="tab-nav"> <li v-for="(item,index) in tabListData" :key="index" :class="{ 'active-tab-nav': tabIndex == index }" @click="changeActiveTab(index)">{{ item.name }}<i /></li> <!-- 最右侧装饰img --> <span class="tab-right-img" /> </ul> <div class="tag-info"> <p class="tag-sort">错序:<i class="iconfont icon-zhuangtai2" />1</p> <p class="tag-place">错架:<i class="iconfont icon-zhuangtai2" />1</p> <p class="tag-all">在架:<i class="iconfont icon-zhuangtai2" />20</p> </div> <!-- </div> --> <div class="shelf-top" :style="rowStyle"> <p v-for="(item,index) in reversedRackNum" :key="index" :style="{width: `calc(142px)`}"><span>{{ item + '架' }}</span></p> </div> <ul v-loading="listLoading" class="data-shelf-row" :style="rowStyle"> <!-- :class="{ active: i === cellIndex }" --> <li v-for="(cell,i) in booShelfGrid" :key="i" class="data-shelf-cell" :style="cellStyle" @dblclick="handleCellCurrent(cell,i)" @mouseenter="showPopover(i)" @mouseleave="hidePopover" > <!-- <span class="cell-name">{{ removeAreaPrefix(cell.gridName) }}</span> --> <div class="tag-info"> <p class="tag-sort"><i class="iconfont icon-zhuangtai2" />1</p> <p class="tag-place"><i class="iconfont icon-zhuangtai2" />1</p> <p class="tag-all"><i class="iconfont icon-zhuangtai2" />20</p> </div> <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> </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'
const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null } export default { name: 'DataScreening', components: { 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 { listLoading: false, tabIndex: 0, floorTabIndex: 0, regionTabIndex: 0, floorName: null, regionName: null, rowType: null, bookShelfDetails: null, booShelfGrid: [], 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: null, 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 = '76px'
// const w = '100%/' + this.rackNum
// return { width: `calc(${w} )`, height: `calc(${h})` }
// },
cellStyle: function() { const h = '76px' // const w = '100%/' + this.rackNum
const w = '146px' return { width: `calc(${w} )`, height: `calc(${h})` } }, rowStyle: function() { const w = 146 * this.rackNum + 'px' return { width: `calc(${w})` } }, reversedRackNum() { if (this.booShelfGrid && this.booShelfGrid.length > 0) { if (this.booShelfGrid[0].gridShelf === '07') { return Array.from({ length: this.rackNum }, (_, i) => this.rackNum - i).map(x => x.toString()) } else { return Array.from({ length: this.rackNum }, (_, i) => i + 1).map(x => x.toString()) } } else { console.log('fff') return [] } } }, async created() { if (localStorage.getItem('dataScreenFloorTableIndex')) { this.floorTabIndex = localStorage.getItem('dataScreenFloorTableIndex') } if (localStorage.getItem('dataScreenRegionTableIndex')) { this.regionTabIndex = localStorage.getItem('dataScreenRegionTableIndex') } if (localStorage.getItem('dataScreenRegion')) { const dataScreenRegion = JSON.parse(localStorage.getItem('dataScreenRegion')) this.floorName = dataScreenRegion.floorName this.regionName = dataScreenRegion.regionName this.rowType = dataScreenRegion.rowType // 单面/双面
this.tabListData = dataScreenRegion.rowType === 1 ? dataScreenRegion.toward === 1 ? [{ name: 'A面' }] : [{ name: 'B面' }] : [{ name: 'A面' }, { name: 'B面' }]
this.tabIndex = this.$route.query.tabIndex ? this.$route.query.tabIndex : 0
FetchBookShelfDetails({ 'shelfId': dataScreenRegion.id }).then(res => { this this.layerNum = res.shelfFloor this.rackNum = res.shelfShelf this.bookShelfDetails = res if (this.$route.query.tabIndex) { this.getInitShelfGridByShelfId(this.$route.query.tabIndex + 1) } else { this.getInitShelfGridByShelfId(this.bookShelfDetails.toward) } }).catch(() => { }) } }, methods: { [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) { this.listLoading = true // 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)
console.log(this.booShelfGrid[0].gridShelf)
this.popoverVisible = Array(this.booShelfGrid.length).fill(false) setTimeout(() => { this.listLoading = false }, 1000) }).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 }, changeActiveTab(index) { this.tabIndex = index this.cellIndex = null this.getInitShelfGridByShelfId(index + 1) }, handleCellCurrent(item, index) { console.log('index', index) console.log('item', item) this.cellIndex = index this.cellInfo = { id: item.id, gridName: item.gridName, gridRow: item.gridRow, gridShelf: item.gridShelf, shelfId: item.shelfId, floorName: this.floorName, regionName: this.regionName, rowType: this.rowType, toward: item.toward } this.handleToGrids(this.cellInfo) }, handleToGrids(data) { this.$router.push({ path: '/dataScreening/gird' }) localStorage.setItem('dataScreenShelf', JSON.stringify(data)) localStorage.setItem('dataScreenShelfTableIndex', this.tabIndex) }, showPopover(index) { this.popoverIndex = index 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: '0', top: '20px' })
} // 如果是倒数第二列(第4列)
if (columnIndex === this.rackNum - 2) { secondLastColumnIndexes.push(i) // 更新倒数第二列的样式
// this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '20px' })
} } }, 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; } } } } .tag-info{ position: absolute; right: 20px; top: 8px; p{ margin-left: 20px; } }
.shelf-top{ display: flex; justify-content: space-around; align-items: center; text-align: center; margin-top: 20px; p{ font-size: 14px; color: #fff; height: 36px; line-height: 30px; background: url('~@/assets/images/shelf04.png') no-repeat center top; background-size: auto 100%; } }
.data-shelf-row{ display: flex; flex: 1; flex-wrap: wrap; text-align: center; // margin-top: -2px;
// padding-top: 40px;
.data-shelf-cell{ position: relative; font-size: 14px; color: #0C0E1E; background: url('~@/assets/images/shelf02.png') repeat-x left top; background-size: 20% 100%; border-radius: 3px; cursor: pointer; .tag-info{ right: 12px; top: 44px; p{ margin-left: 10px; } } &::before{ content: ""; position: absolute; left: 0; top: 0; width: 6px; height: 76px; 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: 76px; background: url('~@/assets/images/shelf01.png') no-repeat left top; background-size: 100% 100%; } .cell-name{ display: block; width: 100%; line-height: 76px; } &.active{ color: #fff; background-color: #0348F3; } } }
::v-deep .data-shelf-row span.el-popover__reference-wrapper{ position: absolute !important; left: 60% !important; top: 48px !important; 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>
|