Browse Source

统计分析/图书查询/数据总览

master
xuhuajiao 6 months ago
parent
commit
542213322b
  1. 6
      .env.production
  2. 2
      public/static/config.js
  3. 10
      src/api/stockTaskLog/index.js
  4. 100
      src/assets/styles/manage.scss
  5. 53
      src/views/components/canvasPreview.vue
  6. 10
      src/views/visualCheck/bookstore/collection/index.vue
  7. 47
      src/views/visualCheck/checkManage/bookSearch/index.vue
  8. 2
      src/views/visualCheck/checkManage/bookshelfSearch/index.vue
  9. 66
      src/views/visualCheck/checkManage/checkLog/index.vue
  10. 2
      src/views/visualCheck/checkManage/checkPlan/index.vue
  11. 195
      src/views/visualCheck/checkManage/dataScreening/girdList.vue
  12. 34
      src/views/visualCheck/checkManage/dataScreening/module/form.vue
  13. 98
      src/views/visualCheck/checkManage/dataScreening/shelfList.vue
  14. 26
      src/views/visualCheck/checkManage/paramSetting/index.vue
  15. 33
      src/views/visualCheck/checkManage/statistic/reverseShelf/index.vue
  16. 91
      src/views/visualCheck/checkManage/statistic/search.vue
  17. 4
      src/views/visualCheck/checkManage/statistic/seqShelf/index.vue
  18. 6
      src/views/visualCheck/venueDevice/bookshelf/index.vue
  19. 2
      src/views/visualCheck/venueDevice/bookshelfPosition/index.vue
  20. 3
      src/views/visualCheck/venueDevice/device/index.vue

6
.env.production

@ -3,7 +3,7 @@ ENV = 'production'
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇,Nginx 配置
# 接口地址,注意协议,如果你没有配置 ssl,需要将 https 改为 http
VUE_APP_BASE_API = 'http://27.16.212.58:11100'
VUE_APP_BASE_API = 'http://192.168.3.220:12010'
# 如果接口是 http 形式, wss 需要改为 ws
VUE_APP_WS_API = 'ws://27.16.212.58:11100'
VUE_APP_CAMERA_API = '192.168.99.107:3000'
#VUE_APP_WS_API = 'ws://27.16.212.58:11100'
#VUE_APP_CAMERA_API = '192.168.99.107:3000'

2
public/static/config.js

@ -1,6 +1,6 @@
window.g = {
AXIOS_TIMEOUT: 10000,
ApiUrl: 'http://27.16.212.58:11100', // 配置服务器地址,
ApiUrl: 'http://192.168.3.220:12010', // 配置服务器地址,
// ParentPage: { // 后续看需求配置
// CrossDomainProxyUrl: '/Home/CrossDomainProxy',
// BtnsApi: '/api/services/app/Authorization/GetBtns',

10
src/api/stockTaskLog/index.js

@ -83,6 +83,14 @@ export function FetchStockGirdNum(params) {
})
}
// 获取目标区域层架位总数量
export function FetchTotalGirdNum(params) {
return request({
url: 'api/stocktask-task/getTotalGirdNum' + '?' + qs.stringify(params, { indices: false }),
method: 'get'
})
}
// 手动创建盘点任务
export function add(data) {
return request({
@ -92,4 +100,4 @@ export function add(data) {
})
}
export default { del, FetchStopStockBill, FetchInitStockLogList, FetchInitStockLogDetails, FetchProgressByStockBillAndGridCode, FetchInitStockTaskDetails, FetchNewBillNo, FetchStockGirdNum, add }
export default { del, FetchStopStockBill, FetchInitStockLogList, FetchInitStockLogDetails, FetchProgressByStockBillAndGridCode, FetchInitStockTaskDetails, FetchNewBillNo, FetchStockGirdNum, FetchTotalGirdNum, add }

100
src/assets/styles/manage.scss

@ -538,4 +538,104 @@
margin-left: 10px;
}
}
}
.tooltip-style,
.popover-external-set {
width: 250px;
background:rgba(0,0,0,1);
color: #fff;
border-radius: 6px;
}
.tooltip-style{
display:none;
position:absolute;
}
.popover-external-set {
position: fixed;
z-index: 1000;
}
.tooltip-style,
.popover-content-set{
.tooltip-top{
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
height: 40px;
line-height: 40px;
padding: 0 10px;
border-bottom: 1px solid #fff;
}
.tooltip-top span,
.tooltip-top i{
font-size: 12px;
font-style: normal;
}
ul{
padding: 10px;
}
ul li{
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 24px;
font-style: normal;
font-size: 12px;
}
ul li p{
width: 60px;
font-weight: bold;
text-align: right;
}
ul li span,
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 span.percentage,
ul li em.percentage{
width: auto;
}
.tag-item{
display: block;
// width: 50px;
height: 18px;
line-height: 16px;
padding: 0 4px;
border-radius: 3px;
font-size: 12px;
color: #A6ADB6;
border: 1px solid #E6E8ED;
background-color: #F3F5F9;
text-align: center;
&.tag-sort{
color: #FD7359 !important;
border-color: #FBC0B5 !important;
background-color: #FCECE9 !important;
}
&.tag-place{
color: #018BFF !important;
border-color: #9BD1FF !important;
background-color: #DCEDFD !important;
}
&.tag-all{
color: #0C0E1E;
border-color: #545B65 !important;
background-color: #E6E8ED !important;
}
}
}

