Browse Source

盘点

master
xuhuajiao 2 years 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. 34
      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. 750
      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. 256
      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

34
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{
@ -351,3 +357,31 @@
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">
<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"> <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>{{ 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) {

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

@ -1,12 +1,30 @@
<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">
<div class="tab-content">
<span class="right-top-line" />
<span class="left-bottom-line" />
<div class="gird-data-header">
<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-in">在架:<i class="iconfont icon-zhuangtai2" />20</p>
</div>
<crudOperation :permission="permission"> <crudOperation :permission="permission">
<template v-slot:middle> <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"> <el-button v-permission="permission.add" size="mini" @click="crud.toAdd">
<i class="iconfont icon-shengchengpandiandan" /> <i class="iconfont icon-shengchengpandiandan" />
架位盘点 架位盘点
@ -19,18 +37,71 @@
</el-button> </el-button>
</template> </template>
</crudOperation> </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 floorOptions" :key="index" :class="{ 'active-tab-nav': tabIndex == index }" @click="changeActiveTab(index)">{{ item.floorName }}<i /></li>
<!-- 最右侧装饰img -->
<span class="tab-right-img" />
</div>
<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> </ul>
</div> </div>
</div> </div>
<div class="venue-right" />
</div>
</div>
</div>
<!-- form --> <!-- 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"> <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">
@ -62,60 +133,119 @@
</div> </div>
</div> </div>
</el-dialog> </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> </div>
</div></template>
</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`, // 鼠标的Y坐标偏移10px
left: `${this.popoverPosition.x}px`, // 鼠标的X坐标偏移10px
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 '始终最左边为第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)
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
}
if (this.tabIndex === 0) {
if (this.allCoverData[0].signPoint) {
const drawinfo = JSON.parse(this.allCoverData[0].signPoint)
this.$nextTick(() => {
this.$refs.previewRefs.initCanvasPreview(drawinfo)
})
// 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)
} }
} }
} 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
},
// 最右为第一架,最左为最后一架, 最顶层为第一层 从上往下
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)
} }
}).catch(() => {
})
}
}
return sortedData
}, },
handleSlidClickFun(index) {
this.rightDataIndex = null
this.handleSlideToFun(index)
// 最左为第一架, 最底层为第一层 从下往上
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
}, },
handleSlideToFun(index) {
this.swiperActiveIndex = index
this.swiperContent.slideTo(index, 500, false)
this.swiperTitle.slideTo(index, 500, false)
// 最左为最后一架, 最底层为第一层 从下往上
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)
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)
},
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{
.gird-layer{
position: relative;
display: flex;
justify-content: space-between;
.gird-left-line{
position: absolute; position: absolute;
right: 20px;
top: 10px;
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;
} }
.venue-left{
flex: 1;
margin-right: 0 !important;
.venue-preview{
height: 633px !important;
.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;
} }
.venue-right{
display: flex;
flex-direction: column;
width: 400px;
padding: 50px 10px 20px 10px !important;
.lib-right-item{
.layer-left-book{
// width: calc(100vw - 655px);
height: 130px;
white-space: nowrap;
.book-item{
position: relative; 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;
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;
}
}
}
}
.layer-right-handle{
width: 300px;
padding: 0 10px;
background-color: #E8F2FF; background-color: #E8F2FF;
color: #000;
margin: 3px 5px;
border-radius: 6px;
}
.layer-info-header{
display: flex;
justify-content: space-between;
align-items: center;
line-height: 30px; line-height: 30px;
border-bottom: 1px solid #edeff3;
h4{
color: #0c0e1e;
} }
.refresh-date{
position: absolute;
right: 14px;
top: 10px;
span{
font-size: 12px; font-size: 12px;
line-height: 30px;
} }
} }
.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;
flex-direction: column;
.el-button{
margin-left: 0 !important;
margin-bottom: 10px
}
} }
.data-right-list {
padding-top: 10px;
li{
.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;
}
}
.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;
justify-content: flex-start;
align-items: center;
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; display: flex;
justify-content: flex-start; justify-content: flex-start;
align-items: center; align-items: center;
line-height: 36px; 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;
}
ul li i{
font-style: normal; font-style: normal;
font-weight: bold; font-weight: bold;
padding: 0 10px; padding: 0 10px;
color: #0348f3; color: #0348f3;
} }
&.percentage{
ul li em.percentage{
width: auto; 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 '始终最左边为第1架(S型排架)'
// shelfType 2 'A面最左为第1架(B面最左为最后1架)'
// shelfType 3 'B面最左为第1架(A面最左为最后1架)'
// floorType 1 '最顶层为第一层(从上至下)'
// floorType 2 '最底层为第一层(从下至上)'
FetchInitShelfGridByShelfId({ 'shelfId': this.bookShelfDetails.id, 'toward': toward }).then(res => {
const sortFunction = toward === 1 ? {
1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' },
2: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' },
3: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' }
} : {
1: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' },
2: { 1: 'sortBookshelvesRightTop', 2: 'sortBookshelvesRightBottom' },
3: { 1: 'sortBookshelvesLeftTop', 2: 'sortBookshelvesLeftBottom' }
}
const shelfType = this.bookShelfDetails.shelfType
const floorType = this.bookShelfDetails.floorType
const sortMethod = sortFunction[shelfType][floorType]
this.booShelfGrid = this[sortMethod](res)
this.popoverVisible = Array(this.booShelfGrid.length).fill(false)
// this.popoverStyles = new Array(this.booShelfGrid.length).fill({ position: 'absolute', left: '20%', top: '48px' })
}).catch(() => {
})
},
// 最左为第一架, 最顶层为第一层 从上往下
sortBookshelvesLeftTop(data) {
const sortedData = []
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor)))
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1))))
for (let i = 1; i <= maxFloor; i++) {
for (let j = 1; j <= maxShelf; j++) {
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j)
if (currentShelf) {
sortedData.push(currentShelf)
}
}
}
return sortedData
},
// 最右为第一架,最左为最后一架, 最顶层为第一层 从上往下
sortBookshelvesRightTop(data) {
const sortedData = []
// 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor)))
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0])))
for (let i = 1; i <= maxFloor; i++) {
// 从最大的书架层数开始,向下排序
for (let j = maxShelf; j >= 1; j--) {
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j)
if (currentShelf) {
sortedData.push(currentShelf)
}
}
}
return sortedData
},
// 最左为第一架, 最底层为第一层 从下往上
sortBookshelvesLeftBottom(data) {
const sortedData = []
// 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor)))
// 获取最大的书架层数
const maxShelf = Math.max(...data.map(item => parseInt(item.gridShelf.slice(-1))))
for (let i = maxFloor; i >= 1; i--) {
for (let j = 1; j <= maxShelf; j++) {
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.slice(-1)) === j)
if (currentShelf) {
sortedData.push(currentShelf)
}
}
}
return sortedData
},
// 最左为最后一架, 最底层为第一层 从下往上
sortBookshelvesRightBottom(data) {
const sortedData = []
// 获取最大的楼层数
const maxFloor = Math.max(...data.map(item => parseInt(item.gridFloor)))
const maxShelfPerFloor = data.map(item => parseInt(item.gridShelf.match(/\d+$/)[0]))
.reduce((acc, curr, index, arr) => {
const floor = parseInt(data[index].gridFloor)
if (!acc[floor]) acc[floor] = 1
if (acc[floor] < curr) acc[floor] = curr
return acc
}, {})
// 从最大的楼层开始向下遍历
for (let i = maxFloor; i >= 1; i--) {
// 从最大的书架编号开始向左遍历
for (let j = maxShelfPerFloor[i] || 1; j >= 1; j--) {
const currentShelf = data.find(item => parseInt(item.gridFloor) === i && parseInt(item.gridShelf.match(/\d+$/)[0]) === j)
if (currentShelf) {
sortedData.push(currentShelf)
}
}
}
return sortedData
},
handleSlidClickFun(index) {
this.cellIndex = null
this.handleSlideToFun(index)
if (localStorage.getItem('bookShelfDetails')) {
this.getInitShelfGridByShelfId(index + 1)
}
},
handleSlideToFun(index) {
this.swiperActiveIndex = index
this.swiperContent.slideTo(index, 500, false)
this.swiperTitle.slideTo(index, 500, false)
},
handleCellCurrent(item, index) {
console.log('index', index)
this.cellIndex = index
this.cellInfo = {
id: item.id,
gridName: item.gridName,
startSortmark: item.startSortmark,
endSortmark: item.endSortmark,
cameraId: item.cameraId,
check: item.isCheck,
order: item.isOrder
}
},
showPopover(index) {
this.popoverIndex = index
// 显示对应的 popover
if (!this.popoverVisible[index]) {
this.$set(this.popoverVisible, index, true)
}
const lastColumnIndexes = []
const secondLastColumnIndexes = []
for (let i = 0; i < this.booShelfGrid.length; i++) {
// 计算当前数据项的列索引
const columnIndex = i % this.rackNum
// 如果是最后一列(第5列)
if (columnIndex === this.rackNum - 1) {
lastColumnIndexes.push(i)
// 更新最后一列的样式
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-140px', top: '48px' })
}
// 如果是倒数第二列(第4列)
if (columnIndex === this.rackNum - 2) {
secondLastColumnIndexes.push(i)
// 更新倒数第二列的样式
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '48px' })
}
}
},
hidePopover() {
this.popoverIndex = null
// 隐藏所有的popover
this.popoverVisible.forEach((isVisible, index) => {
if (isVisible) {
this.$set(this.popoverVisible, index, false)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.container-right{
min-height: calc(100vh - 232px) !important;
}
.venue-content{
position: relative;
}
.crud-opts{
position: absolute;
right: 20px;
top: 10px;
}
.venue-left{
flex: 1;
margin-right: 0 !important;
.venue-preview{
height: 633px !important;
}
}
.venue-right{
display: flex;
flex-direction: column;
width: 400px;
padding: 50px 10px 20px 10px !important;
.lib-right-item{
position: relative;
padding-bottom: 10px;
margin-bottom: 10px;
border: 1px solid #E8F2FF;
border-radius: 4px;
h4{
padding: 6px 10px;
background-color: #E8F2FF;
color: #000;
line-height: 30px;
border-bottom: 1px solid #edeff3;
}
.refresh-date{
position: absolute;
right: 14px;
top: 10px;
font-size: 12px;
line-height: 30px;
}
}
}
.data-right-list {
padding-top: 10px;
li{
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 36px;
p{
width: 80px;
font-weight: bold;
text-align: right;
}
span{
width: 140px;
display: block;
text-align: right;
i{
font-style: normal;
font-weight: bold;
padding: 0 10px;
color: #0348f3;
}
&.percentage{
width: auto;
}
}
}
}
.swiper-title{
::v-deep .swiper-wrapper{
margin: 10px 0;
border-bottom: 1px solid #EDEFF3;
}
}
.swiper-slide-title {
width: auto !important;
margin-right: 20px;
cursor: pointer;
.tab-name {
padding: 10px;
&.active {
color: #0348F3;
border-bottom: 3px solid #0348F3;
}
}
}
.swiper-content{
height: 610px;
}
.tag-info{
position: absolute;
right: 20px;
top: 34px;
display: flex;
justify-content: flex-start;
padding-left: 100px;
p{
margin-left: 20px;
margin-top: -4px;
font-size: 14px;
}
}
.cabinet-row .cabinet-cell{
background: url('~@/assets/images/shelf02.png') repeat-x left top;
background-size: 100% 100%;
border: none;
overflow: inherit;
cursor: pointer;
&::before{
content: "";
position: absolute;
left: 0;
top: 0;
width: 6px;
height: 68px;
background: url('~@/assets/images/shelf01.png') no-repeat left top;
background-size: 100% 100%;
}
&::after{
content: "";
position: absolute;
right: -4px;
top: 0;
width: 6px;
height: 68px;
background: url('~@/assets/images/shelf01.png') no-repeat left top;
background-size: 100% 100%;
}
span.cell-name{
position: initial !important;
transform: none;
line-height: 68px;
}
}
::v-deep .cabinet-row .cabinet-cell span.el-popover__reference-wrapper{
position: absolute !important;
left: 50% !important;
top: 20px !important;
transform: none;
width: 300px;
height: 210px;
background:rgba(0,0,0,.8);
color: #fff;
border-radius: 6px;
z-index: 99999999;
.popover-content{
.tooltip-top{
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
line-height: 40px;
padding: 0 10px;
border-bottom: 1px solid #fff;
}
.tooltip-top i{
font-style: normal;
font-size: 12px;
}
ul{
padding: 10px;
}
ul li{
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 36px;
font-style: normal;
}
ul li p{
width: 80px;
font-weight: bold;
text-align: right;
}
ul li em{
width: 100px;
display: block;
text-align: right;
font-style: normal;
}
ul li i{
font-style: normal;
font-weight: bold;
padding: 0 10px;
color: #0348f3;
}
ul li em.percentage{
width: auto;
}
}
}
</style>

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

@ -27,67 +27,37 @@
<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"
>
<ul class="cabinet-row">
<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 <li
v-for="(cell,i) in booShelfGrid" v-for="(cell,i) in booShelfGrid"
:key="i" :key="i"
class="cabinet-cell"
class="data-shelf-cell"
:style="cellStyle" :style="cellStyle"
:class="{ active: i === cellIndex }"
@click="handleCellCurrent(cell,i)"
@dblclick="handleCellCurrent(cell,i)"
@mouseenter="showPopover(i)" @mouseenter="showPopover(i)"
@mouseleave="hidePopover" @mouseleave="hidePopover"
> >
<span class="cell-name">{{ removeAreaPrefix(cell.gridName) }}</span>
<!-- v-if="popoverIndex === i" -->
<!-- <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 <el-popover
v-if="popoverIndex === i" v-if="popoverIndex === i"
ref="popover" ref="popover"
@ -111,8 +81,6 @@
</el-popover> </el-popover>
</li> </li>
</ul> </ul>
</swiper-slide>
</swiper>
</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 '始终最左边为第1架(S型排架)' // shelfType 1 '始终最左边为第1架(S型排架)'
@ -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) this.getInitShelfGridByShelfId(index + 1)
}
},
handleSlideToFun(index) {
this.swiperActiveIndex = index
this.swiperContent.slideTo(index, 500, false)
this.swiperTitle.slideTo(index, 500, false)
}, },
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;
.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; cursor: pointer;
span.cell-name{
position: initial !important;
transform: none;
line-height: 58px;
.tag-info{
right: 12px;
top: 44px;
p{
margin-left: 10px;
} }
} }
::v-deep .cabinet-row .cabinet-cell span.el-popover__reference-wrapper{
&::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; 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> </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> </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>
</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