Browse Source

盘点

master
xuhuajiao 9 months ago
parent
commit
b4975c021d
  1. 37
      src/api/stockTask/index.js
  2. 14
      src/assets/iconfonts/light/iconfont.css
  3. 2
      src/assets/iconfonts/light/iconfont.js
  4. 14
      src/assets/iconfonts/light/iconfont.json
  5. BIN
      src/assets/iconfonts/light/iconfont.ttf
  6. BIN
      src/assets/iconfonts/light/iconfont.woff
  7. BIN
      src/assets/iconfonts/light/iconfont.woff2
  8. BIN
      src/assets/images/shelf01.png
  9. BIN
      src/assets/images/shelf02.png
  10. BIN
      src/assets/images/shelf03.png
  11. BIN
      src/assets/images/shelf04.png
  12. 36
      src/assets/styles/manage.scss
  13. 8
      src/utils/index.js
  14. 10
      src/views/visualCheck/checkManage/bookshelfSearch/index.vue
  15. 244
      src/views/visualCheck/checkManage/checkPlan/index.vue
  16. 852
      src/views/visualCheck/checkManage/dataScreening/girdList.vue
  17. 1
      src/views/visualCheck/checkManage/dataScreening/index.vue
  18. 3
      src/views/visualCheck/checkManage/dataScreening/regionsList.vue
  19. 686
      src/views/visualCheck/checkManage/dataScreening/shelfList copy.vue
  20. 316
      src/views/visualCheck/checkManage/dataScreening/shelfList.vue
  21. 149
      src/views/visualCheck/checkManage/upDownLog/index.vue
  22. 10
      src/views/visualCheck/venueDevice/bookshelfPosition/index.vue

37
src/api/stockTask/index.js

@ -0,0 +1,37 @@
import request from '@/utils/request'
// import qs from 'qs'
export function add(data) {
return request({
url: 'api/stocktask-task/editStockTask',
method: 'post',
data
})
}
export function edit(data) {
return request({
url: 'api/stocktask-task/editStockTask',
method: 'post',
data
})
}
export function del(ids) {
return request({
url: '',
method: 'post',
data: ids
})
}
// 修改盘点任务状态
export function FetchUpdateStockTaskStatus(data) {
return request({
url: 'api/stocktask-task/updateStockTaskStatus',
method: 'post',
data
})
}
export default { add, edit, del, FetchUpdateStockTaskStatus }

14
src/assets/iconfonts/light/iconfont.css

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 3966148 */ font-family: "iconfont"; /* Project id 3966148 */
src: url('iconfont.woff2?t=1735042074321') format('woff2'),
url('iconfont.woff?t=1735042074321') format('woff'),
url('iconfont.ttf?t=1735042074321') format('truetype');
src: url('iconfont.woff2?t=1735178700019') format('woff2'),
url('iconfont.woff?t=1735178700019') format('woff'),
url('iconfont.ttf?t=1735178700019') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-zhuangtai1:before {
content: "\e690";
}
.icon-zhuangtai2:before {
content: "\e6bc";
}
.icon-biaoqian:before { .icon-biaoqian:before {
content: "\e693"; content: "\e693";
} }

2
src/assets/iconfonts/light/iconfont.js
File diff suppressed because it is too large
View File

14
src/assets/iconfonts/light/iconfont.json