53
src/views/components/canvasPreview.vue

@ -267,59 +267,6 @@ export default {
}
}
</script>
<style>
.tooltip-style{
display:none;
position:absolute;
width: 300px;
background:rgba(0,0,0,.6);
color: #fff;
border-radius: 6px;
}
.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 span{
font-size: 12px;
}
#tooltip ul{
padding: 10px;
}
#tooltip ul li{
display: flex;
justify-content: flex-start;
align-items: center;
line-height: 36px;
font-style: normal;
}
#tooltip ul li p{
width: 80px;
font-weight: bold;
text-align: right;
}
#tooltip ul li span{
width: 100px;
display: block;
text-align: right;
}
#tooltip ul li i{
font-style: normal;
font-weight: bold;
padding: 0 10px;
color: #0348f3;
}
#tooltip ul li span.percentage{
width: auto;
}
</style>
<style lang="scss" scoped>
#expImg{
display: none;

10
src/views/visualCheck/bookstore/collection/index.vue

@ -80,7 +80,7 @@
/>
</el-select>
</el-form-item>
<div>
<!-- <div>
<el-form-item class="collection-tree-select" label="所在架位" prop="actualLocation">
<treeselect
v-model="form.actualShelfId"
@ -107,7 +107,7 @@
<div slot="value-label" slot-scope="{ node }">{{ getAutoNameUnknown(node.label) }}</div>
</treeselect>
</el-form-item>
</div>
</div> -->
</div>
<div v-if="imageUrl" class="preview-cover">
<p>封面预览</p>
@ -174,8 +174,8 @@ import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import pagination from '@crud/Pagination'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
// import Treeselect from '@riophae/vue-treeselect'
// import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { parseTime, saveAs, getBlob } from '@/utils/index'
import qs from 'qs'
import { mapGetters } from 'vuex'
@ -184,7 +184,7 @@ import JsBarcode from 'jsbarcode'
const defaultForm = { id: null, title: null, sortmark: null, isbn: null, barcode: null, collectionName: null, actualLocation: null, actualShelfId: null }
export default {
name: 'Collection',
components: { crudOperation, pagination, Treeselect },
components: { crudOperation, pagination },
filters: {
creatBarCode(barCodeData, codePrintData, barCodeText) {
console.log('codePrintData', codePrintData)

47
src/views/visualCheck/checkManage/bookSearch/index.vue

@ -12,10 +12,10 @@
</div>
<crudOperation :permission="permission">
<template v-slot:right>
<el-button size="mini" :disabled="crud.selections.length === 0" @click="handleBatchListing">
<!-- <el-button size="mini" :disabled="crud.selections.length === 0" @click="handleBatchListing">
<i class="iconfont icon-ruku" />
批量上架
</el-button>
</el-button> -->
<el-button size="mini" :loading="crud.downloadLoading" :disabled="crud.selections.length === 0" @click="handleRemoveShelf(crud.selections)">
<i class="iconfont icon-chuku" />
一键下架
@ -32,34 +32,33 @@
class="archives-table"
:data="crud.data"
style="width: 100%;"
height="540"
height="calc(100vh - 329px)"
@selection-change="crud.selectionChangeHandler"
@row-click="clickRowHandler"
@row-dblclick="handleDbClick"
>
<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 label="状态" align="center" prop="deptsStatus">
<!-- slot-scope="scope" -->
<template>
<span class="row-state row-warehousing">未知</span>
<!-- <span class="row-state row-binding state-active">在架</span>
<span class="row-state row-lending state-active">错架</span>
<span class="row-state row-physical state-active">错序</span> -->
<el-table-column prop="bookName" label="题名" />
<el-table-column prop="bookAuthor" label="著者" />
<el-table-column prop="barcode" label="条码" />
<el-table-column prop="sortmark" label="索书号" />
<el-table-column prop="regionName" label="所在位置" />
<el-table-column label="状态" align="center" prop="bookStatus">
<template slot-scope="scope">
<span v-if="scope.row.bookStatus === '未知'" class="row-state row-warehousing">未知</span>
<span v-if="scope.row.bookStatus === '在架'" class="row-state row-binding state-active">在架</span>
<span v-if="scope.row.bookStatus === '错架'" class="row-state row-lending state-active">错架</span>
<span v-if="scope.row.bookStatus === '错序'" class="row-state row-physical state-active">错序</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="所属馆藏">
<!-- <el-table-column prop="createTime" label="所属馆藏">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
<el-table-column prop="createTime" label="更新时间">
</el-table-column> -->
<el-table-column prop="updateTime" label="更新时间">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
<div>{{ scope.row.updateTime | parseTime }}</div>
</template>
</el-table-column>
</el-table>
@ -200,7 +199,7 @@ export default {
name: 'BookSearch',
components: { crudOperation, rrOperation, pagination },
cruds() {
return CRUD({ title: '图书检索', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
return CRUD({ title: '图书检索', url: 'api/bookBasice/initBookDetailsSearch', crudMethod: { ...crudRegion }, sort: [], optShow: {
add: false,
edit: false,
del: false,
@ -213,10 +212,10 @@ export default {
data() {
return {
statusOptions: [
{ key: '1', display_name: '在架' },
{ key: '2', display_name: '错架' },
{ key: '3', display_name: '错序' },
{ key: '4', display_name: '未知' }
{ key: 1, display_name: '在架' },
{ key: 2, display_name: '错架' },
{ key: 3, display_name: '错序' },
{ key: 4, display_name: '未知' }
],
permission: {
add: ['admin', 'search:add'],

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

@ -6,7 +6,7 @@
<el-select v-model="selectFloorVal" clearable size="small" placeholder="楼层" class="filter-item" style="width: 80px" value-key="id" @change="changeBeforeFloor">
<el-option v-for="(item,index) in floorOptions" :key="index" :label="item.floorName" :value="item" />
</el-select>
<el-select v-model="selectRegionVal" clearable size="small" placeholder="区域" class="filter-item" style="width: 120px" value-key="id" @change="changeBeforeRegion">
<el-select v-model="selectRegionVal" clearable size="small" placeholder="区域" class="filter-item" style="width: 140px" value-key="id" @change="changeBeforeRegion">
<el-option v-for="(item,index) in regionOptions" :key="index" :label="item.regionName" :value="item" />
</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" />

66
src/views/visualCheck/checkManage/checkLog/index.vue

@ -51,7 +51,7 @@
<el-table-column prop="stockRegion" label="目标位置" :show-overflow-tooltip="true" />
<el-table-column prop="stockGridNum" label="目标数量">
<template slot-scope="scope">
<div>{{ scope.row.stockGridNum + ' / 层位' }}</div>
<div>{{ scope.row.stockGridNum + ' / '+ (scope.row.totalGridNum?scope.row.totalGridNum:'0') +' 层位' }}</div>
</template>
</el-table-column>
<el-table-column prop="stockRemarks" label="备注">
@ -141,7 +141,7 @@
<li v-if="detailInfo.stockType===6"><span>盘点类型</span>层位盘点</li>
<li><span>目标位置</span>{{ detailInfo.stockRegion }}</li>
<li><span>目标数量</span>{{ detailInfo.stockGridNum }} / 层位</li>
<li><span>目标数量</span>{{ detailInfo.stockGridNum }} / {{ detailInfo.totalGridNum }} 层位</li>
<li v-if="detailInfo.stockRemarks !== null" class="row-li"><span>备注</span>{{ detailInfo.stockRemarks }}</li>
<li v-else class="row-li"><span>备注</span>-</li>
@ -182,7 +182,7 @@
>
<el-table-column prop="gridName" label="层位架" min-width="180" :show-overflow-tooltip="true" />
<el-table-column prop="floorName" label="楼层" />
<el-table-column prop="regionName" label="区域" />
<el-table-column prop="regionName" label="区域" min-width="120" />
<el-table-column prop="booksheflCount" label="盘点详情" min-width="280" :show-overflow-tooltip="true">
<template slot-scope="scope">
<ul class="detail-table-info">
@ -192,7 +192,11 @@
</ul>
</template>
</el-table-column>
<el-table-column prop="progress" label="进度" min-width="140" />
<el-table-column prop="progress" label="进度" min-width="140">
<template slot-scope="scope">
<span>{{ scope.row.progress !== null ? scope.row.progress : '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="state" label="状态" width="80">
<template slot-scope="scope">
<span v-if="scope.row.state === 0" class="row-state row-lending state-active">已终止</span>
@ -238,7 +242,7 @@ import { mapGetters } from 'vuex'
import { parseTime, saveAs, getBlob } from '@/utils/index'
import qs from 'qs'
const defaultForm = { stockTypeName: '全量盘点', stockType: 1, stockBill: null, stockRegion: '全部区域', stockGridNum: null, stockGridNumName: null, stockRemarks: null, regionId: null, shelfId: null, gridShelf: null, gridId: null }
const defaultForm = { stockTypeName: '全量盘点', stockType: 1, stockBill: null, stockRegion: '全部区域', stockGridNum: null, stockGridNumName: null, totalGridNum: null, stockRemarks: null, regionId: null, shelfId: null, gridShelf: null, gridId: null }
export default {
name: 'CheckLog',
components: { crudOperation, rrOperation, pagination, taskStockLogEcharts },
@ -315,17 +319,24 @@ export default {
},
//
[CRUD.HOOK.beforeToAdd]() {
let params
if (this.crud.form.stockType === 1) {
this.crud.form.stockTypeName = '全量盘点'
params = {
'gridShelf': null,
'regionId': null,
'shelfId': null
}
}
Promise.all([
crudStockTaskLog.FetchNewBillNo(),
crudStockTaskLog.FetchStockGirdNum()
]).then(([newBillNoRes, stockGridNumRes]) => {
crudStockTaskLog.FetchStockGirdNum(),
crudStockTaskLog.FetchTotalGirdNum(params)
]).then(([newBillNoRes, stockGridNumRes, totalGirdNumRes]) => {
this.crud.form.stockBill = newBillNoRes
this.crud.form.stockGridNumName = stockGridNumRes + ' / 层位'
this.crud.form.stockGridNumName = stockGridNumRes + ' / ' + totalGirdNumRes + ' 层位'
this.crud.form.stockGridNum = stockGridNumRes
this.crud.form.totalGridNum = totalGirdNumRes
}).catch(error => {
console.error(error)
})
@ -394,26 +405,33 @@ export default {
}
crudStockTaskLog.FetchInitStockTaskDetails(params).then(res => {
if (res) {
const progressPromises = res.content.map(item => {
const paramsProgress = {
'stockBill': this.dbRowData.stockBill,
'gridCode': item.gridCode
}
return crudStockTaskLog.FetchProgressByStockBillAndGridCode(paramsProgress)
})
if (this.dbRowData.state === 2) {
const progressPromises = res.content.map(item => {
const paramsProgress = {
'stockBill': this.dbRowData.stockBill,
'gridCode': item.gridCode
}
return crudStockTaskLog.FetchProgressByStockBillAndGridCode(paramsProgress)
})
Promise.all(progressPromises).then(progressResults => {
this.detailTable = res.content.map((item, index) => {
item.progress = progressResults[index]
return item
})
Promise.all(progressPromises).then(progressResults => {
this.gridTableLoading = false
}).catch(error => {
console.error(error)
this.gridTableLoading = false
})
} else {
this.detailTable = res.content.map((item, index) => {
item.progress = progressResults[index]
item.progress = this.dbRowData.state === 0 ? '已终止' : (this.dbRowData.state === 1 ? '排队中' : '已完成')
return item
})
this.gridTableLoading = false
}).catch(error => {
console.error(error)
this.gridTableLoading = false
})
}
this.detailPage.total = res.totalElements
}
}).catch(() => {

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

@ -270,7 +270,7 @@ import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import qs from 'qs'
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 }
const defaultForm = { id: null, taskType: '计划盘点', regionId: null, weekly: [], taskName: null, timerType: 2, timeInterval: null, startTime2: parseTime(new Date().getTime()), endTime2: null, nowTime: null, longTime: true, explain: null }
export default {
name: 'CheckPlan',
components: { crudOperation, rrOperation, pagination, Treeselect },

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

@ -34,6 +34,25 @@
<p class="tag-place">错架<i class="iconfont icon-zhuangtai2" />1</p>
<p class="tag-all">在架<i class="iconfont icon-zhuangtai2" />20</p>
</div>
<div class="time-update-cont">
<span class="time-left-txt">最后更新时间</span>
<el-button>2024-11-28 09:46</el-button>
<div class="time-update-line">
<el-timeline>
<el-timeline-item
v-for="(activity, index) in checkDateLine"
:key="index"
:icon="activity.icon"
:type="activity.type"
:color="activity.color"
:size="activity.size"
:timestamp="activity.timestamp"
>
{{ activity.content }}
</el-timeline-item>
</el-timeline>
</div>
</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: 10px;">
@ -97,10 +116,10 @@
<div
v-if="popoverIndex !== null"
class="popover-external"
class="popover-external-set"
:style="popoverStyle"
>
<div class="popover-content">
<div class="popover-content-set">
<div class="tooltip-top">
<h4>水浒传</h4>
<span class="tag-item tag-sort">错架</span>
@ -229,7 +248,7 @@ export default {
shelfAllGridData: [],
layerNum: 0,
rackNum: 0,
bookNum: 55,
bookNum: 46,
layerVal: null,
rackOptions: [],
tabListData: [],
@ -242,7 +261,37 @@ export default {
popoverVisible: [],
popoverStyles: [],
currentBookName: '', //
popoverPosition: { x: 0, y: 0 } // Popover
popoverPosition: { x: 0, y: 0 }, // Popover
checkDateLine: [{
content: '现在',
// timestamp: '2018-04-12 20:46',
size: 'large',
type: 'primary',
icon: 'el-icon-more',
color: '#0bbd87'
}, {
content: '手动盘点全局',
timestamp: '2024-11-08 09:46',
size: 'large'
}, {
content: '计划盘点全局',
timestamp: '2024-11-08 09:46',
size: 'large'
}, {
content: '计划盘点全局计划盘点全局计划盘点全局',
timestamp: '2024-11-08 09:46'
}, {
content: '计划盘点全局',
timestamp: '2024-11-08 09:46',
size: 'large'
}, {
content: '计划盘点全局',
timestamp: '2024-11-08 09:46'
}, {
content: '计划盘点全局',
timestamp: '2024-11-08 09:46',
size: 'large'
}]
}
},
computed: {
@ -481,18 +530,18 @@ export default {
localStorage.setItem('dataScreenShelf', JSON.stringify(data))
},
showPopover(layerIndex, bookIndex, event) {
console.log('layerIndex', layerIndex)
console.log('bookIndex', bookIndex)
this.popoverIndex = { layer: layerIndex, book: bookIndex }
const bookElement = event.target //
const rect = bookElement.getBoundingClientRect() //
if (layerIndex === 0) {
this.popoverPosition = {
x: window.scrollX + rect.left + rect.width / 2,
x: window.scrollX + rect.left + rect.width / 2 - 40,
y: window.scrollY + rect.top + rect.height
}
} else {
this.popoverPosition = {
x: window.scrollX + rect.left + rect.width / 2,
x: window.scrollX + rect.left + rect.width / 2 - 40,
y: window.scrollY + rect.top + rect.height - 170
}
}
@ -543,6 +592,41 @@ export default {
}
}
.time-update-cont{
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 20px;
span.time-left-txt{
font-size: 14px;
}
.el-button{
padding:5px;
border: none;
}
.time-update-line{
display: none;
position: absolute;
top: 33px;
right: 20px;
z-index: 9999;
max-height: 645px;
padding: 20px 30px;
background-color: #fff;
border: 1px solid #e8f2ff;
border-radius: 10px;
-webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
overflow: hidden;
overflow-y: scroll;
}
}
.time-update-cont:hover .time-update-line {
display: block;
}
.gird-data-book{
position: relative;
height: 650px;
@ -718,101 +802,4 @@ export default {
}
}
}
::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;
}
.tag-item{
display: block;
// width: 50px;
height: 22px;
line-height: 20px;
padding: 0 4px;
border-radius: 3px;
font-size: 12px;
color: #A6ADB6;
border: 1px solid #E6E8ED;
background-color: #F3F5F9;
text-align: center;
&.tag-sort{
color: #FD7359 !important;
border-color: #FBC0B5 !important;
background-color: #FCECE9 !important;
}
&.tag-place{
color: #018BFF !important;
border-color: #9BD1FF !important;
background-color: #DCEDFD !important;
}
&.tag-all{
color: #0C0E1E;
border-color: #545B65 !important;
background-color: #E6E8ED !important;
}
}
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: 140px;
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>

34
src/views/visualCheck/checkManage/dataScreening/module/form.vue

@ -34,7 +34,7 @@
import crudStockTaskLog from '@/api/stockTaskLog/index'
import CRUD, { form } from '@crud/crud'
const defaultForm = { stockTypeName: '', stockType: null, stockBill: null, stockRegion: '', stockGridNum: null, stockGridNumName: null, stockRemarks: null, regionId: null, shelfId: null, gridShelf: null, gridId: null }
const defaultForm = { stockTypeName: '', stockType: null, stockBill: null, stockRegion: '', stockGridNum: null, stockGridNumName: null, totalGridNum: null, stockRemarks: null, regionId: null, shelfId: null, gridShelf: null, gridId: null }
export default {
name: 'DataForm',
mixins: [
@ -106,11 +106,13 @@ export default {
this.form.stockTypeName = stockTypeName
Promise.all([
crudStockTaskLog.FetchNewBillNo(),
crudStockTaskLog.FetchStockGirdNum(params)
]).then(([newBillNoRes, stockGridNumRes]) => {
crudStockTaskLog.FetchStockGirdNum(params),
crudStockTaskLog.FetchTotalGirdNum(params)
]).then(([newBillNoRes, stockGridNumRes, totalGirdNumRes]) => {
this.form.stockBill = newBillNoRes
this.form.stockGridNumName = stockGridNumRes + ' / 层位'
this.form.stockGridNum = stockGridNumRes
this.crud.form.stockGridNumName = stockGridNumRes + ' / ' + totalGirdNumRes + ' 层位'
this.crud.form.stockGridNum = stockGridNumRes
this.crud.form.totalGridNum = totalGirdNumRes
}).catch(error => {
console.error(error)
})
@ -127,17 +129,17 @@ export default {
delete this.form.stockGridNumName
delete this.form.stockTypeName
console.log('this.form', this.form)
// crudStockTaskLog.add(this.form).then((res) => {
// if (res.code !== 500) {
// this.$message({ message: '', type: 'success', offset: 8 })
// } else {
// this.$message({ message: res.message, type: 'error', offset: 8 })
// }
// this.handleCloseForm()
// // this.$emit('refresh')
// }).catch(err => {
// console.log(err)
// })
crudStockTaskLog.add(this.form).then((res) => {
if (res.code !== 500) {
this.$message({ message: '新增盘点成功', type: 'success', offset: 8 })
} else {
this.$message({ message: res.message, type: 'error', offset: 8 })
}
this.handleCloseForm()
// this.$emit('refresh')
}).catch(err => {
console.log(err)
})
} else {
return false
}

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

@ -53,16 +53,17 @@
</div>
<ul v-loading="listLoading" class="data-shelf-row" :style="rowStyle">
<!-- :class="{ active: i === cellIndex }" -->
<!-- { active: columnIndex === i % rackNum} -->
<li
v-for="(cell,i) in booShelfGrid"
:key="i"
class="data-shelf-cell"
:class="['data-shelf-cell',{'active': isActiveColumn(i)}]"
:style="cellStyle"
@dblclick="handleCellCurrent(cell,i)"
@mouseenter="showPopover(i)"
@mouseleave="hidePopover"
>
<!-- <span class="cell-name">{{ removeAreaPrefix(cell.gridName) }}</span> -->
<div class="mask" />
<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>
@ -76,13 +77,13 @@
:style="popoverStyles[i]"
trigger="manual"
>
<div slot="reference" class="popover-content">
<div slot="reference" class="popover-content-set">
<div class="tooltip-top">
<h4>层位概况</h4>
<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 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>
@ -95,14 +96,14 @@
</div>
<div class="venue-right">
<div class="lib-right-item lib-info">
<h4>架概况</h4>
<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>
<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>
@ -163,6 +164,7 @@ export default {
rackNum: 0,
swiperActiveIndex: 0,
cellIndex: null,
columnIndex: null,
swiperOptionContent: {
slidesPerView: 'auto',
on: {
@ -187,7 +189,8 @@ export default {
},
popoverIndex: null,
popoverVisible: [],
popoverStyles: []
popoverStyles: [],
activeColumns: {}
}
},
computed: {
@ -281,11 +284,7 @@ export default {
this.$refs.eform.setData(type)
},
removeAreaPrefix(gridNames) {
const index = gridNames.indexOf('区')
if (index !== -1) {
return gridNames.substring(index + 1)
}
return gridNames
return gridNames.replace(/\d*区|\d*层/g, '')
},
getInitShelfGridByShelfId(toward) {
this.listLoading = true
@ -311,6 +310,8 @@ export default {
const sortMethod = sortFunction[shelfType][floorType]
this.booShelfGrid = this[sortMethod](res)
console.log('booShelfGrid', this.booShelfGrid)
this.popoverVisible = Array(this.booShelfGrid.length).fill(false)
setTimeout(() => {
this.listLoading = false
@ -436,7 +437,7 @@ export default {
if (columnIndex === this.rackNum - 1) {
lastColumnIndexes.push(i)
//
// this.$set(this.popoverStyles, i, { position: 'absolute', left: '0', top: '20px' })
this.$set(this.popoverStyles, i, { position: 'absolute', left: '-180px', top: '20px' })
}
// 4
if (columnIndex === this.rackNum - 2) {
@ -445,10 +446,16 @@ export default {
// this.$set(this.popoverStyles, i, { position: 'absolute', left: '-20px', top: '20px' })
}
}
const columnIndex = index % this.rackNum
this.activeColumns[columnIndex] = true
},
isActiveColumn(index) {
const columnIndex = index % this.rackNum
return this.activeColumns[columnIndex] === true
},
hidePopover() {
this.activeColumns = {}
this.popoverIndex = null
// popover
this.popoverVisible.forEach((isVisible, index) => {
if (isVisible) {
this.$set(this.popoverVisible, index, false)
@ -565,8 +572,14 @@ export default {
line-height: 76px;
}
&.active{
color: #fff;
background-color: #0348F3;
.mask{
position: absolute;
top: 0;
left: 6px;
width: 98%;
height: 100%;
background-color: rgba(255,0,0,.3);
}
}
}
}
@ -575,57 +588,12 @@ export default {
position: absolute !important;
left: 60% !important;
top: 48px !important;
width: 300px;
height: 210px;
background:rgba(0,0,0,.8);
width: 250px;
// height: 210px;
background:rgba(0,0,0,1);
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>

26
src/views/visualCheck/checkManage/paramSetting/index.vue

@ -3,13 +3,24 @@
<div class="container-wrap">
<span class="right-top-line" />
<span class="left-bottom-line" />
<el-form ref="form" :rules="rules" :model="form" size="small" label-width="120px" style="display: flex; justify-content: flex-start;">
<el-form-item label="AI处理终端IP" prop="ip">
<el-input v-model="form.ip" placeholder="请输入IP地址,如:192.168.1.1" style="width: 300px;" />
</el-form-item>
<p style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置成功后方可执行视觉盘点任务该参数设置需要超级管理员权限授权</p>
<el-form ref="form" :rules="rules" :model="form" size="small" label-width="120px">
<el-row style="display: flex; justify-content: flex-start;">
<el-form-item label="AI处理终端IP" prop="ip">
<el-input v-model="form.ip" placeholder="请输入IP地址,如:192.168.1.1" style="width: 300px;" />
</el-form-item>
<p style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置成功后方可执行视觉盘点任务</p>
</el-row>
<el-row style="display: flex; justify-content: flex-start;">
<el-form-item label="层位占用上限" prop="number">
<el-input v-model="form.number" type="number" placeholder="请输入" style="width: 300px;" />
</el-form-item>
<p style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置成功后方可在倒架建议中给出正确的数据通常情况下上限为 50 </p>
</el-row>
</el-form>
<el-button style="margin-left: 30px;" :loading="crud.status.cu === 2" type="primary" @click="toVerify">保存</el-button>
<div>
<el-button style="margin-left: 30px;" :loading="crud.status.cu === 2" type="primary" @click="toVerify">保存</el-button>
<span style="line-height: 32px; margin-left: 20px; font-size: 12px;">设置需要超级管理员权限授权</span>
</div>
</div>
<el-dialog class="tip-dialog tip-middle-dialog" title="操作提示" :close-on-click-modal="false" :modal-append-to-body="false" append-to-body :visible.sync="verifyDialogVisible" :before-close="handleClose">
@ -75,6 +86,9 @@ export default {
rules: {
ip: [
{ required: true, message: 'AI处理终端IP不可为空', trigger: 'blur' }
],
number: [
{ required: true, message: '层位占用上限不可为空', trigger: 'blur' }
]
}
}

33
src/views/visualCheck/checkManage/statistic/reverseShelf/index.vue

@ -1,7 +1,7 @@
<template>
<div class="operateLog-main">
<Search :is-shelf-type="isShelfType" />
<div class="statistic-shelf">
<div v-loading="shelfLoading" class="statistic-shelf">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>架满列表上架率 100% - 80%</span>
@ -52,23 +52,10 @@ export default {
},
data() {
return {
shelfLoading: false,
isShelfType: 'reverse',
leftData: [
{ id: 0, percentage: 100, girdName: '一楼区域A001排01架1层' },
{ id: 0, percentage: 100, girdName: '一楼区域A001排01架1层' },
{ id: 1, percentage: 90, girdName: '一楼区域A001排01架1层' },
{ id: 2, percentage: 80, girdName: '一楼区域A001排01架1层' },
{ id: 3, percentage: 70, girdName: '一楼区域A001排01架1层' },
{ id: 3, percentage: 60, girdName: '一楼区域A001排01架1层' }
],
rightData: [
{ id: 0, percentage: 0, girdName: '一楼区域A001排01架1层' },
{ id: 1, percentage: 0, girdName: '一楼区域A001排01架1层' },
{ id: 2, percentage: 10, girdName: '一楼区域A001排01架1层' },
{ id: 3, percentage: 20, girdName: '一楼区域A001排01架1层' },
{ id: 4, percentage: 22, girdName: '一楼区域A001排01架1层' },
{ id: 5, percentage: 50, girdName: '一楼区域A001排01架1层' }
]
leftData: [],
rightData: []
}
},
computed: {
@ -77,12 +64,13 @@ export default {
])
},
created() {
this.getListAll()
// this.getListAll()
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
},
getListAll() {
this.shelfLoading = true
const sendRequest = (orderType) => {
const params = {
'orderType': orderType,
@ -105,9 +93,16 @@ export default {
console.log('所有请求结果:', results)
this.leftData = results[0]
this.rightData = results[1]
setTimeout(() => {
this.shelfLoading = false
}, 1000)
})
.catch((error) => {
console.error(error)
setTimeout(() => {
this.shelfLoading = false
}, 1000)
})
//
@ -135,7 +130,7 @@ export default {
.statistic-shelf{
display: flex;
justify-content: space-between;
height: calc(100vh - 284px);
height: calc(100vh - 286px);
.box-card{
width: calc(100% / 2);
height: 100%;

91
src/views/visualCheck/checkManage/statistic/search.vue

@ -20,11 +20,12 @@
<div slot="value-label" slot-scope="{ node }">{{ getAutoNameUnknown(node.label) }}</div>
</treeselect>
<el-button class="filter-item filter-search" size="mini" type="success" icon="el-icon-search" @click="crud.toQuery">搜索</el-button>
<el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery()">重置</el-button>
<!-- <el-button class="filter-item filter-refresh" size="mini" type="warning" icon="el-icon-refresh-left" @click="resetQuery()">重置</el-button> -->
</div>
<crudOperation>
<template v-slot:right>
<el-button :loading="crud.downloadLoading" size="mini" @click="doExport(crud.selections)">
<!-- :disabled="isShelfType === 'seq' && crud.data.length === 0" -->
<el-button :loading="crud.downloadLoading" size="mini" @click="doExport()">
<i class="iconfont icon-daochu" />
导出
</el-button>
@ -38,10 +39,9 @@ import { FetchRegionTree } from '@/api/deviceVI/index'
import CRUD, { header, crud } from '@crud/crud'
import crudOperation from '@crud/CRUD.operation'
import { mapGetters } from 'vuex'
import { exportFile } from '@/utils/index'
import { parseTime, saveAs, getBlob } from '@/utils/index'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import qs from 'qs'
export default {
components: { crudOperation, Treeselect },
mixins: [header(), crud()],
@ -55,7 +55,8 @@ export default {
return {
search: null,
regionOptions: [],
levelNumber: 4
levelNumber: 4,
defaultSelectedValue: null
}
},
computed: {
@ -67,10 +68,45 @@ export default {
created() {
FetchRegionTree().then(res => {
this.regionOptions = [this.transformData(res)]
console.log('regionOptions', this.regionOptions)
const targetNode = this.findRegionNode(this.regionOptions)
if (targetNode) {
console.log('targetNode', targetNode)
this.search = targetNode.id
this.handleSugList(targetNode)
}
}).catch(() => {
})
},
methods: {
findRegionNode(nodes) {
for (const node of nodes) {
if (node.regionId) {
return node
}
if (node.children && node.children.length > 0) {
const result = this.findRegionNode(node.children)
if (result) {
return result
}
}
}
return null
},
// findNodeWithoutFondsId(nodes) {
// for (const node of nodes) {
// if (!node.fondsId) {
// return node
// }
// if (node.children && node.children.length > 0) {
// const result = this.findNodeWithoutFondsId(node.children)
// if (result) {
// return result
// }
// }
// }
// return null
// },
getAutoNameUnknown(name) {
if (name.lastIndexOf('unknown') > -1) {
return name.split('(')[0]
@ -113,6 +149,9 @@ export default {
treeSelectInput(value) {
console.log(value)
const selectKey = value
this.handleSugList(selectKey)
},
handleSugList(selectKey) {
if (selectKey.hasOwnProperty('floorId')) {
this.crud.query.floorId = selectKey.id
} else if (selectKey.hasOwnProperty('regionId')) {
@ -133,8 +172,7 @@ export default {
this.crud.query.regionId = null
this.crud.toQuery()
},
doExport(data) {
console.log(data)
doExport() {
crud.downloadLoading = true
this.$confirm('此操作将导出所选数据' + '<span>你是否还要继续?</span>', '提示', {
confirmButtonText: '继续',
@ -142,24 +180,37 @@ export default {
type: 'warning',
dangerouslyUseHTMLString: true
}).then(() => {
const ids = []
data.forEach(val => {
ids.push(val.id)
})
const params = {
'ids': ids
}
if (this.isLogType === 'login') {
exportFile(this.baseApi + '/api/log/downloadLoginLog?' + qs.stringify(params, { indices: false }))
} else if (this.isLogType === 'operate') {
exportFile(this.baseApi + '/api/log/downloadLog?' + qs.stringify(params, { indices: false }))
const { floorId, regionId } = this.crud.query
const params = { floorId, regionId }
if (this.isShelfType === 'seq') {
const url = this.baseApi + '/api/stocktask-task/exportErrorProbaDesc' + '?' + new URLSearchParams(params).toString()
getBlob(url, (blob) => {
const fileName = '建议顺架-' + parseTime(new Date()) + '.xlsx'
saveAs(blob, fileName)
})
} else {
exportFile(this.baseApi + '/api/log/downloadErrorLog?' + qs.stringify(params, { indices: false }))
const url = this.baseApi + '/api/stocktask-task/exportSuggestTilting' + '?' + new URLSearchParams(params).toString()
getBlob(url, (blob) => {
const fileName = '建议倒架-' + parseTime(new Date()) + '.xlsx'
saveAs(blob, fileName)
})
// const params1 = { ...params, orderType: 1 }
// const url1 = this.baseApi + '/api/stocktask-task/exportSuggestTilting' + '?' + new URLSearchParams(params1).toString()
// getBlob(url1, (blob) => {
// const fileName = '-' + parseTime(new Date()) + '.xlsx'
// saveAs(blob, fileName)
// })
// const params2 = { ...params, orderType: 2 }
// const url2 = this.baseApi + '/api/stocktask-task/exportSuggestTilting' + '?' + new URLSearchParams(params2).toString()
// getBlob(url2, (blob) => {
// const fileName = '-' + parseTime(new Date()) + '.xlsx'
// saveAs(blob, fileName)
// })
}
}).catch(() => {
})
}
}
}
</script>

4
src/views/visualCheck/checkManage/statistic/seqShelf/index.vue

@ -18,11 +18,11 @@
<div>在架: {{ scope.row.onShelfNum }} / 错架{{ scope.row.onErrorShelfNum }} / {{ scope.row.prop }} </div>
</template>
</el-table-column>
<el-table-column prop="createTime" label="更新时间" min-width="180">
<!-- <el-table-column prop="createTime" label="更新时间" min-width="180">
<template slot-scope="scope">
<div>{{ scope.row.createTime | parseTime }}</div>
</template>
</el-table-column>
</el-table-column> -->
</el-table>
<pagination v-if="crud.data.length !== 0" />
</div>

6
src/views/visualCheck/venueDevice/bookshelf/index.vue

@ -162,8 +162,8 @@
</el-row>
<el-form-item label="倒架规则" prop="shelfRule">
<el-radio-group v-model="form.shelfRule" v-removeAriaHidden size="mini">
<el-radio :label="2">有序</el-radio>
<el-radio :label="1">无序</el-radio>
<el-radio :label="1">有序</el-radio>
<el-radio :label="2">无序</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="错架判断" prop="shelfErrorJudge">
@ -204,7 +204,7 @@ import defaultImg from '@/assets/images/system/default-img.jpg'
import MarkCover from '@/views/components/mark.vue'
import { fabric } from 'fabric'
const defaultForm = { id: null, floorName: null, floorId: null, regionName: null, rowType: 1, toward: 1, shelfRow: '', shelfName: '', shelfShelf: null, shelfFloor: null, startShelf: null, shelfType: 1, floorType: 1, shelfRule: 2, shelfErrorJudge: 2, signPoint: '' }
const defaultForm = { id: null, floorName: null, floorId: null, regionName: null, rowType: 1, toward: 1, shelfRow: '', shelfName: '', shelfShelf: null, shelfFloor: null, startShelf: null, shelfType: 1, floorType: 1, shelfRule: 1, shelfErrorJudge: 2, signPoint: '' }
export default {
name: 'Bookshelf',
components: { crudOperation, pagination, MarkCover },

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

@ -151,7 +151,7 @@
</el-dialog>
<!-- 查看监控视频 -->
<el-dialog class="view-video" ppend-to-body :close-on-click-modal="false" :modal-append-to-body="false" :visible="hkVideoVisible" title="查看监控视频" :before-close="handleClose">
<el-dialog class="view-video" append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :visible="hkVideoVisible" title="查看监控视频" :before-close="handleClose">
<span class="dialog-right-top" />
<span class="dialog-left-bottom" />
<div class="setting-dialog">

3
src/views/visualCheck/venueDevice/device/index.vue

@ -62,7 +62,8 @@
</el-button>
</template>
<template v-slot:right>
<el-button type="primary" size="mini" :disabled="activeRightBtn || crud.selections[0].shelfCount !== 0" @click="openBindShelf('')"><i class="iconfont icon-bangding" />书架绑定</el-button>
<!-- :disabled="activeRightBtn" -->
<el-button type="primary" size="mini" @click="openBindShelf('')"><i class="iconfont icon-bangding" />书架绑定</el-button>
</template>
</crudOperation>
</div>

Loading…
Cancel
Save