图书馆综合管理系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1142 lines
39 KiB

6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
5 months ago
5 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
5 months ago
6 months ago
5 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
5 months ago
  1. <template>
  2. <div class="app-container">
  3. <div class="venue-header dataScreening-header">
  4. <h4><i class="iconfont icon-shuju" />架位总览</h4>
  5. <div class="bookshelf-area">
  6. <!-- <span class="bookshelf-area">{{ floorName }} - {{ regionName }} - {{ gridRow +'排' }}</span> -->
  7. <router-link :to="{ path: '/check/check/dataScreening', query: {floorTabIndex: floorTabIndex }}">
  8. {{ floorName }}
  9. </router-link>
  10. <span>/</span>
  11. <router-link :to="{ path: '/dataScreening/regions', query: {regionTabIndex: regionTabIndex }}">
  12. {{ regionName }}
  13. </router-link>
  14. <span>/</span>
  15. <router-link :to="{ path: '/dataScreening/shelf', query: {tabIndex: tabIndex }}">
  16. {{ gridRow +'排' }}
  17. </router-link>
  18. <div class="double-click-btn"><span>点击左侧位置返回</span></div>
  19. </div>
  20. <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
  21. </div>
  22. <div class="venue-content">
  23. <div class="tab-content">
  24. <span class="right-top-line" />
  25. <span class="left-bottom-line" />
  26. <div class="gird-data-header">
  27. <ul class="tab-nav">
  28. <li v-for="(item,index) in tabListData" :key="index" class="active-tab-nav">{{ item.name }}<i /></li>
  29. <!-- 最右侧装饰img -->
  30. <span class="tab-right-img" />
  31. </ul>
  32. <!-- <div class="tag-info">
  33. <p class="tag-sort">错序<i class="iconfont icon-zhuangtai2" />1</p>
  34. <p class="tag-place">错架<i class="iconfont icon-zhuangtai2" />1</p>
  35. <p class="tag-all">在架<i class="iconfont icon-zhuangtai2" />20</p>
  36. </div> -->
  37. <div v-if="checkDateLine.length !== 0" class="time-update-cont">
  38. <span class="time-left-txt">最后更新时间</span>
  39. <!-- <el-button class="time-btn-txt">{{ checkDateLine[2].endTime }}</el-button> -->
  40. <el-button>{{ checkDateLine[timeIndex].stockType === 0 ? '现在' : checkDateLine[timeIndex].endTime }}</el-button>
  41. <div class="time-update-line">
  42. <ul class="el-timeline">
  43. <li v-for="(activity, index) in checkDateLine" :key="index" class="el-timeline-item" @click="handleHistory(activity,index)">
  44. <div class="el-timeline-item__tail" />
  45. <div class="el-timeline-item__node el-timeline-item__node--normal" :style="index === timeIndex ? 'background-color: rgb(11, 189, 135);' : ''">
  46. <i v-if="index === timeIndex" class="el-timeline-item__icon el-icon-more" />
  47. </div>
  48. <div class="el-timeline-item__wrapper">
  49. <div class="el-timeline-item__content">
  50. {{ computedStockType(activity.stockType) }}
  51. </div>
  52. <div class="el-timeline-item__timestamp is-bottom">
  53. {{ activity.endTime }}
  54. </div>
  55. </div>
  56. </li>
  57. </ul>
  58. </div>
  59. </div>
  60. <crudOperation :permission="permission">
  61. <template v-slot:middle>
  62. <el-select v-model="layerVal" size="small" placeholder="架位" class="filter-item" style="width: 100px; margin-right: 10px;" @change="changeShelfGetGrid">
  63. <el-option v-for="item in rackOptions" :key="item.id" :label="item.name" :value="item.id" />
  64. </el-select>
  65. <el-button v-permission="permission.add" class="check-btn" size="mini" @click="toAdd(5)">
  66. <i class="iconfont icon-shengchengpandiandan" />
  67. 架位盘点
  68. </el-button>
  69. </template>
  70. <template v-slot:right>
  71. <!-- @click="doExport(crud.selections)" -->
  72. <el-button :loading="crud.downloadLoading" size="mini" @click="doExport(3)">
  73. <i class="iconfont icon-daochu" />
  74. 导出
  75. </el-button>
  76. </template>
  77. </crudOperation>
  78. </div>
  79. <div v-loading="shelfAllGridDataLoading" class="gird-data-book">
  80. <div v-for="(item,index) in shelfAllGridData" :key="index" class="gird-layer">
  81. <span class="gird-left-line" />
  82. <span class="gird-right-line" />
  83. <div class="layer-left">
  84. <div class="layer-left-book">
  85. <div
  86. v-for="(book,i) in item.books"
  87. :key="i"
  88. :class="['book-item', { 'red-active' : book.bookStatus === '错架'} ,{ 'blue-active' : book.bookStatus === '错序'}]"
  89. @mouseenter="showPopover(index, i, $event)"
  90. @mouseleave="hidePopover"
  91. >
  92. <span class="book-name">{{ book.bookName }}</span>
  93. </div>
  94. </div>
  95. </div>
  96. <div class="layer-right-handle">
  97. <div class="layer-info-header">
  98. <h4>{{ item.gridName }}</h4>
  99. <!-- <span>2024-11-28 09:46</span> -->
  100. </div>
  101. <div class="layer-right-content">
  102. <div class="layer-tag-info">
  103. <div class="tag-item tag-sort">错序<i class="iconfont icon-zhuangtai2" /><p>{{ baseStockData.length !==0 && baseStockData[index].errorOrderNum }}</p><span>{{ baseStockData.length !==0 && baseStockData[index].errorOrderProbo }}</span></div>
  104. <div class="tag-item tag-place">错架<i class="iconfont icon-zhuangtai2" /><p>{{ baseStockData.length !==0 &&baseStockData[index].errorShelfNum }}</p><span>{{ baseStockData.length !==0 && baseStockData[index].errorShelfProbo }}</span></div>
  105. <div class="tag-item tag-all">在架<i class="iconfont icon-zhuangtai2" /><p>{{ baseStockData.length !==0 && baseStockData[index].onShelfNum }}</p></div>
  106. </div>
  107. <div class="layer-handle">
  108. <el-button size="mini" @click="handleDetail(item)">
  109. <i class="iconfont icon-xiaowenjian" />
  110. 详情
  111. </el-button>
  112. <el-button size="mini" class="check-btn" @click="toAdd(6,item)">
  113. <i class="iconfont icon-shengchengpandiandan" />
  114. 盘点
  115. </el-button>
  116. </div>
  117. </div>
  118. </div>
  119. </div>
  120. <!-- popover -->
  121. <div
  122. v-if="popoverIndex !== null"
  123. class="popover-external-set"
  124. :style="popoverStyle"
  125. >
  126. <div class="popover-content-set">
  127. <div class="tooltip-top">
  128. <h4>{{ shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].bookName }}</h4>
  129. <span v-if="shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].bookStatus === '错序'" class="tag-item tag-place">错序</span>
  130. <span v-if="shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].bookStatus === '错架'" class="tag-item tag-sort">错架</span>
  131. </div>
  132. <ul>
  133. <li><p>索书号</p><em>{{ shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].sortmark }}</em></li>
  134. <li><p>ISBN</p><em>{{ shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].isbn }}</em></li>
  135. <li><p>著者</p><em>{{ shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].bookAuthor }}</em></li>
  136. <li><p>出版社</p><em>{{ shelfAllGridData[popoverIndex.layer].books[popoverIndex.book].bookPublish }}</em></li>
  137. </ul>
  138. </div>
  139. </div>
  140. </div>
  141. </div>
  142. </div>
  143. <!-- 详情 -->
  144. <el-dialog class="dialog-grid-detail" append-to-body :close-on-click-modal="false" :visible.sync="detailVisible" :title="detailCurrent.gridName +'- 详情'" @close="handleCloseDialog">
  145. <span class="dialog-right-top" />
  146. <span class="dialog-left-bottom" />
  147. <div class="setting-dialog">
  148. <div class="detail-tab tab-content">
  149. <!-- <el-button v-if="detailCurrent && detailCurrent.onShelfNum" class="check-view-img" size="mini" @click="handleViewImg">
  150. <i class="iconfont icon-sulan" />
  151. 盘点照片
  152. </el-button> -->
  153. <div v-if="detailCurrent && detailCurrent.onShelfNum" style="height: 260px; background-color: #ccc; overflow: hidden; position: relative;" @dblclick="handleViewImg" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseleave="onMouseUp" @mouseup="onMouseUp">
  154. <img
  155. ref="image"
  156. style="display:block; width: 100%;cursor: grab;"
  157. :src="bigImg"
  158. alt=""
  159. @wheel="onWheel"
  160. >
  161. <span style="position: absolute; top: 0; right: 0; padding: 4px 6px; color: #fff; background-color: rgba(3,72,243,.8); border-radius: 4px;">双击可查看所有图片</span>
  162. <el-button v-if="shouldShowResetButton" style="position: absolute; bottom: 10px; right: 10px; background-color: #fff; color: rgba(3,72,243,1); font-weight: bold; padding: 4px;" @click="resetImage"><i class="iconfont icon-shuaxin" style="font-size: 12px;" />重置</el-button>
  163. </div>
  164. <ul class="tab-nav">
  165. <li :class="{'active-tab-nav': tabdialogIndex === 0}" @click="changeDialogTab(0)">图书列表</li>
  166. <el-button class="compare-btn" @click="isCompare = !isCompare">
  167. <i :class="['iconfont', !isCompare ? 'icon-zhongxinjiance':'icon-huifu' ]" />{{ !isCompare ? '数据比对' : '返回列表' }}</el-button>
  168. </ul>
  169. <el-table
  170. v-if="!isCompare"
  171. ref="table"
  172. class="archives-table"
  173. :data="detailTable"
  174. style="width: 100%;"
  175. height="calc(100vh - 560px)"
  176. >
  177. <el-table-column type="index" label="序号" width="55" align="center" />
  178. <el-table-column prop="bookName" label="题名" min-width="110" show-overflow-tooltip />
  179. <el-table-column prop="isbn" label="ISBN" />
  180. <el-table-column prop="sortmark" label="索书号" />
  181. <el-table-column prop="barcode" label="条码" />
  182. <el-table-column prop="floorName" label="所在位置" min-width="160">
  183. <template slot-scope="scope">
  184. <span>
  185. {{ getLocation(scope.row) }}
  186. </span>
  187. </template>
  188. </el-table-column>
  189. <el-table-column prop="bookStatus" label="盘点结果" align="center">
  190. <template slot-scope="scope">
  191. <span v-if="scope.row.bookStatus === '未知'" class="row-state row-warehousing">未知</span>
  192. <span v-if="scope.row.bookStatus === '在架'" class="row-state row-binding state-active">在架</span>
  193. <span v-if="scope.row.bookStatus === '错架'" class="row-state row-lending state-active">错架</span>
  194. <span v-if="scope.row.bookStatus === '错序'" class="row-state row-physical state-active">错序</span>
  195. </template>
  196. </el-table-column>
  197. </el-table>
  198. <swiper
  199. v-else
  200. ref="swiperList"
  201. class="swiper-title layerShelf-swiper"
  202. :options="swiperListOptions"
  203. :auto-update="true"
  204. :auto-destroy="true"
  205. >
  206. <swiper-slide
  207. v-for="(item,index) in detailTable"
  208. :key="index"
  209. ref="swiperSlideItem"
  210. class="swiper-slide-title"
  211. >
  212. <div class="book-name" :class="[{ 'red-active' : item.bookStatus === '错架'} ,{ 'blue-active' : item.bookStatus === '错序'}]">
  213. <span>{{ index+1 }}</span>
  214. {{ item.bookName }}
  215. </div>
  216. </swiper-slide>
  217. </swiper>
  218. </div>
  219. </div>
  220. </el-dialog>
  221. <el-dialog class="gird-img-detail" append-to-body :close-on-click-modal="false" :visible.sync="detailImgVisible">
  222. <span class="dialog-right-top" />
  223. <span class="dialog-left-bottom" />
  224. <div class="gird-img-button">
  225. <el-button size="mini" :loading="downImgLoading" :disabled="downImgLoading" @click="handleDownloadImg">
  226. <i class="iconfont icon-xiazai" />
  227. 下载
  228. </el-button>
  229. <el-button size="mini" @click="handleCloseImgDialog">
  230. <i class="iconfont icon-guanbixiao" />
  231. 关闭
  232. </el-button>
  233. </div>
  234. <div class="setting-dialog">
  235. <el-carousel ref="carousel" indicator-position="outside" :autoplay="false" @setActiveItem="setActiveItem">
  236. <el-carousel-item v-for="item in bookImgData" :key="item">
  237. <img :src="item" alt="">
  238. </el-carousel-item>
  239. </el-carousel>
  240. </div>
  241. </el-dialog>
  242. <eForm ref="eform" />
  243. <exportForm ref="exportform" export-type="grid" />
  244. </div>
  245. </template>
  246. <script>
  247. import { FetchInitStockInfo, FetchInitBookDetailsByGrids, FetchBillByShelfIdAndGridShelf, FetchIsGoodcutByBillNoAndGridId, FetchShowByBillIdAndShelfIdAndGridShelf } from '@/api/stockTask/index'
  248. import { dataScreeningCrud } from '@/views/visualCheck/mixins/index'
  249. import { FetchBookShelfDetails, FetchShelfGridByShelfIdAndGridShelf } from '@/api/shelf/index'
  250. import crudRegion from '@/api/area/index'
  251. import CRUD, { presenter, header, crud } from '@crud/crud'
  252. import crudOperation from '@crud/CRUD.operation'
  253. import { mapGetters } from 'vuex'
  254. import eForm from './module/form'
  255. import exportForm from './module/export'
  256. import { parseTime, saveAs, getBlob } from '@/utils/index'
  257. import { swiper, swiperSlide } from 'vue-awesome-swiper'
  258. import 'swiper/dist/css/swiper.css'
  259. export default {
  260. name: 'DataScreening',
  261. components: { crudOperation, eForm, exportForm, swiper, swiperSlide },
  262. cruds() {
  263. return CRUD({ title: '架位盘点', url: 'api/libraryRegion/initLibraryRegionList', crudMethod: { ...crudRegion }, sort: [], optShow: {
  264. add: false,
  265. edit: false,
  266. del: false,
  267. download: false,
  268. group: false,
  269. reset: false
  270. },
  271. queryOnPresenterCreated: false
  272. })
  273. },
  274. mixins: [presenter(), header(), crud(), dataScreeningCrud],
  275. data() {
  276. return {
  277. activeIndex: 0,
  278. downImgLoading: false,
  279. detailVisible: false,
  280. detailImgVisible: false,
  281. detailTable: [],
  282. detailCurrent: {},
  283. tabdialogIndex: 0,
  284. listLoading: false,
  285. tabIndex: 0,
  286. floorTabIndex: 0,
  287. regionTabIndex: 0,
  288. floorName: null,
  289. floorId: null,
  290. regionName: null,
  291. regionId: null,
  292. gridRow: null,
  293. gridShelf: null,
  294. bookShelfDetails: null,
  295. booShelfGrid: null,
  296. shelfAllGridData: [],
  297. layerNum: 0,
  298. rackNum: 0,
  299. bookNum: 46,
  300. layerVal: null,
  301. rackOptions: [],
  302. tabListData: [],
  303. permission: {
  304. add: ['admin', 'floor:add'],
  305. edit: ['admin', 'floor:edit'],
  306. del: ['admin', 'floor:del']
  307. },
  308. popoverIndex: null,
  309. popoverVisible: [],
  310. popoverStyles: [],
  311. currentBookName: '', // 当前书籍的名称
  312. popoverPosition: { x: 0, y: 0 }, // Popover的位置
  313. checkDateLine: [],
  314. baseStockData: [],
  315. shelfAllGridDataLoading: false,
  316. billNoImg: null,
  317. bookImgData: [],
  318. bigImg: '',
  319. timeIndex: 0,
  320. gridName: '',
  321. getGridToward: 1,
  322. currentScale: 1, // 当前缩放比例
  323. isDragging: false, // 是否正在拖拽图片
  324. startX: 0, // 拖拽起始点x坐标
  325. startY: 0, // 拖拽起始点y坐标
  326. translateX: 0, // 图片平移x方向距离
  327. translateY: 0, // 图片平移y方向距离
  328. dragSpeed: 0.3, // 拖拽速度
  329. zoomSpeed: 0.1, // 控制缩放速度
  330. maxScale: 5, // 最大缩放值
  331. minScale: 0.1, // 最小缩放值
  332. swiperListOptions: {
  333. slidesPerView: 'auto',
  334. freeMode: true
  335. },
  336. isCompare: false,
  337. shouldShowResetButton: false
  338. }
  339. },
  340. computed: {
  341. ...mapGetters([
  342. 'user',
  343. 'baseApi'
  344. ]),
  345. swiperList() {
  346. return this.$refs.swiperList.$el.swiper
  347. },
  348. cellStyle: function() {
  349. const h = '76px'
  350. const w = '100%/' + this.rackNum
  351. return { width: `calc(${w} )`, height: `calc(${h})` }
  352. },
  353. popoverStyle() {
  354. return {
  355. top: `${this.popoverPosition.y - 300}px`, // 鼠标的Y坐标偏移10px
  356. left: `${this.popoverPosition.x - 240}px`, // 鼠标的X坐标偏移10px
  357. position: 'absolute'
  358. }
  359. }
  360. },
  361. async created() {
  362. this.initData()
  363. },
  364. methods: {
  365. [CRUD.HOOK.beforeRefresh]() {
  366. },
  367. [CRUD.HOOK.afterRefresh](crud) {
  368. },
  369. // 提交前的验证
  370. [CRUD.HOOK.afterValidateCU](crud) {
  371. return true
  372. },
  373. computedStockType(stockType) {
  374. switch (stockType) {
  375. case 1:
  376. return '全量盘点'
  377. case 2:
  378. return '区域盘点'
  379. case 3:
  380. return '计划盘点'
  381. case 4:
  382. return '书架盘点'
  383. case 5:
  384. return '架位盘点'
  385. case 6:
  386. return '层位盘点'
  387. default:
  388. return '现在'
  389. }
  390. },
  391. initData() {
  392. if (localStorage.getItem('dataScreenFloorTableIndex')) {
  393. this.floorTabIndex = localStorage.getItem('dataScreenFloorTableIndex')
  394. }
  395. if (localStorage.getItem('dataScreenRegionTableIndex')) {
  396. this.regionTabIndex = localStorage.getItem('dataScreenRegionTableIndex')
  397. }
  398. if (localStorage.getItem('dataScreenShelf')) {
  399. const dataScreenShelf = JSON.parse(localStorage.getItem('dataScreenShelf'))
  400. this.floorName = dataScreenShelf.floorName
  401. this.regionName = dataScreenShelf.regionName
  402. this.gridName = dataScreenShelf.gridName
  403. this.gridRow = dataScreenShelf.gridRow
  404. this.gridShelf = dataScreenShelf.gridShelf
  405. if (localStorage.getItem('dataScreenShelfAllGrid')) {
  406. this.shelfAllGridData = JSON.parse(localStorage.getItem('dataScreenShelfAllGrid'))
  407. }
  408. this.updateParts(dataScreenShelf.gridName)
  409. // 单面/双面
  410. this.tabListData = [{ name: dataScreenShelf.regionName + ' - ' + this.removeAreaPrefix(dataScreenShelf.gridName) }]
  411. // dataScreenShelf.rowType === 1
  412. // ? dataScreenShelf.toward === 1
  413. // ? [{ name: 'A面' }]
  414. // : [{ name: 'B面' }]
  415. // : [{ name: 'A面' }, { name: 'B面' }]
  416. this.tabIndex = dataScreenShelf.toward - 1
  417. FetchBookShelfDetails({ 'shelfId': dataScreenShelf.shelfId }).then(res => {
  418. this.layerNum = res.shelfFloor
  419. this.rackNum = res.shelfShelf
  420. this.floorId = res.floorId
  421. this.regionId = res.regionId
  422. this.bookShelfDetails = res
  423. this.rackOptions = []
  424. for (let i = 1; i <= this.rackNum; i++) {
  425. this.rackOptions.push({ id: i, name: `0${i}` })
  426. }
  427. this.layerVal = parseInt(this.gridShelf) || ''
  428. this.getInitStockInfo(this.shelfAllGridData)
  429. this.getInitBookDetailsByGrids(this.shelfAllGridData)
  430. this.getBillByShelfIdAndGridShelf(this.shelfAllGridData)
  431. }).catch(() => {
  432. })
  433. }
  434. },
  435. removeQUPrefix(gridNames) {
  436. const index = gridNames.indexOf('区')
  437. if (index !== -1) {
  438. return gridNames.substring(index + 1)
  439. }
  440. return gridNames
  441. },
  442. removeAreaPrefix(gridNames) {
  443. const index = gridNames.indexOf('面')
  444. if (index !== -1) {
  445. return gridNames.substring(0, index + 1)
  446. }
  447. return gridNames
  448. },
  449. getLocation(row) {
  450. const parts = []
  451. if (row.floorName) {
  452. parts.push(row.floorName)
  453. }
  454. if (row.regionName) {
  455. parts.push(row.regionName)
  456. }
  457. if (row.gridName) {
  458. parts.push(row.gridName)
  459. }
  460. return parts.length > 0 ? parts.join('-') : '-'
  461. },
  462. getBillByShelfIdAndGridShelf(data) {
  463. const params = {
  464. 'gridShelf': data[0].gridShelf,
  465. 'ShelfId': data[0].shelfId,
  466. 'size': 5
  467. }
  468. FetchBillByShelfIdAndGridShelf(params).then(res => {
  469. if (res !== null) {
  470. this.checkDateLine = res.sort((a, b) => {
  471. return new Date(b.endTime) - new Date(a.endTime)
  472. })
  473. this.checkDateLine.unshift({
  474. stockType: 0,
  475. icon: 'el-icon-more',
  476. color: '#0bbd87'
  477. })
  478. this.billNoImg = this.checkDateLine[this.timeIndex].stockType === 0 ? this.checkDateLine[1].stockBill : this.checkDateLine[this.timeIndex].stockBill
  479. } else {
  480. this.checkDateLine = []
  481. }
  482. }).catch(() => {
  483. })
  484. },
  485. async getInitStockInfo(data) {
  486. const promises = data.map(item => {
  487. const params = {
  488. 'floorId': this.floorId,
  489. 'regionId': this.regionId,
  490. 'shelfId': item.shelfId,
  491. 'gridId': item.id
  492. }
  493. return FetchInitStockInfo(params)
  494. })
  495. const results = await Promise.all(promises)
  496. if (!Array.isArray(this.baseStockData)) {
  497. this.baseStockData = []
  498. }
  499. this.baseStockData = this.baseStockData.concat(results)
  500. },
  501. getInitBookDetailsByGrids(data) {
  502. const ids = data.map(item => item.id)
  503. const params = {
  504. 'grids': ids.join(',')
  505. }
  506. FetchInitBookDetailsByGrids(params).then(res => {
  507. this.shelfAllGridData.forEach((item) => {
  508. const gridId = item.id
  509. if (res.hasOwnProperty(gridId)) {
  510. this.$set(item, 'books', res[gridId])
  511. }
  512. })
  513. }).catch(() => {
  514. })
  515. },
  516. toAdd(type, item) {
  517. if (type === 5) {
  518. // this.$refs.eform.formVisible = true
  519. this.$refs.eform.form.shelfId = this.bookShelfDetails.id
  520. this.$refs.eform.form.toward = this.getGridToward
  521. this.$refs.eform.form.gridShelf = this.gridShelf
  522. this.$refs.eform.form.stockRegion = this.floorName + '-' + this.regionName + '-' + this.bookShelfDetails.shelfName + this.gridShelf + '架'
  523. } else {
  524. // if (item.isCheck) {
  525. // this.$refs.eform.formVisible = true
  526. this.$refs.eform.form.shelfId = null
  527. this.$refs.eform.form.gridShelf = null
  528. this.$refs.eform.form.gridId = item.id
  529. this.$refs.eform.form.toward = this.getGridToward
  530. this.$refs.eform.form.stockRegion = this.removeQUPrefix(item.gridName)
  531. this.$refs.eform.gridStockRegion = this.floorName + '-' + this.regionName + '-' + this.removeQUPrefix(item.gridName)
  532. // } else {
  533. // this.$message({ message: '当前层位不可盘点', type: 'error', offset: 8 })
  534. // }
  535. }
  536. this.$refs.eform.setData(type, item)
  537. },
  538. doExport(type) {
  539. this.$refs.exportform.formExportVisible = true
  540. this.$refs.exportform.type = 3
  541. this.$refs.exportform.params = {
  542. // 'floorId': this.floorId,
  543. // 'regionId': this.regionId,
  544. 'shelfId': this.bookShelfDetails.id
  545. }
  546. },
  547. handleCellCurrent(item, index) {
  548. this.cellIndex = index
  549. this.cellInfo = {
  550. id: item.id,
  551. gridName: item.gridName,
  552. startSortmark: item.startSortmark,
  553. endSortmark: item.endSortmark,
  554. cameraId: item.cameraId,
  555. check: item.isCheck,
  556. order: item.isOrder
  557. }
  558. this.handleToGrids(this.cellInfo)
  559. },
  560. handleDetail(item) {
  561. this.detailVisible = true
  562. this.detailTable = item.books
  563. this.detailCurrent = item
  564. if (this.detailCurrent.onShelfNum) {
  565. this.bigImg = `${this.baseApi}/api/fileRelevant/getImg?imgType=1&imgId=/${this.libcode}/${this.billNoImg}/${this.detailCurrent.gridCode}/img_result/result_LSD_compressed.jpg`
  566. } else {
  567. this.bigImg = ''
  568. }
  569. },
  570. setActiveItem(index) {
  571. this.$refs.carousel.setActiveItem(index)
  572. },
  573. // 鼠标按下事件处理函数
  574. onMouseDown(e) {
  575. e.preventDefault()
  576. this.isDragging = true
  577. this.startX = e.clientX
  578. this.startY = e.clientY
  579. this.$refs.image.style.cursor = 'grabbing'
  580. },
  581. // 鼠标移动事件处理函数
  582. onMouseMove(e) {
  583. if (!this.isDragging) return
  584. const deltaX = (e.clientX - this.startX) * this.dragSpeed
  585. const deltaY = (e.clientY - this.startY) * this.dragSpeed
  586. this.translateX += deltaX
  587. this.translateY += deltaY
  588. this.$refs.image.style.transform = `scale(${this.currentScale}) translate(${this.translateX}px, ${this.translateY}px)`
  589. this.startX = e.clientX
  590. this.startY = e.clientY
  591. this.shouldShowResetButton = true
  592. },
  593. // 鼠标松开事件处理函数
  594. onMouseUp() {
  595. this.isDragging = false
  596. this.$refs.image.style.cursor = 'grab'
  597. },
  598. // 鼠标滚轮事件处理函数
  599. onWheel(e) {
  600. e.preventDefault()
  601. const delta = e.deltaY > 0 ? -1 : 1
  602. this.currentScale = Math.min(this.maxScale, Math.max(this.minScale, this.currentScale + delta * this.zoomSpeed))
  603. this.$refs.image.style.transform = `scale(${this.currentScale}) translate(${this.translateX}px, ${this.translateY}px)`
  604. this.shouldShowResetButton = true
  605. },
  606. // 重置图片缩放和移动
  607. resetImage() {
  608. this.currentScale = 1
  609. this.translateX = 0
  610. this.translateY = 0
  611. this.$refs.image.style.transform = 'scale(1) translate(0, 0)'
  612. this.shouldShowResetButton = false
  613. },
  614. handleViewImg() {
  615. // /PD20250102001/040011011/img_result/result_cut_1.jpg
  616. // /PD20250102001/040011011/img_result/result_cut_2.jpg
  617. // /PD20250102001/040011011/img_result/result_cut_3.jpg
  618. // http://192.168.99.67:12010/api/fileRelevant/getImg?imgType=1&imgId=/ceshi111/1_1_book_spine-0.png
  619. // http://192.168.99.67:12010/api/fileRelevant/getImg?imgType=1&imgId=/1501/PD20250108013/010011015/img_result/result_LSD.jpg
  620. // http://192.168.99.67:12010/api/fileRelevant/getImg?imgType=1&imgId=/1501/PD20250108013/010011015/img_result/result_cut_1_compressed.jpg
  621. this.bookImgData = []
  622. this.detailImgVisible = true
  623. const params = {
  624. 'billNo': this.billNoImg,
  625. 'gridId': this.detailCurrent.id
  626. }
  627. FetchIsGoodcutByBillNoAndGridId(params)
  628. .then(res => {
  629. const baseUrl = `${this.baseApi}/api/fileRelevant/getImg?imgType=1&imgId=/${this.libcode}/${this.billNoImg}/${this.detailCurrent.gridCode}/img_result/`
  630. const commonImgs = [
  631. `${baseUrl}result_LSD_compressed.jpg`,
  632. `${baseUrl}result_cut_1_compressed.jpg`
  633. ]
  634. this.$refs.carousel.setActiveItem(0)
  635. if (res === null) {
  636. this.bookImgData = commonImgs
  637. } else if (res === true) {
  638. this.bookImgData = [...commonImgs, `${baseUrl}result_cut_2_compressed.jpg`]
  639. } else if (res === false) {
  640. this.bookImgData = [...commonImgs, `${baseUrl}result_cut_2_compressed.jpg`, `${baseUrl}result_cut_3_compressed.jpg`]
  641. }
  642. })
  643. .catch(error => {
  644. console.error(error)
  645. })
  646. },
  647. handleDownloadImg() {
  648. this.downImgLoading = true
  649. const idsArray = []
  650. for (const url of this.bookImgData) {
  651. const startIndex = url.indexOf('imgId=') + 'imgId='.length
  652. const endIndex = url.length
  653. idsArray.push(url.slice(startIndex, endIndex))
  654. }
  655. // 下载桶图片
  656. const params = {
  657. 'imgIds': idsArray
  658. }
  659. const url = this.baseApi + '/api/fileRelevant/uploadImgs' + '?' + new URLSearchParams(params).toString()
  660. getBlob(url, (blob) => {
  661. const fileName = this.billNoImg + '-' + parseTime(new Date()) + '.zip'
  662. saveAs(blob, fileName)
  663. this.downImgLoading = false
  664. })
  665. },
  666. handleCloseDialog() {
  667. this.detailVisible = false
  668. this.isCompare = false
  669. if (this.shouldShowResetButton) {
  670. this.resetImage()
  671. }
  672. },
  673. handleCloseImgDialog() {
  674. this.detailImgVisible = false
  675. this.activeIndex = 0
  676. },
  677. handleToGrids(data) {
  678. this.$router.push({ path: '/dataScreening/gird' })
  679. localStorage.setItem('dataScreenShelf', JSON.stringify(data))
  680. },
  681. showPopover(layerIndex, bookIndex, event) {
  682. this.popoverIndex = { layer: layerIndex, book: bookIndex }
  683. const bookElement = event.target // 获取书籍项元素
  684. const rect = bookElement.getBoundingClientRect() // 获取边界
  685. if (layerIndex === 0) {
  686. this.popoverPosition = {
  687. x: window.scrollX + rect.left + rect.width / 2 - 40,
  688. y: window.scrollY + rect.top + rect.height
  689. }
  690. } else {
  691. this.popoverPosition = {
  692. x: window.scrollX + rect.left + rect.width / 2 - 40,
  693. y: window.scrollY + rect.top + rect.height - 170
  694. }
  695. }
  696. },
  697. hidePopover() {
  698. this.popoverIndex = null
  699. // 隐藏所有的popover
  700. // this.popoverVisible.forEach((isVisible, index) => {
  701. // if (isVisible) {
  702. // this.$set(this.popoverVisible, index, false)
  703. // }
  704. // })
  705. },
  706. changeDialogTab(index) {
  707. this.tabdialogIndex = index
  708. },
  709. updateParts(gridName) {
  710. const parts = gridName.match(/(\d+)区(\d+)排([A-Za-z])面(\d+)架(\d+)层/)
  711. if (parts) {
  712. this.getGridShelf = parts[4]
  713. this.getGridFloor = parts[5]
  714. const toward = parts[3]
  715. if (toward === 'A') {
  716. this.getGridToward = 1
  717. } else if (toward === 'B') {
  718. this.getGridToward = 2
  719. }
  720. }
  721. },
  722. changeShelfGetGrid(val) {
  723. this.updateParts(this.gridName)
  724. this.shelfAllGridDataLoading = true
  725. const params = {
  726. 'gridShelf': '0' + val,
  727. 'shelfId': this.bookShelfDetails.id,
  728. 'toward': this.getGridToward,
  729. 'floorType': this.bookShelfDetails.floorType
  730. }
  731. FetchShelfGridByShelfIdAndGridShelf(params).then(res => {
  732. this.shelfAllGridData = []
  733. this.shelfAllGridData = res
  734. this.getInitStockInfo(this.shelfAllGridData)
  735. this.getInitBookDetailsByGrids(this.shelfAllGridData)
  736. this.shelfAllGridDataLoading = false
  737. }).catch(() => {
  738. })
  739. },
  740. handleHistory(item, index) {
  741. this.shelfAllGridDataLoading = true
  742. this.timeIndex = index
  743. this.billNoImg = this.checkDateLine[this.timeIndex].stockType === 0 ? this.checkDateLine[1].stockBill : this.checkDateLine[this.timeIndex].stockBill
  744. if (item.stockType === 0) {
  745. this.initData()
  746. setTimeout(() => {
  747. this.shelfAllGridDataLoading = false
  748. }, 500)
  749. } else {
  750. const params = {
  751. 'gridShelf': '0' + this.layerVal,
  752. 'ShelfId': this.bookShelfDetails.id,
  753. 'toward': this.bookShelfDetails.toward,
  754. 'billId': item.stockBill
  755. }
  756. FetchShowByBillIdAndShelfIdAndGridShelf(params).then(res => {
  757. this.shelfAllGridData.forEach((item) => {
  758. console.log(item.id)
  759. const gridId = item.id
  760. if (res.hasOwnProperty(gridId)) {
  761. this.$set(item, 'books', res.gridShelfList[gridId])
  762. }
  763. })
  764. const sortedKeys = Object.keys(res.gridShelfList).sort()
  765. const sortedShelfDetails = []
  766. sortedKeys.forEach(key => {
  767. res.shelfDetails.forEach(shelfDetail => {
  768. if (shelfDetail.gridId === key) {
  769. sortedShelfDetails.push(shelfDetail)
  770. }
  771. })
  772. })
  773. this.baseStockData = sortedShelfDetails
  774. setTimeout(() => {
  775. this.shelfAllGridDataLoading = false
  776. }, 500)
  777. }).catch(() => {
  778. })
  779. }
  780. }
  781. }
  782. }
  783. </script>
  784. <style lang="scss" scoped>
  785. .venue-content{
  786. position: relative;
  787. padding: 20px;
  788. background-color: #fff;
  789. }
  790. .tab-content{
  791. width: 100%;
  792. min-height: calc(100vh - 232px) !important;
  793. .tab-nav{
  794. position: relative;
  795. flex: 1;
  796. .iconfont{
  797. font-size: 12px;
  798. }
  799. }
  800. .compare-btn{
  801. position: absolute;
  802. right: 0;
  803. top: 0;
  804. font-size: 12px;
  805. padding: 3px;
  806. }
  807. }
  808. .gird-data-header{
  809. display: flex;
  810. justify-content: space-between;
  811. }
  812. .tag-info{
  813. display: flex;
  814. justify-content: flex-start;
  815. align-items: center;
  816. padding: 0 20px;
  817. p{
  818. margin-left: 20px;
  819. font-size: 14px;
  820. font-weight: bold;
  821. }
  822. }
  823. .time-update-cont{
  824. position: relative;
  825. display: flex;
  826. justify-content: flex-start;
  827. align-items: center;
  828. padding: 0 20px;
  829. span.time-left-txt{
  830. font-size: 14px;
  831. }
  832. .el-button{
  833. width: 134px;
  834. padding:5px;
  835. border: none;
  836. text-align: left;
  837. }
  838. .time-update-line{
  839. display: none;
  840. position: absolute;
  841. top: 33px;
  842. right: 20px;
  843. z-index: 9999;
  844. width: 250px;
  845. max-height: 645px;
  846. padding: 20px 30px;
  847. background-color: #fff;
  848. border: 1px solid #e8f2ff;
  849. border-radius: 10px;
  850. -webkit-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
  851. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
  852. overflow: hidden;
  853. overflow-y: scroll;
  854. }
  855. }
  856. .time-update-cont:hover .time-update-line {
  857. display: block;
  858. }
  859. .gird-data-book{
  860. position: relative;
  861. height: 650px;
  862. margin-top: 4px;
  863. overflow: hidden;
  864. overflow-y: scroll;
  865. }
  866. .gird-layer{
  867. position: relative;
  868. display: flex;
  869. justify-content: space-between;
  870. .gird-left-line{
  871. position: absolute;
  872. left: 0;
  873. top: 0;
  874. display: block;
  875. width: 6px;
  876. height: 130px;
  877. background: url('~@/assets/images/shelf01.png') no-repeat left top;
  878. background-size: 100% 100%;
  879. z-index: 999;
  880. }
  881. .gird-right-line{
  882. position: absolute;
  883. right: calc(298px);
  884. top: 0;
  885. display: block;
  886. width: 6px;
  887. height: 130px;
  888. background: url('~@/assets/images/shelf01.png') no-repeat left top;
  889. background-size: 100% 100%;
  890. z-index: 999;
  891. }
  892. .layer-left{
  893. width: calc(100% - 240px);
  894. height: 130px;
  895. margin-right: 5px;
  896. padding: 0 16px 0 20px;
  897. background: url('~@/assets/images/shelf02.png') repeat left top;
  898. background-size: 10% 100%;
  899. overflow: hidden;
  900. overflow-x: scroll;
  901. }
  902. .layer-left-book{
  903. // width: calc(100vw - 655px);
  904. height: 130px;
  905. white-space: nowrap;
  906. .book-item{
  907. position: relative;
  908. display: inline-block;
  909. width: 42px;
  910. height: 120px;
  911. margin-top: 18px;
  912. background: url('~@/assets/images/shelf03.png') no-repeat left top;
  913. background-size: 100% 100%;
  914. margin-left: -15px;
  915. cursor: pointer;
  916. span.book-name{
  917. position: absolute;
  918. left: 15px;
  919. top: 16px;
  920. display: block;
  921. height: 90px;
  922. font-size: 12px;
  923. writing-mode:vertical-rl;
  924. overflow: hidden;
  925. white-space: nowrap;
  926. text-overflow: ellipsis;
  927. }
  928. &.red-active{
  929. background: url('~@/assets/images/shelf05.png') no-repeat left top;
  930. background-size: 100% 100%;
  931. }
  932. &.blue-active{
  933. background: url('~@/assets/images/shelf06.png') no-repeat left top;
  934. background-size: 100% 100%;
  935. }
  936. }
  937. }
  938. }
  939. .layer-right-handle{
  940. width: 300px;
  941. padding: 0 10px;
  942. background-color: #E8F2FF;
  943. margin: 3px 5px;
  944. border-radius: 6px;
  945. }
  946. .layer-info-header{
  947. display: flex;
  948. justify-content: space-between;
  949. align-items: center;
  950. line-height: 30px;
  951. h4{
  952. color: #0c0e1e;
  953. }
  954. span{
  955. font-size: 12px;
  956. }
  957. }
  958. .layer-right-content{
  959. display: flex;
  960. justify-content: space-between;
  961. }
  962. .layer-tag-info{
  963. div.tag-item {
  964. display: flex;
  965. justify-content: flex-start;
  966. line-height: 26px;
  967. font-size: 14px;
  968. }
  969. }
  970. .layer-handle{
  971. display: flex;
  972. flex-direction: column;
  973. .el-button{
  974. margin-left: 0 !important;
  975. margin-bottom: 10px
  976. }
  977. }
  978. .dialog-grid-detail{
  979. ::v-deep .el-dialog{
  980. width: 1200px !important;
  981. .el-dialog__body{
  982. padding: 0 !important;
  983. }
  984. .tab-nav{
  985. margin: 14px 0 10px 0 !important;
  986. }
  987. }
  988. .detail-tab{
  989. position: relative;
  990. }
  991. .check-view-img{
  992. position: absolute;
  993. right: 0;
  994. top: -10px;
  995. }
  996. }
  997. .gird-img-detail{
  998. ::v-deep .el-dialog{
  999. width: 1200px !important;
  1000. padding: 0 !important;
  1001. background: none;
  1002. box-shadow: none;
  1003. .el-dialog__header{
  1004. display: none;
  1005. }
  1006. .el-dialog__body{
  1007. padding: 0 !important;
  1008. }
  1009. }
  1010. ::v-deep .el-carousel__container{
  1011. height: 600px !important;
  1012. .el-carousel__item{
  1013. display: flex;
  1014. align-items: center;
  1015. }
  1016. .el-carousel__item img{
  1017. display: block;
  1018. max-width: 100%;
  1019. max-height: 100%;
  1020. margin: 0 auto;
  1021. }
  1022. .el-carousel__arrow{
  1023. background-color: rgba(3,72,243,1);
  1024. i.el-icon-arrow-left,
  1025. i.el-icon-arrow-right{
  1026. color: #fff;
  1027. }
  1028. .el-icon-arrow-right:before{
  1029. color: #fff;
  1030. }
  1031. }
  1032. }
  1033. ::v-deep .el-carousel__button{
  1034. height: 6px !important;
  1035. }
  1036. ::v-deep .el-carousel__indicators--outside button{
  1037. background-color: rgba(3,72,243,1);
  1038. }
  1039. .gird-img-button{
  1040. position: fixed;
  1041. right: -200px;
  1042. top: -60px;
  1043. display: flex;
  1044. justify-content: flex-start;
  1045. align-items: center;
  1046. z-index: 9999999;
  1047. .el-button{
  1048. background-color: #e8f2ff;
  1049. }
  1050. }
  1051. }
  1052. .venue-content {
  1053. .tab-content .tab-nav {
  1054. li{
  1055. cursor: default;
  1056. }
  1057. }
  1058. }
  1059. .popover-external-set{
  1060. ul li p{
  1061. width: 50px;
  1062. font-weight: bold;
  1063. text-align: right;
  1064. }
  1065. ul li span,
  1066. ul li em{
  1067. width: 140px;
  1068. display: block;
  1069. text-align: right;
  1070. font-style: normal;
  1071. }
  1072. }
  1073. .layerShelf-swiper{
  1074. margin: 0 20px;
  1075. ::v-deep .swiper-wrapper{
  1076. font-size: 14px;
  1077. border-bottom: none !important;
  1078. .swiper-slide-title {
  1079. font-weight: bold;
  1080. height: 300px;
  1081. margin-top: 10px;
  1082. margin-right: 10px;
  1083. color: #0c0e1e;
  1084. writing-mode:vertical-rl;
  1085. overflow: hidden;
  1086. white-space: nowrap;
  1087. text-overflow: ellipsis;
  1088. cursor: pointer;
  1089. .book-name {
  1090. &.red-active{
  1091. color: #ed4a41;
  1092. }
  1093. &.blue-active{
  1094. color: #0348f3;
  1095. }
  1096. span{
  1097. display: inline-block;
  1098. width: 20px;
  1099. height: 20px;
  1100. line-height: 20px;
  1101. text-align: center;
  1102. transform: rotate(-90deg);
  1103. }
  1104. }
  1105. }
  1106. }
  1107. }
  1108. </style>