@ -5,6 +5,20 @@
"css_prefix_text": "icon-", "css_prefix_text": "icon-",
"description": "", "description": "",
"glyphs": [ "glyphs": [
{
"icon_id": "13446589",
"name": "状态",
"font_class": "zhuangtai1",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "18916458",
"name": "状态",
"font_class": "zhuangtai2",
"unicode": "e6bc",
"unicode_decimal": 59068
},
{ {
"icon_id": "4487893", "icon_id": "4487893",
"name": "标签", "name": "标签",

BIN
src/assets/iconfonts/light/iconfont.ttf

BIN
src/assets/iconfonts/light/iconfont.woff

BIN
src/assets/iconfonts/light/iconfont.woff2

BIN
src/assets/images/shelf01.png

After

Width: 32  |  Height: 441  |  Size: 1.4 KiB

BIN
src/assets/images/shelf02.png

After

Width: 368  |  Height: 441  |  Size: 62 KiB

BIN
src/assets/images/shelf03.png

After

Width: 48  |  Height: 192  |  Size: 2.1 KiB

BIN
src/assets/images/shelf04.png

After

Width: 256  |  Height: 256  |  Size: 3.0 KiB

36
src/assets/styles/manage.scss

@ -11,6 +11,7 @@
border-bottom: 1px solid #EDEFF3; border-bottom: 1px solid #EDEFF3;
h4{ h4{
font-size: 18px; font-size: 18px;
flex: 1;
i{ i{
font-size: 22px; font-size: 22px;
color: #0348F3; color: #0348F3;
@ -22,6 +23,11 @@
font-size: 18px; font-size: 18px;
} }
} }
.bookshelf-area{
padding-right: 30px;
font-weight: bold;
color: #0348F3;
}
} }
.venue-content{ .venue-content{
@ -350,4 +356,32 @@
.in-all, .in-part{ .in-all, .in-part{
background-color: #1AAE93; background-color: #1AAE93;
} }
}
}
.tag-info{
display: flex;
justify-content: flex-start;
align-items: center;
p{
font-size: 14px;
font-weight: bold;
}
}
.tag-sort{
i{
color: #0348F3;
}
}
.tag-place{
i{
color: #FF8329;
}
}
.tag-in{
i{
color: #2ECAAC;
}
}

8
src/utils/index.js

@ -478,3 +478,11 @@ export function saveByteArray(fileName, byte) {
link.download = fileName link.download = fileName
link.click() link.click()
} }
export function timeToTimestamp(time) {
const timestamp = Date.parse(new Date(time).toString())
// 在JavaScript中,new Date().getTime()得到的是13位的时间戳;
// 若要获取10位的时间戳需除以1000,获取13位的时间戳不需要除以1000;
// timestamp = timestamp / 1000
return timestamp
}

10
src/views/visualCheck/checkManage/bookshelfSearch/index.vue

@ -58,11 +58,11 @@
<el-table-column prop="deptsStatus" label="盘点概况" min-width="340"> <el-table-column prop="deptsStatus" label="盘点概况" min-width="340">
<!-- slot-scope="scope" --> <!-- slot-scope="scope" -->
<template> <template>
<ul class="tag-list">
<li class="blue-tag"><p>错序</p><span><em>1</em><i class="iconfont icon-biaoqian" /></span></li>
<li class="yellow-tag"><p>错架</p><span><em>2</em><i class="iconfont icon-biaoqian" /></span></li>
<li class="green-tag"><p>在架</p><span><em>33</em><i class="iconfont icon-biaoqian" /></span></li>
</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-in">在架<i class="iconfont icon-zhuangtai2" />20</p>
</div>
<!-- <span class="row-state row-binding state-active">在架</span> <!-- <span class="row-state row-binding state-active">在架</span>
<span class="row-state row-lending state-active">错架</span> <span class="row-state row-lending state-active">错架</span>
<span class="row-state row-physical state-active">错序</span> --> <span class="row-state row-physical state-active">错序</span> -->

244
src/views/visualCheck/checkManage/checkPlan/index.vue

@ -7,7 +7,7 @@
<i slot="prefix" class="iconfont icon-zhuangtai" /> <i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" /> <el-option v-for="item in enabledTypeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select> </el-select>
<el-input v-model="query.search" clearable size="small" placeholder="输入任务名称搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" />
<el-input v-model="query.taskName" clearable size="small" placeholder="输入任务名称搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" />
<rrOperation /> <rrOperation />
</div> </div>
<crudOperation :permission="permission"> <crudOperation :permission="permission">
@ -39,15 +39,28 @@
@row-dblclick="handleDbClick" @row-dblclick="handleDbClick"
> >
<el-table-column type="selection" align="center" width="55" /> <el-table-column type="selection" align="center" width="55" />
<el-table-column prop="regionName" label="任务名称" />
<el-table-column prop="regionCode" label="任务类型" />
<el-table-column prop="floorName" label="目标位置" />
<el-table-column prop="booksheflCount" label="计划" />
<el-table-column prop="booksheflCount" label="下次运行" />
<el-table-column prop="booksheflCount" label="最后运行" />
<el-table-column label="状态" align="center" prop="deptsStatus">
<el-table-column prop="taskName" label="任务名称" />
<el-table-column prop="taskType" label="任务类型" />
<el-table-column prop="regionName" label="目标位置" />
<el-table-column prop="timerType" label="计划">
<template slot-scope="scope"> <template slot-scope="scope">
<el-switch v-model="scope.row.deptsStatus" active-color="#409EFF" inactive-color="#F56C6C" :active-value="1" :inactive-value="0" @change="changeStatus(scope.row, scope.row.deptsStatus)" />
<div v-if="scope.row.timerType===1">{{ getWeekDays(scope.row.timeInterval) }}</div>
<div v-if="scope.row.timerType===2">单次</div>
</template>
</el-table-column>
<el-table-column prop="nextExecute" label="下次运行">
<template slot-scope="scope">
<div>{{ scope.row.nextExecute | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="lastExecute" label="最后运行">
<template slot-scope="scope">
<div>{{ scope.row.lastExecute | parseTime }}</div>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-color="#409EFF" inactive-color="#F56C6C" :active-value="1" :inactive-value="0" @change="changeStatus(scope.row, scope.row.status)" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -77,35 +90,36 @@
> >
<el-option <el-option
v-for="item in typeOptions" v-for="item in typeOptions"
:key="item.value"
:key="item.label"
:label="item.label" :label="item.label"
:value="item.value"
:value="item.label"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="目标位置" prop="deviceId">
<el-select
v-model="form.deviceId"
style="width: 240px; height:30px"
clearable
<el-form-item label="目标位置" prop="regionId">
<treeselect
v-model="form.regionId"
:options="regionOptions"
flat
:multiple="false"
placeholder="请选择" placeholder="请选择"
:normalizer="normalizer"
:default-expand-level="levelNumber"
style="width: 235px;"
@select="node=>treeSelectInput(node)"
> >
<el-option
v-for="item in deviceOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<div slot="value-label" slot-scope="{ node }">{{ getAutoNameUnknown(node.label) }}</div>
</treeselect>
</el-form-item> </el-form-item>
<el-form-item label="任务名称" prop="taskName"> <el-form-item label="任务名称" prop="taskName">
<el-input v-model="form.taskName" style="width: 588px;" /> <el-input v-model="form.taskName" style="width: 588px;" />
</el-form-item> </el-form-item>
<!-- v-if="form.deviceId === 'DDAF09DDD05ED8ACF9928E'" -->
<!-- v-if="form.regionId === 'DDAF09DDD05ED8ACF9928E'" -->
<el-row> <el-row>
<el-form-item label="说明" prop="remark">
<el-form-item label="说明" prop="explain">
<div style="display:inline-block; width: 588px; border: 1px solid #e6e8ed; background-color: #e6e8ed; border-radius: 4px; padding: 6px 10px; line-height: 24px;">盘点任务的目标已区域进行划分在指定的计划设定时间内对所选区域的所有层位进行图书盘点操作可以指定多个盘点任务注意不要指定重复的时间计划</div> <div style="display:inline-block; width: 588px; border: 1px solid #e6e8ed; background-color: #e6e8ed; border-radius: 4px; padding: 6px 10px; line-height: 24px;">盘点任务的目标已区域进行划分在指定的计划设定时间内对所选区域的所有层位进行图书盘点操作可以指定多个盘点任务注意不要指定重复的时间计划</div>
<!-- <el-input v-model="form.remark" type="textarea" style="width: 572px;" disabled :rows="4" /> -->
<!-- <el-input v-model="form.explain" type="textarea" style="width: 572px;" disabled :rows="4" /> -->
</el-form-item> </el-form-item>
</el-row> </el-row>
</div> </div>
@ -128,23 +142,11 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</div> </div>
<!-- <el-form-item v-if="form.timerType===1 || form.timerType===2" label="间隔" prop="timeInterval">
<div>
<el-input-number v-model="form.timeInterval" controls-position="right" :min="1" />
<span v-if="form.timerType===1" class="unit-name">小时</span>
<span v-if="form.timerType===2" class="unit-name"></span>
</div>
</el-form-item> -->
<el-form-item v-if="form.timerType===3" label="" prop="weekly">
<el-form-item v-if="form.timerType===1" label="" prop="weekly">
<el-checkbox-group v-model="form.weekly" style="margin-left: 80px; width: 558px;" @change="handleWeeklyTypes"> <el-checkbox-group v-model="form.weekly" style="margin-left: 80px; width: 558px;" @change="handleWeeklyTypes">
<el-checkbox v-for="item in weeklyOptions" :key="item.value" :label="item.value">{{ item.label }}</el-checkbox> <el-checkbox v-for="item in weeklyOptions" :key="item.value" :label="item.value">{{ item.label }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<!-- <el-form-item v-if="form.timerType===4" label="" prop="halfOrPart">
<el-checkbox-group v-if="form.timerType===4" v-model="form.halfOrPart" style="margin-left: 80px;">
<el-checkbox v-for="item in halfOrPartOptions" :key="item.value" :label="item.value">{{ item.label }}</el-checkbox>
</el-checkbox-group>
</el-form-item> -->
<div> <div>
<el-form-item label="开始时间" prop="startTime2"> <el-form-item label="开始时间" prop="startTime2">
<el-date-picker <el-date-picker
@ -227,22 +229,24 @@
</template> </template>
<script> <script>
import crudRegion from '@/api/area/index'
import crudStocktask from '@/api/stockTask/index'
import { FetchRegionTree } from '@/api/deviceVI/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation' import crudOperation from '@crud/CRUD.operation'
import rrOperation from '@crud/RR.operation' import rrOperation from '@crud/RR.operation'
import pagination from '@crud/Pagination' import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { parseTime, timeToTimestamp } from '@/utils/index.js'
// import { exportFile } from '@/utils/index'
// import qs from 'qs'
import { parseTime, saveAs, getBlob, timeToTimestamp } from '@/utils/index'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import qs from 'qs'
const defaultForm = { id: null, taskType: null, deviceId: null, weekly: [], taskName: null, timerType: 2, timeInterval: 1, status: 1, startTime2: parseTime(new Date().getTime()), endTime2: null, nowTime: null, longTime: true, remark: null, halfOrPart: [] }
const defaultForm = { id: null, taskType: null, regionId: null, weekly: [], taskName: null, timerType: 2, timeInterval: null, startTime2: parseTime(new Date().getTime()), endTime2: null, nowTime: null, longTime: true, explain: null }
export default { export default {
name: 'CheckPlan', name: 'CheckPlan',
components: { crudOperation, rrOperation, pagination },
components: { crudOperation, rrOperation, pagination, Treeselect },
cruds() { cruds() {
return CRUD({ title: '盘点任务', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
return CRUD({ title: '盘点任务', url: 'api/stocktask-task/initStockTaskList', crudMethod: { ...crudStocktask }, sort: [], optShow: {
add: true, add: true,
edit: true, edit: true,
del: false, del: false,
@ -254,13 +258,14 @@ export default {
mixins: [presenter(), header(), form(defaultForm), crud()], mixins: [presenter(), header(), form(defaultForm), crud()],
data() { data() {
return { return {
levelNumber: 4,
enabledTypeOptions: [ enabledTypeOptions: [
{ key: '1', display_name: '激活' },
{ key: '0', display_name: '锁定' }
{ key: 1, display_name: '激活' },
{ key: 0, display_name: '锁定' }
], ],
detailVisible: false, detailVisible: false,
detailTable: [], detailTable: [],
floorOptions: [],
regionOptions: [],
tabIndex: 0, tabIndex: 0,
permission: { permission: {
add: ['admin', 'checkTask:add'], add: ['admin', 'checkTask:add'],
@ -275,22 +280,14 @@ export default {
], ],
deviceOptions: [], deviceOptions: [],
timeTypeOptions: [ timeTypeOptions: [
// {
// label: '',
// value: 1
// },
{ {
label: '单次',
value: 2
label: '周循环',
value: 1
}, },
{ {
label: '周循环',
value: 3
label: '单次',
value: 2
} }
// {
// label: '/',
// value: 4
// }
], ],
weeklyOptions: [ weeklyOptions: [
{ {
@ -339,7 +336,7 @@ export default {
taskType: [ taskType: [
{ required: true, message: '请选择', trigger: 'change' } { required: true, message: '请选择', trigger: 'change' }
], ],
deviceId: [
regionId: [
{ required: true, message: '请选择', trigger: 'change' } { required: true, message: '请选择', trigger: 'change' }
], ],
timerType: [ timerType: [
@ -390,18 +387,79 @@ export default {
]) ])
}, },
methods: { methods: {
getWeekDays(timeInterval) {
const daysOfWeek = {
'1': '周一',
'2': '周二',
'3': '周三',
'4': '周四',
'5': '周五',
'6': '周六',
'7': '周日'
}
const days = timeInterval.split(',').map(num => daysOfWeek[num.trim()])
return days.join(' ')
},
getAutoNameUnknown(name) {
if (name.lastIndexOf('unknown') > -1) {
return name.split('(')[0]
} else {
return name
}
},
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.id,
label: node.label,
children: node.children,
isDisabled: !node.regionId
}
},
// tree
transformData(data) {
return {
id: data.fondsId,
fondsId: data.fondsId,
label: data.fondsName,
children: data.floors.map(floor => ({
id: floor.id,
floorId: floor.id,
label: floor.floorName,
children: floor.regions.map(region => ({
id: region.id,
regionId: region.id,
label: region.regionName,
parentFloorId: floor.id
}))
}))
}
},
[CRUD.HOOK.beforeRefresh]() { [CRUD.HOOK.beforeRefresh]() {
}, },
[CRUD.HOOK.afterRefresh](crud) { [CRUD.HOOK.afterRefresh](crud) {
}, },
//
[CRUD.HOOK.afterToCU](crud, form) {
FetchRegionTree().then(res => {
this.regionOptions = [this.transformData(res)]
}).catch(() => {
})
},
// //
[CRUD.HOOK.beforeToAdd]() { [CRUD.HOOK.beforeToAdd]() {
this.form.startTime2 = parseTime(new Date().getTime()) this.form.startTime2 = parseTime(new Date().getTime())
}, //
}, //
[CRUD.HOOK.beforeToEdit](crud, form) { [CRUD.HOOK.beforeToEdit](crud, form) {
// if (form.timerType === 4 && form.timeInterval) {
// form.halfOrPart = form.timeInterval.split(',').map(Number)
// }
if (form.timeInterval !== null) {
this.form.weekly = form.timeInterval.split(',').map(item => {
return parseInt(item)
})
console.log('this.form.weekly', this.form.weekly)
}
if (form.startTime) { if (form.startTime) {
this.form.startTime2 = parseTime(form.startTime) this.form.startTime2 = parseTime(form.startTime)
} }
@ -414,7 +472,7 @@ export default {
} }
}, },
[CRUD.HOOK.beforeValidateCU](crud, form) { [CRUD.HOOK.beforeValidateCU](crud, form) {
if (this.form.taskType === null || this.form.deviceId === null || this.form.name === null) {
if (this.form.taskType === null || this.form.regionId === null || this.form.name === null) {
this.$message.error('请制定完善 “ 任务设定 ” ') this.$message.error('请制定完善 “ 任务设定 ” ')
} }
}, },
@ -430,17 +488,28 @@ export default {
} else { } else {
this.form.endTime = null this.form.endTime = null
} }
// if (this.form.timerType === 4 && this.form.halfOrPart) {
// this.form.timeInterval = this.form.halfOrPart.join(',')
// }
delete crud.form.remark
if (this.form.timerType === 2) {
this.form.timeInterval = null
} else {
const sortWeekly = this.form.weekly.sort((a, b) => a - b)
this.form.timeInterval = sortWeekly.join(',')
}
delete crud.form.longTime delete crud.form.longTime
delete crud.form.startTime2 delete crud.form.startTime2
delete crud.form.endTime2 delete crud.form.endTime2
delete crud.form.nowTime delete crud.form.nowTime
delete crud.form.halfOrPart
delete crud.form.lastExecute
delete crud.form.nextExecute
delete crud.form.plan
delete crud.form.status
delete crud.form.weekly
console.log('curd.form', crud.form)
return true return true
}, },
treeSelectInput(value) {
console.log(value)
},
changeFormTab(index) { changeFormTab(index) {
this.tabIndex = index this.tabIndex = index
}, },
@ -470,15 +539,12 @@ export default {
// return true // return true
// }, // },
handleTaskType(val) { handleTaskType(val) {
this.form.deviceId = null
this.form.regionId = null
}, },
handleTimerType(val) { handleTimerType(val) {
// if (val === 4) {
// this.form.timeInterval = null
// this.form.halfOrPart = [1]
// } else {
// this.form.timeInterval = 1
// }
if (val === 2) {
this.form.timeInterval = null
}
}, },
changeFloorValue(value) { changeFloorValue(value) {
console.log(value) console.log(value)
@ -515,22 +581,21 @@ export default {
}, },
// //
changeStatus(data, val) { changeStatus(data, val) {
data.id = data.deptsId
this.$confirm('此操作将禁用 / 启用当前任务' + '<span>你是否还要继续?</span>', '提示', { this.$confirm('此操作将禁用 / 启用当前任务' + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续', confirmButtonText: '继续',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning',
dangerouslyUseHTMLString: true dangerouslyUseHTMLString: true
}).then(() => { }).then(() => {
// crudDept.FetchUpdateDeptsStatus(data).then(res => {
// crudStocktask.FetchUpdateStockTaskStatus(data).then(res => {
// this.$message({ message: '', type: 'success', offset: 8 }) // this.$message({ message: '', type: 'success', offset: 8 })
// this.crud.refresh() // this.crud.refresh()
// }).catch(() => { // }).catch(() => {
// data.deptsStatus = !data.deptsStatus
// data.status = !data.status
// }) // })
}).catch(() => { }).catch(() => {
this.$message({ message: '已取消修改', offset: 8 }) this.$message({ message: '已取消修改', offset: 8 })
data.deptsStatus = data.deptsStatus ? 0 : 1
data.status = data.status ? 0 : 1
}) })
}, },
doExport(data) { doExport(data) {
@ -544,15 +609,18 @@ export default {
}).then(() => { }).then(() => {
const ids = [] const ids = []
data.forEach(val => { data.forEach(val => {
ids.push(val.deptsId)
ids.push(val.id)
}) })
const params = { const params = {
'deptsIds': ids
'taskIds': ids
} }
console.log(params)
// exportFile(this.baseApi + '/api/depts/download?' + qs.stringify(params, { indices: false }))
// this.crud.downloadLoading = false
const fileName = '盘点任务-' + parseTime(new Date()) + '.xlsx'
getBlob(this.baseApi + '/api/stocktask-task/exportStockTask' + '?' + qs.stringify(params, { indices: false }), function(blob) {
saveAs(blob, fileName)
this.crud.downloadLoading = false
})
}).catch(() => { }).catch(() => {
this.crud.downloadLoading = false
}) })
}, },
changeActiveTab(index) { changeActiveTab(index) {

852
src/views/visualCheck/checkManage/dataScreening/girdList.vue

@ -1,121 +1,251 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<div class="venue-header"> <div class="venue-header">
<h4><i class="iconfont icon-shuju" />架位总览</h4>
<h4 @click="handleToGrids"><i class="iconfont icon-shuju" />架位总览</h4>
<span class="bookshelf-area">{{ floorName }} - {{ regionName }} - {{ gridRow +'排' }}</span>
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
</div> </div>
<div class="venue-content"> <div class="venue-content">
<crudOperation :permission="permission">
<template v-slot:middle>
<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 class="tab-content">
<span class="right-top-line" />
<span class="left-bottom-line" />
<div class="gird-data-header">
<ul class="tab-nav"> <ul class="tab-nav">
<li v-for="(item,index) in floorOptions" :key="index" :class="{ 'active-tab-nav': tabIndex == index }" @click="changeActiveTab(index)">{{ item.floorName }}<i /></li>
<li v-for="(item,index) in tabListData" :key="index" :class="{ 'active-tab-nav': tabIndex == index }" @click="changeActiveTab(index)">{{ item.name }}<i /></li>
<!-- 最右侧装饰img --> <!-- 最右侧装饰img -->
<span class="tab-right-img" /> <span class="tab-right-img" />
</ul> </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-in">在架<i class="iconfont icon-zhuangtai2" />20</p>
</div>
<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 rackOptions" :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> </div>
</div>
<div class="venue-right" />
<!-- 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 class="gird-data-book">
<div v-for="(item,index) in layerNum" :key="index" class="gird-layer">
<span class="gird-left-line" />
<span class="gird-right-line" />
<div class="layer-left">
<div class="layer-left-book">
<div
v-for="(book,i) in bookNum"
:key="i"
class="book-item"
@mouseenter="showPopover(index, i, $event)"
@mouseleave="hidePopover"
>
<span class="book-name">{{ i+1 }}水浒传水浒传水浒传水浒传</span>
</div>
</div>
</div>
<div class="layer-right-handle">
<div class="layer-info-header">
<h4>001排A面01架1层</h4>
<span>2024-11-28 09:46</span>
</div>
<div class="layer-right-content">
<div class="layer-tag-info">
<div class="tag-item tag-sort">错序<i class="iconfont icon-zhuangtai2" /><p>1</p><span>5.00%</span></div>
<div class="tag-item tag-place">错架<i class="iconfont icon-zhuangtai2" /><p>1</p><span>5.00%</span></div>
<div class="tag-item tag-in">在架<i class="iconfont icon-zhuangtai2" /><p>20</p></div>
</div>
<div class="layer-handle">
<el-button size="mini" @click="handleDetail">
<i class="iconfont icon-xiaowenjian" />
详情
</el-button>
<el-button size="mini">
<i class="iconfont icon-shengchengpandiandan" />
盘点
</el-button>
</div>
</div>
</div>
</div>
<div
v-if="popoverIndex !== null"
class="popover-external"
:style="popoverStyle"
>
<div 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;">{{ currentBookName }}</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>
</div> </div>
</div> </div>
</el-dialog>
</div>
</div> </div>
</div></template>
<!-- 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>
<!-- 详情 -->
<el-dialog class="dialog-grid-detail" append-to-body :close-on-click-modal="false" :visible.sync="detailVisible" title="001排A面01架1层 - 详情" @close="handleCloseDialog">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">
<div class="detail-tab tab-content">
<el-button class="check-view-img" size="mini" @click="handleViewImg">
<i class="iconfont icon-sulan" />
盘点照片
</el-button>
<ul class="tab-nav">
<li :class="{'active-tab-nav': tabdialogIndex === 0}" @click="changeDialogTab(0)">图书列表</li>
</ul>
<el-table
ref="table"
class="archives-table"
:data="detailTable"
style="width: 100%;"
>
<el-table-column type="index" label="序号" width="55" align="center" />
<el-table-column prop="regionCode" label="题名" />
<el-table-column prop="floorName" label="ISBN" />
<el-table-column prop="booksheflCount" label="索书号" />
<el-table-column prop="booksheflCount" label="条码" />
<el-table-column prop="booksheflCount" label="应在位置" />
<el-table-column prop="booksheflCount" label="盘点位置" />
<el-table-column prop="booksheflCount" label="盘点结果">
<template>
<span class="row-state row-warehousing state-active">错架</span>
<!-- <span class="row-state row-binding state-active">在架</span>
<span class="row-state row-physical state-active">错序</span> -->
</template>
</el-table-column>
<el-table-column prop="createTime" label="完成时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
</el-dialog>
<el-dialog class="gird-img-detail" append-to-body :close-on-click-modal="false" :visible.sync="detailImgVisible">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="gird-img-button">
<el-button size="mini">
<i class="iconfont icon-xiazai" />
下载
</el-button>
<el-button size="mini" @click="handleCloseImgDialog">
<i class="iconfont icon-guanbixiao" />
关闭
</el-button>
</div>
<div class="setting-dialog">
<el-carousel indicator-position="outside">
<el-carousel-item v-for="item in 4" :key="item">
<img src="~@/assets/images/system/default-img.jpg" alt="">
</el-carousel-item>
</el-carousel>
</div>
</el-dialog>
</div>
</template>
<script> <script>
import { FetchLibraryFloorListAll } from '@/api/floor/index'
import { FetchInitLibraryRegionList } from '@/api/area/index'
import { FetchBookShelfDetails } from '@/api/shelf/index'
import crudRegion from '@/api/area/index' import crudRegion from '@/api/area/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation' import crudOperation from '@crud/CRUD.operation'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import defaultImg from '@/assets/images/system/default-img.jpg'
const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null } const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null }
export default { export default {
name: 'DataScreening', name: 'DataScreening',
components: { crudOperation }, components: { crudOperation },
cruds() { cruds() {
return CRUD({ title: '数据总览', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
return CRUD({ title: '架位盘点', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
add: false, add: false,
edit: false, edit: false,
del: false, del: false,
download: false, download: false,
group: false, group: false,
reset: false reset: false
}})
},
queryOnPresenterCreated: false
})
}, },
mixins: [presenter(), header(), form(defaultForm), crud()], mixins: [presenter(), header(), form(defaultForm), crud()],
data() { data() {
const _this = this
return { return {
floorOptions: [],
detailVisible: false,
detailImgVisible: false,
detailTable: [{}],
tabdialogIndex: 0,
listLoading: false,
tabIndex: 0, tabIndex: 0,
defaultImg: defaultImg,
imageUrl: defaultImg,
imageRegionUrl: defaultImg,
currentMarkData: null,
allCoverData: [],
swiperActiveIndex: 0,
rightDataIndex: null,
swiperOptionContent: {
slidesPerView: 'auto',
on: {
slideChangeTransitionStart: function() {
_this.rightDataIndex = null
_this.swiperActiveIndex = this.activeIndex
_this.swiperTitle.slideTo(this.activeIndex, 500, false)
}
}
},
swiperOptionTitle: {
slidesPerView: 'auto',
freeMode: true
},
tabListData: [{ name: '热门图书' }, { name: '热门架位' }, { name: '冷面图书' }],
floorName: null,
regionName: null,
gridRow: null,
bookShelfDetails: null,
booShelfGrid: null,
layerNum: 0,
rackNum: 0,
bookNum: 55,
layerVal: '01架',
rackOptions: [],
tabListData: [],
permission: { permission: {
add: ['admin', 'floor:add'], add: ['admin', 'floor:add'],
edit: ['admin', 'floor:edit'], edit: ['admin', 'floor:edit'],
@ -134,7 +264,12 @@ export default {
number: [ number: [
{ required: true, message: '请输入目标数量', trigger: 'blur' } { required: true, message: '请输入目标数量', trigger: 'blur' }
] ]
}
},
popoverIndex: null,
popoverVisible: [],
popoverStyles: [],
currentBookName: '', //
popoverPosition: { x: 0, y: 0 } // Popover
} }
}, },
computed: { computed: {
@ -144,11 +279,52 @@ export default {
]), ]),
swiperContent() { swiperContent() {
return this.$refs.swiperContent.$el.swiper return this.$refs.swiperContent.$el.swiper
},
swiperTitle() {
return this.$refs.swiperTitle.$el.swiper
},
cellStyle: function() {
const h = '76px'
const w = '100%/' + this.rackNum
return { width: `calc(${w} )`, height: `calc(${h})` }
},
popoverStyle() {
return {
top: `${this.popoverPosition.y}px`, // Y10px
left: `${this.popoverPosition.x}px`, // X10px
position: 'absolute'
}
}
},
async created() {
if (localStorage.getItem('dataScreenShelf')) {
const dataScreenShelf = JSON.parse(localStorage.getItem('dataScreenShelf'))
this.floorName = dataScreenShelf.floorName
this.regionName = dataScreenShelf.regionName
this.gridRow = dataScreenShelf.gridRow
// /
this.tabListData = dataScreenShelf.rowType === 1
? dataScreenShelf.toward === 1
? [{ name: 'A面' }]
: [{ name: 'B面' }]
: [{ name: 'A面' }, { name: 'B面' }]
FetchBookShelfDetails({ 'shelfId': dataScreenShelf.shelfId }).then(res => {
this
this.layerNum = res.shelfFloor
this.rackNum = res.shelfShelf
this.bookShelfDetails = res
this.rackOptions = []
for (let i = 1; i <= this.rackNum; i++) {
this.rackOptions.push({ id: i, name: `${i}` })
}
}).catch(() => {
})
} }
}, },
methods: { methods: {
[CRUD.HOOK.beforeRefresh]() { [CRUD.HOOK.beforeRefresh]() {
this.getLibraryFloorListAll()
}, },
[CRUD.HOOK.afterRefresh](crud) { [CRUD.HOOK.afterRefresh](crud) {
}, },
@ -156,138 +332,460 @@ export default {
[CRUD.HOOK.afterValidateCU](crud) { [CRUD.HOOK.afterValidateCU](crud) {
return true return true
}, },
//
getLibraryFloorListAll() {
FetchLibraryFloorListAll().then(res => {
this.floorOptions = res
this.changeActiveTab(this.tabIndex)
}).catch(() => {
})
},
changeActiveTab(index) {
this.tabIndex = index
const params = {
'floorId': this.floorOptions[index].id
removeAreaPrefix(gridNames) {
const index = gridNames.indexOf('区')
if (index !== -1) {
return gridNames.substring(index + 1)
} }
FetchInitLibraryRegionList(params).then(res => {
console.log(res)
this.allCoverData = res.content
return gridNames
},
getInitShelfGridByShelfId(toward) {
this.listLoading = true
// rowType 1 2
// toward 1 A 2 B
// shelfType 1 '1S'
// shelfType 2 'A1B1'
// shelfType 3 'B1A1'
// 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)
if (this.allCoverData.length !== 0) {
this.currentMarkData = this.allCoverData[0]
if (this.allCoverData[0].floorMap) {
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + this.allCoverData[0].floorMap
} else {
this.imageUrl = this.defaultImg
// 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)
} }
if (this.tabIndex === 0) {
if (this.allCoverData[0].signPoint) {
const drawinfo = JSON.parse(this.allCoverData[0].signPoint)
this.$nextTick(() => {
this.$refs.previewRefs.initCanvasPreview(drawinfo)
})
}
}
}
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)
} }
} else {
this.currentMarkData = {}
if (this.floorOptions[index].floorMap) {
this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + this.floorOptions[index].floorMap
} else {
this.imageUrl = this.defaultImg
}
}
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)
} }
} }
}).catch(() => {
})
}
return sortedData
}, },
handleSlidClickFun(index) {
this.rightDataIndex = null
this.handleSlideToFun(index)
changeActiveTab(index) {
this.tabIndex = index
this.cellIndex = null
this.getInitShelfGridByShelfId(index + 1)
},
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
}
this.handleToGrids(this.cellInfo)
},
handleDetail() {
this.detailVisible = true
},
handleViewImg() {
this.detailImgVisible = true
},
handleCloseDialog() {
this.detailVisible = false
},
handleCloseImgDialog() {
this.detailImgVisible = false
},
handleToGrids(data) {
this.$router.push({ path: '/dataScreening/gird' })
localStorage.setItem('dataScreenShelf', JSON.stringify(data))
},
showPopover(layerIndex, bookIndex, event) {
this.popoverIndex = { layer: layerIndex, book: bookIndex }
const bookElement = event.target //
const rect = bookElement.getBoundingClientRect() //
this.currentBookName = `水浒传${bookIndex + 1}` //
this.popoverPosition = {
// Popover使
x: window.scrollX + rect.left + rect.width / 2,
y: window.scrollY + rect.top + rect.height
}
console.log('this.popoverPosition ', this.popoverPosition)
}, },
handleSlideToFun(index) {
this.swiperActiveIndex = index
this.swiperContent.slideTo(index, 500, false)
this.swiperTitle.slideTo(index, 500, false)
hidePopover() {
this.popoverIndex = null
// popover
// this.popoverVisible.forEach((isVisible, index) => {
// if (isVisible) {
// this.$set(this.popoverVisible, index, false)
// }
// })
},
changeDialogTab(index) {
this.tabdialogIndex = index
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.container-right{
.venue-content{
position: relative;
padding: 20px;
background-color: #fff;
}
.tab-content{
width: 100%;
min-height: calc(100vh - 232px) !important; min-height: calc(100vh - 232px) !important;
.tab-nav{
flex: 1;
}
} }
.venue-content{
.gird-data-header{
display: flex;
justify-content: space-between;
}
.tag-info{
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 20px;
p{
margin-left: 20px;
font-size: 14px;
font-weight: bold;
}
}
.tag-sort{
i{
color: #0348F3;
}
}
.tag-place{
i{
color: #FF8329;
}
}
.tag-in{
i{
color: #2ECAAC;
}
}
.gird-data-book{
position: relative; position: relative;
height: 649px;
margin-top: 6px;
overflow: hidden;
overflow-y: scroll;
} }
.crud-opts{
position: absolute;
right: 20px;
top: 10px;
.gird-layer{
position: relative;
display: flex;
justify-content: space-between;
.gird-left-line{
position: absolute;
left: 0;
top: 0;
display: block;
width: 6px;
height: 130px;
background: url('~@/assets/images/shelf01.png') no-repeat left top;
background-size: 100% 100%;
z-index: 999;
}
.gird-right-line{
position: absolute;
right: calc(298px);
top: 0;
display: block;
width: 6px;
height: 130px;
background: url('~@/assets/images/shelf01.png') no-repeat left top;
background-size: 100% 100%;
z-index: 999;
}
.layer-left{
width: calc(100% - 240px);
height: 130px;
margin-right: 5px;
padding: 0 12px;
background: url('~@/assets/images/shelf02.png') repeat left top;
background-size: 10% 100%;
overflow: hidden;
overflow-x: scroll;
}
.layer-left-book{
// width: calc(100vw - 655px);
height: 130px;
white-space: nowrap;
.book-item{
position: relative;
display: inline-block;
width: 24px;
height: 100px;
margin-top: 18px;
background: url('~@/assets/images/shelf03.png') no-repeat left top;
background-size: 100% 100%;
cursor: pointer;
span.book-name{
position: absolute;
left: 0;
top: 14px;
display: block;
height: 90px;
writing-mode:vertical-rl;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
}
} }
.venue-left{
flex: 1;
margin-right: 0 !important;
.venue-preview{
height: 633px !important;
.layer-right-handle{
width: 300px;
padding: 0 10px;
background-color: #E8F2FF;
margin: 3px 5px;
border-radius: 6px;
}
.layer-info-header{
display: flex;
justify-content: space-between;
align-items: center;
line-height: 30px;
h4{
color: #0c0e1e;
}
span{
font-size: 12px;
} }
} }
.venue-right{
.layer-right-content{
display: flex;
justify-content: space-between;
}
.layer-tag-info{
div.tag-item {
display: flex;
justify-content: flex-start;
line-height: 26px;
font-size: 14px;
}
}
.layer-handle{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 400px;
padding: 50px 10px 20px 10px !important;
.lib-right-item{
position: relative;
// padding: 10px;
// height: calc(100% / 3);
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;
.el-button{
margin-left: 0 !important;
margin-bottom: 10px
}
}
.dialog-grid-detail{
::v-deep .el-dialog{
width: 936px !important;
.el-dialog__body{
padding: 0 !important;
} }
} }
.detail-tab{
position: relative;
}
.check-view-img{
position: absolute;
right: 0;
top: -10px;
}
} }
.data-right-list {
padding-top: 10px;
li{
.gird-img-detail{
::v-deep .el-dialog{
width: 1200px !important;
padding: 0 !important;
background: none;
// overflow: hidden;
box-shadow: none;
.el-dialog__header{
display: none;
}
.el-dialog__body{
padding: 0 !important;
}
}
::v-deep .el-carousel__container{
height: 700px !important;
.el-carousel__item img{
display: block;
width: 100%;
height: 100%;
}
}
.gird-img-button{
position: fixed;
right: -200px;
top: -60px;
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
line-height: 36px;
z-index: 9999999;
.el-button{
background-color: #e8f2ff;
}
}
}
::v-deep .book-item 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-external {
position: fixed; /* 固定定位,确保popover不受overflow:hidden影响 */
z-index: 1000; /* 确保popover在最上层 */
width: 300px;
height: 210px;
background:rgba(0,0,0,.8);
color: #fff;
border-radius: 6px;
}
.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;
}
p{
ul li p{
width: 80px; width: 80px;
font-weight: bold; font-weight: bold;
text-align: right; text-align: right;
} }
span{
width: 140px;
ul li em{
width: 100px;
display: block; display: block;
text-align: right; text-align: right;
i{
font-style: normal;
font-weight: bold;
padding: 0 10px;
color: #0348f3;
}
&.percentage{
width: auto;
}
font-style: normal;
}
ul li i{
font-style: normal;
font-weight: bold;
padding: 0 10px;
color: #0348f3;
}
ul li em.percentage{
width: auto;
} }
} }
}
</style> </style>

1
src/views/visualCheck/checkManage/dataScreening/index.vue

@ -211,6 +211,7 @@ export default {
return { return {
id: item.id, id: item.id,
name: item.regionName, name: item.regionName,
floorName: item.floorName,
floorId: item.floorId, floorId: item.floorId,
pointInfo: signPoint.pointInfo[0].pointInfo pointInfo: signPoint.pointInfo[0].pointInfo
} }

3
src/views/visualCheck/checkManage/dataScreening/regionsList.vue

@ -2,6 +2,7 @@
<div class="app-container"> <div class="app-container">
<div class="venue-header"> <div class="venue-header">
<h4 @click="handleToShelfs"><i class="iconfont icon-shuju" />区域总览</h4> <h4 @click="handleToShelfs"><i class="iconfont icon-shuju" />区域总览</h4>
<span class="bookshelf-area">{{ floorName }} </span>
<p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p> <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
</div> </div>
<div class="venue-content"> <div class="venue-content">
@ -119,6 +120,7 @@ export default {
const _this = this const _this = this
return { return {
regionOptions: [], regionOptions: [],
floorName: null,
currentRegionId: null, currentRegionId: null,
tabIndex: 0, tabIndex: 0,
defaultImg: defaultImg, defaultImg: defaultImg,
@ -186,6 +188,7 @@ export default {
this.regionOptions = crud.data this.regionOptions = crud.data
const item = this.regionOptions.find(element => element.id === this.currentRegionId) const item = this.regionOptions.find(element => element.id === this.currentRegionId)
const index = item ? this.regionOptions.indexOf(item) : -1 const index = item ? this.regionOptions.indexOf(item) : -1
this.floorName = this.regionOptions[index].floorName
this.tabIndex = index this.tabIndex = index
this.changeActiveTab(index) this.changeActiveTab(index)
}, },

686
src/views/visualCheck/checkManage/dataScreening/shelfList copy.vue

@ -0,0 +1,686 @@
<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 '1S'
// shelfType 2 'A1B1'
// shelfType 3 'B1A1'
// 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>

316
src/views/visualCheck/checkManage/dataScreening/shelfList.vue

@ -27,92 +27,60 @@
<div class="container-right tab-content"> <div class="container-right tab-content">
<span class="right-top-line" /> <span class="right-top-line" />
<span class="left-bottom-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>
<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"> <div class="tag-info">
<p>错序1</p>
<p>错架1</p>
<p>在架20</p>
<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-in">在架<i class="iconfont icon-zhuangtai2" />20</p>
</div> </div>
<!-- </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"
<div class="shelf-top">
<p v-for="(item,index) in rackNum" :key="index" :style="{width: `calc(${'100%/' + rackNum} - 4px )`}"><span>{{ index+1 + '架' }}</span></p>
</div>
<ul v-loading="listLoading" class="data-shelf-row">
<!-- :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"
> >
<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>
<!-- <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-in"><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> </div>
<div class="venue-right"> <div class="venue-right">
@ -120,7 +88,7 @@
<h4>本架概况</h4> <h4>本架概况</h4>
<ul class="data-right-list"> <ul class="data-right-list">
<li><p>书架</p><span><i>001</i></span></li> <li><p>书架</p><span><i>001</i></span></li>
<li><p></p><span><i>双面 6 x 5</i></span></li>
<li><p></p><span><i>双面 6 x 5</i></span></li>
</ul> </ul>
</div> </div>
<div class="lib-right-item"> <div class="lib-right-item">
@ -174,13 +142,11 @@ import crudRegion from '@/api/area/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud' import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation' import crudOperation from '@crud/CRUD.operation'
import { mapGetters } from 'vuex' 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 } const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null }
export default { export default {
name: 'DataScreening', name: 'DataScreening',
components: { swiper, swiperSlide, crudOperation },
components: { crudOperation },
cruds() { cruds() {
return CRUD({ title: '架位总览', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: { return CRUD({ title: '架位总览', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
add: false, add: false,
@ -197,8 +163,11 @@ export default {
data() { data() {
const _this = this const _this = this
return { return {
listLoading: false,
tabIndex: 0,
floorName: null, floorName: null,
regionName: null, regionName: null,
rowType: null,
bookShelfDetails: null, bookShelfDetails: null,
booShelfGrid: null, booShelfGrid: null,
cellInfo: { cellInfo: {
@ -249,7 +218,7 @@ export default {
{ required: true, message: '请输入目标数量', trigger: 'blur' } { required: true, message: '请输入目标数量', trigger: 'blur' }
] ]
}, },
popoverIndex: 1,
popoverIndex: null,
popoverVisible: [], popoverVisible: [],
popoverStyles: [] popoverStyles: []
} }
@ -268,9 +237,9 @@ export default {
cellStyle: function() { cellStyle: function() {
// const h = '100%/' + this.layerNum // const h = '100%/' + this.layerNum
// const w = '100%/' + this.rackNum // const w = '100%/' + this.rackNum
const h = '60px'
const h = '76px'
const w = '100%/' + this.rackNum const w = '100%/' + this.rackNum
return { width: `calc(${w} - 4px )`, height: `calc(${h} - 2px)` }
return { width: `calc(${w} )`, height: `calc(${h})` }
} }
}, },
async created() { async created() {
@ -278,6 +247,7 @@ export default {
const dataScreenRegion = JSON.parse(localStorage.getItem('dataScreenRegion')) const dataScreenRegion = JSON.parse(localStorage.getItem('dataScreenRegion'))
this.floorName = dataScreenRegion.floorName this.floorName = dataScreenRegion.floorName
this.regionName = dataScreenRegion.regionName this.regionName = dataScreenRegion.regionName
this.rowType = dataScreenRegion.rowType
// / // /
this.tabListData = dataScreenRegion.rowType === 1 this.tabListData = dataScreenRegion.rowType === 1
? dataScreenRegion.toward === 1 ? dataScreenRegion.toward === 1
@ -286,6 +256,7 @@ export default {
: [{ name: 'A面' }, { name: 'B面' }] : [{ name: 'A面' }, { name: 'B面' }]
FetchBookShelfDetails({ 'shelfId': dataScreenRegion.id }).then(res => { FetchBookShelfDetails({ 'shelfId': dataScreenRegion.id }).then(res => {
this
this.layerNum = res.shelfFloor this.layerNum = res.shelfFloor
this.rackNum = res.shelfShelf this.rackNum = res.shelfShelf
this.bookShelfDetails = res this.bookShelfDetails = res
@ -295,9 +266,6 @@ export default {
} }
}, },
methods: { methods: {
handleToGrids() {
this.$router.push({ path: '/dataScreening/gird', query: { }})
},
[CRUD.HOOK.beforeRefresh]() { [CRUD.HOOK.beforeRefresh]() {
}, },
[CRUD.HOOK.afterRefresh](crud) { [CRUD.HOOK.afterRefresh](crud) {
@ -314,6 +282,7 @@ export default {
return gridNames return gridNames
}, },
getInitShelfGridByShelfId(toward) { getInitShelfGridByShelfId(toward) {
this.listLoading = true
// rowType 1 2 // rowType 1 2
// toward 1 A 2 B // toward 1 A 2 B
// shelfType 1 '1S' // shelfType 1 '1S'
@ -337,7 +306,9 @@ export default {
this.booShelfGrid = this[sortMethod](res) this.booShelfGrid = this[sortMethod](res)
this.popoverVisible = Array(this.booShelfGrid.length).fill(false) this.popoverVisible = Array(this.booShelfGrid.length).fill(false)
// this.popoverStyles = new Array(this.booShelfGrid.length).fill({ position: 'absolute', left: '20%', top: '48px' })
setTimeout(() => {
this.listLoading = false
}, 1000)
}).catch(() => { }).catch(() => {
}) })
}, },
@ -415,34 +386,34 @@ export default {
} }
return sortedData return sortedData
}, },
handleSlidClickFun(index) {
changeActiveTab(index) {
this.tabIndex = index
this.cellIndex = null 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)
this.getInitShelfGridByShelfId(index + 1)
}, },
handleCellCurrent(item, index) { handleCellCurrent(item, index) {
console.log('index', index) console.log('index', index)
console.log('item', item)
this.cellIndex = index this.cellIndex = index
this.cellInfo = { this.cellInfo = {
id: item.id, id: item.id,
gridName: item.gridName, gridName: item.gridName,
startSortmark: item.startSortmark,
endSortmark: item.endSortmark,
cameraId: item.cameraId,
check: item.isCheck,
order: item.isOrder
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))
}, },
showPopover(index) { showPopover(index) {
this.popoverIndex = index this.popoverIndex = index
// popover
if (!this.popoverVisible[index]) { if (!this.popoverVisible[index]) {
this.$set(this.popoverVisible, index, true) this.$set(this.popoverVisible, index, true)
} }
@ -451,19 +422,18 @@ export default {
const secondLastColumnIndexes = [] const secondLastColumnIndexes = []
for (let i = 0; i < this.booShelfGrid.length; i++) { for (let i = 0; i < this.booShelfGrid.length; i++) {
//
const columnIndex = i % this.rackNum const columnIndex = i % this.rackNum
// 5 // 5
if (columnIndex === this.rackNum - 1) { if (columnIndex === this.rackNum - 1) {
lastColumnIndexes.push(i) lastColumnIndexes.push(i)
// //
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-140px', top: '48px' })
// this.$set(this.popoverStyles, i, { position: 'absolute', left: '0', top: '20px' })
} }
// 4 // 4
if (columnIndex === this.rackNum - 2) { if (columnIndex === this.rackNum - 2) {
secondLastColumnIndexes.push(i) secondLastColumnIndexes.push(i)
// //
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '48px' })
// this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '20px' })
} }
} }
}, },
@ -487,16 +457,7 @@ export default {
.venue-content{ .venue-content{
position: relative; position: relative;
} }
.venue-header{
h4{
flex: 1;
}
.bookshelf-area{
padding-right: 30px;
font-weight: bold;
color: #0348F3;
}
}
.crud-opts{ .crud-opts{
position: absolute; position: absolute;
right: 20px; right: 20px;
@ -566,62 +527,95 @@ export default {
} }
} }
} }
.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: 600px;
}
.tag-info{ .tag-info{
position: absolute; position: absolute;
right: 20px; right: 20px;
top: 34px;
display: flex;
justify-content: flex-start;
padding-left: 100px;
top: 8px;
p{ p{
margin-left: 20px; margin-left: 20px;
margin-top: -4px;
}
}
.shelf-top{
display: flex;
justify-content: space-around;
align-items: center;
text-align: center;
margin-top: 20px;
p{
font-size: 14px; font-size: 14px;
color: #fff;
height: 36px;
line-height: 30px;
background: url('~@/assets/images/shelf04.png') no-repeat center top;
background-size: auto 100%;
} }
} }
.cabinet-row .cabinet-cell{
overflow: inherit;
cursor: pointer;
span.cell-name{
position: initial !important;
transform: none;
line-height: 58px;
.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 .cabinet-row .cabinet-cell span.el-popover__reference-wrapper{
::v-deep .data-shelf-row span.el-popover__reference-wrapper{
position: absolute !important; position: absolute !important;
left: 50% !important;
top: 20px !important;
transform: none;
left: 60% !important;
top: 48px !important;
width: 300px; width: 300px;
height: 210px; height: 210px;
background:rgba(0,0,0,.8); background:rgba(0,0,0,.8);
color: #fff; color: #fff;
border-radius: 6px; border-radius: 6px;
z-index: 99999999; z-index: 99999999;
.popover-content{ .popover-content{
.tooltip-top{ .tooltip-top{
display: flex; display: flex;

149
src/views/visualCheck/checkManage/upDownLog/index.vue

@ -1,16 +1,159 @@
<template> <template>
<div class="app-container">
上架/下架日志
<div class="app-container row-container">
<div class="head-container">
<div class="head-search">
<!-- 搜索 -->
<el-select v-model="query.type" clearable size="small" placeholder="类型" class="filter-item" style="width: 120px" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in typeOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-select v-model="query.other" clearable size="small" placeholder="方式" class="filter-item" style="width: 120px" @change="crud.toQuery">
<i slot="prefix" class="iconfont icon-zhuangtai" />
<el-option v-for="item in otherOptions" :key="item.key" :label="item.display_name" :value="item.key" />
</el-select>
<el-input v-model="query.search" clearable size="small" placeholder="输入关键字搜索" prefix-icon="el-icon-search" style="width: 220px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" />
<rrOperation />
</div>
<crudOperation :permission="permission">
<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>
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-table
ref="table"
v-loading="crud.loading"
class="archives-table"
:data="crud.data"
style="width: 100%;"
height="590"
@selection-change="crud.selectionChangeHandler"
@row-click="clickRowHandler"
@row-dblclick="handleDbClick"
>
<el-table-column prop="regionName" label="类型" />
<el-table-column prop="regionCode" label="方式" />
<el-table-column prop="floorName" label="题名" />
<el-table-column prop="booksheflCount" label="索书号" />
<el-table-column prop="booksheflCount" label="条码" />
<el-table-column prop="booksheflCount" label="目标层位" />
<el-table-column prop="booksheflCount" label="盘点单号" />
<el-table-column prop="booksheflCount" label="操作者" />
<el-table-column prop="createTime" label="操作时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination v-if="crud.data.length!==0" />
</div>
</div> </div>
</template> </template>
<script> <script>
import crudRegion from '@/api/area/index'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import rrOperation from '@crud/RR.operation'
import pagination from '@crud/Pagination'
import { mapGetters } from 'vuex'
// import { exportFile } from '@/utils/index'
// import qs from 'qs'
const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null }
export default { export default {
name: 'UpDownLog', name: 'UpDownLog',
components: { crudOperation, rrOperation, pagination },
cruds() {
return CRUD({ title: '上架/下架日志', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
add: false,
edit: false,
del: false,
download: false,
group: false,
reset: false
}})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data() { data() {
return { return {
otherOptions: [
{ key: '1', display_name: '自动' },
{ key: '2', display_name: '手动' }
],
typeOptions: [
{ key: '1', display_name: '上架' },
{ key: '2', display_name: '下架' }
],
permission: {
add: ['admin', 'checkLog:add'],
edit: ['admin', 'checkLog:edit'],
del: ['admin', 'checkLog:del']
}
}
},
computed: {
...mapGetters([
'user',
'baseApi'
])
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
},
[CRUD.HOOK.afterRefresh](crud) {
},
//
[CRUD.HOOK.beforeToAdd]() {
}, //
[CRUD.HOOK.beforeToEdit](crud, form) {
},
[CRUD.HOOK.beforeValidateCU](crud, form) {
},
//
[CRUD.HOOK.afterValidateCU](crud) {
return false
},
clickRowHandler(row) {
this.$refs.table.clearSelection()
this.$refs.table.toggleRowSelection(row)
},
doExport(data) {
console.log(data)
this.crud.downloadLoading = true
this.$confirm('此操作将导出所选数据' + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
cancelButtonText: '取消',
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
const ids = []
data.forEach(val => {
ids.push(val.deptsId)
})
const params = {
'deptsIds': ids
}
console.log(params)
// exportFile(this.baseApi + '/api/depts/download?' + qs.stringify(params, { indices: false }))
// this.crud.downloadLoading = false
}).catch(() => {
})
},
handleCloseDialog() {
} }
} }
} }
</script> </script>
<style scoped>
<style lang="scss" scoped>
</style> </style>

10
src/views/visualCheck/venueDevice/bookshelfPosition/index.vue

@ -552,16 +552,6 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.venue-header{
h4{
flex: 1;
}
.bookshelf-area{
padding-right: 30px;
font-weight: bold;
color: #0348F3;
}
}
.swiper-title{ .swiper-title{
::v-deep .swiper-wrapper{ ::v-deep .swiper-wrapper{
margin: 10px 0; margin: 10px 0;

Loading…
Cancel
Save