图书馆综合管理系统
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.

351 lines
11 KiB

7 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
7 months ago
6 months ago
7 months ago
6 months ago
6 months ago
7 months ago
6 months ago
6 months ago
7 months ago
6 months ago
7 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
7 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
6 months ago
7 months ago
  1. <template>
  2. <div class="app-container">
  3. <div class="venue-header">
  4. <h4 @click="handleToRegions"><i class="iconfont icon-shuju" />数据总览</h4>
  5. <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
  6. </div>
  7. <div class="venue-content">
  8. <crudOperation :permission="permission">
  9. <template v-slot:middle>
  10. <el-button v-permission="permission.add" size="mini" @click="crud.toAdd">
  11. <i class="iconfont icon-shengchengpandiandan" />
  12. 全量盘点
  13. </el-button>
  14. </template>
  15. <template v-slot:right>
  16. <el-button :loading="crud.downloadLoading" size="mini" @click="doExport(crud.selections)">
  17. <i class="iconfont icon-daochu" />
  18. 导出
  19. </el-button>
  20. </template>
  21. </crudOperation>
  22. <div class="venue-left">
  23. <div class="container-right tab-content">
  24. <span class="right-top-line" />
  25. <span class="left-bottom-line" />
  26. <ul class="tab-nav">
  27. <li v-for="(item,index) in floorOptions" :key="index" :class="{ 'active-tab-nav': tabIndex == index }" @click="changeActiveTab(index)">{{ item.floorName }}<i /></li>
  28. <!-- 最右侧装饰img -->
  29. <span class="tab-right-img" />
  30. </ul>
  31. <div class="total-data">
  32. <span>楼层概况</span>
  33. <p>区域1</p>
  34. <p>书架4</p>
  35. <p>摄像头12</p>
  36. </div>
  37. <CanvasPreview ref="previewRefs" page-preview="floor" :current-mark-data="currentMarkData" :image-url="imageUrl" />
  38. </div>
  39. </div>
  40. <div class="venue-right">
  41. <div class="lib-right-item lib-info">
  42. <h4>场馆概况</h4>
  43. <ul class="data-right-list">
  44. <li><p>楼层</p><span><i>5</i></span></li>
  45. <li><p>区域</p><span><i>25</i></span></li>
  46. <li><p>书架</p><span><i>100</i></span></li>
  47. <li><p>摄像头</p><span><i>300</i></span></li>
  48. </ul>
  49. </div>
  50. <div class="lib-right-item">
  51. <h4>盘点概况</h4>
  52. <div class="refresh-date">2024-11-28 09:46</div>
  53. <ul class="data-right-list">
  54. <li><p>在架</p><span><i>15000</i></span></li>
  55. <li><p>错架</p><span><i>300</i></span> <span class="percentage">2.00%</span></li>
  56. <li><p>错序</p><span><i>0</i></span><span class="percentage">0.00%</span></li>
  57. </ul>
  58. </div>
  59. <div class="lib-right-item">
  60. <h4>流通统计</h4>
  61. <div class="refresh-date">2024-11-28 09:46</div>
  62. <bookSwiper />
  63. </div>
  64. </div>
  65. </div>
  66. <!-- form -->
  67. <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">
  68. <span class="dialog-right-top" />
  69. <span class="dialog-left-bottom" />
  70. <div class="setting-dialog">
  71. <el-form ref="form" :inline="true" :model="form" :rules="rules" size="small" label-width="80px">
  72. <el-form-item label="盘点单号" prop="taskName">
  73. <el-input v-model="form.taskName" />
  74. </el-form-item>
  75. <el-form-item label="盘点类型" prop="taskType">
  76. <el-input v-model="form.taskType" />
  77. </el-form-item>
  78. <el-form-item label="目标位置" prop="location">
  79. <el-input v-model="form.location" />
  80. </el-form-item>
  81. <el-form-item label="目标数量" prop="number">
  82. <el-input v-model="form.number" />
  83. </el-form-item>
  84. <el-row>
  85. <el-form-item label="备注" prop="remark">
  86. <el-input v-model="form.remark" type="textarea" style="width: 572px;" :rows="4" />
  87. </el-form-item>
  88. </el-row>
  89. </el-form>
  90. <div slot="footer" class="dialog-footer">
  91. <el-button type="text" @click="crud.cancelCU">取消</el-button>
  92. <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">保存</el-button>
  93. </div>
  94. </div>
  95. </el-dialog>
  96. </div>
  97. </template>
  98. <script>
  99. import { FetchInitLibraryRegionList } from '@/api/area/index'
  100. import crudFloor from '@/api/floor/index'
  101. import CRUD, { presenter, header, form, crud } from '@crud/crud'
  102. import crudOperation from '@crud/CRUD.operation'
  103. import { mapGetters } from 'vuex'
  104. import defaultImg from '@/assets/images/system/default-img.jpg'
  105. import bookSwiper from '@/views/components/bookSwiper.vue'
  106. import CanvasPreview from '@/views/components/canvasPreview.vue'
  107. const defaultForm = { id: null, taskType: null, taskName: null, location: null, number: null, remark: null }
  108. export default {
  109. name: 'DataScreening',
  110. components: { crudOperation, bookSwiper, CanvasPreview },
  111. cruds() {
  112. return CRUD({ title: '数据总览', url: 'api/libraryFloor/initLibraryFloorList', crudMethod: { ...crudFloor }, sort: [], optShow: {
  113. add: false,
  114. edit: false,
  115. del: false,
  116. download: false,
  117. group: false,
  118. reset: false
  119. }})
  120. },
  121. mixins: [presenter(), header(), form(defaultForm), crud()],
  122. data() {
  123. const _this = this
  124. return {
  125. floorOptions: [],
  126. tabIndex: 0,
  127. defaultImg: defaultImg,
  128. imageUrl: defaultImg,
  129. imageRegionUrl: defaultImg,
  130. currentMarkData: null,
  131. allCoverData: [],
  132. swiperActiveIndex: 0,
  133. rightDataIndex: null,
  134. swiperOptionContent: {
  135. slidesPerView: 'auto',
  136. on: {
  137. slideChangeTransitionStart: function() {
  138. _this.rightDataIndex = null
  139. _this.swiperActiveIndex = this.activeIndex
  140. _this.swiperTitle.slideTo(this.activeIndex, 500, false)
  141. }
  142. }
  143. },
  144. swiperOptionTitle: {
  145. slidesPerView: 'auto',
  146. freeMode: true
  147. },
  148. tabListData: [{ name: '热门图书' }, { name: '热门架位' }, { name: '冷面图书' }],
  149. permission: {
  150. add: ['admin', 'floor:add'],
  151. edit: ['admin', 'floor:edit'],
  152. del: ['admin', 'floor:del']
  153. },
  154. rules: {
  155. taskName: [
  156. { required: true, message: '请输入盘点单号', trigger: 'blur' }
  157. ],
  158. taskType: [
  159. { required: true, message: '请输入盘点类型', trigger: 'blur' }
  160. ],
  161. location: [
  162. { required: true, message: '请输入目标位置', trigger: 'blur' }
  163. ],
  164. number: [
  165. { required: true, message: '请输入目标数量', trigger: 'blur' }
  166. ]
  167. }
  168. }
  169. },
  170. computed: {
  171. ...mapGetters([
  172. 'user',
  173. 'baseApi'
  174. ]),
  175. swiperContent() {
  176. return this.$refs.swiperContent.$el.swiper
  177. }
  178. },
  179. methods: {
  180. [CRUD.HOOK.beforeRefresh]() {
  181. },
  182. [CRUD.HOOK.afterRefresh](crud) {
  183. this.floorOptions = crud.data
  184. this.changeActiveTab(this.tabIndex)
  185. },
  186. // 提交前的验证
  187. [CRUD.HOOK.afterValidateCU](crud) {
  188. return true
  189. },
  190. changeActiveTab(index) {
  191. if (this.$refs.previewRefs.canvasPreview.lowerCanvasEl) {
  192. this.$refs.previewRefs.canvasPreview.clear()
  193. this.$refs.previewRefs.canvasPreview.dispose()
  194. }
  195. this.allCoverData = []
  196. this.tabIndex = index
  197. const params = {
  198. 'floorId': this.floorOptions[index].id
  199. }
  200. FetchInitLibraryRegionList(params).then(res => {
  201. console.log(res)
  202. this.allCoverData = res.content
  203. if (this.floorOptions[index].floorMap) {
  204. this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgId=' + this.floorOptions[index].floorMap
  205. } else {
  206. this.imageUrl = this.defaultImg
  207. }
  208. if (this.allCoverData.length !== 0) {
  209. this.currentMarkData = this.allCoverData[0]
  210. const parsedSignPoints = this.allCoverData.map(item => {
  211. const signPoint = JSON.parse(item.signPoint)
  212. return {
  213. id: item.id,
  214. name: item.regionName,
  215. floorName: item.floorName,
  216. floorId: item.floorId,
  217. pointInfo: signPoint.pointInfo[0].pointInfo
  218. }
  219. })
  220. const imgInfo = JSON.parse(this.allCoverData[0].signPoint).imgInfo
  221. const result = {
  222. pointInfo: parsedSignPoints,
  223. imgInfo: imgInfo
  224. }
  225. console.log('result', result)
  226. this.$nextTick(() => {
  227. console.log('this.$refs.previewRefs', this.$refs.previewRefs)
  228. this.$refs.previewRefs.initCanvasPreview(result)
  229. })
  230. } else {
  231. this.currentMarkData = {}
  232. }
  233. }).catch(() => {
  234. })
  235. },
  236. handleToRegions() {
  237. this.$router.push({ path: '/dataScreening/regions', query: { }})
  238. },
  239. handleSlidClickFun(index) {
  240. this.rightDataIndex = null
  241. this.handleSlideToFun(index)
  242. },
  243. handleSlideToFun(index) {
  244. this.swiperActiveIndex = index
  245. this.swiperContent.slideTo(index, 500, false)
  246. this.swiperTitle.slideTo(index, 500, false)
  247. }
  248. }
  249. }
  250. </script>
  251. <style lang="scss" scoped>
  252. .container-right{
  253. min-height: calc(100vh - 232px) !important;
  254. }
  255. .venue-content{
  256. position: relative;
  257. }
  258. .crud-opts{
  259. position: absolute;
  260. right: 20px;
  261. top: 10px;
  262. }
  263. .venue-left{
  264. flex: 1;
  265. margin-right: 0 !important;
  266. .venue-preview{
  267. height: 633px !important;
  268. }
  269. }
  270. .venue-right{
  271. display: flex;
  272. flex-direction: column;
  273. width: 400px;
  274. padding: 50px 10px 20px 10px !important;
  275. .lib-right-item{
  276. position: relative;
  277. // padding: 10px;
  278. // height: calc(100% / 3);
  279. padding-bottom: 10px;
  280. margin-bottom: 10px;
  281. border: 1px solid #E8F2FF;
  282. border-radius: 4px;
  283. h4{
  284. padding: 6px 10px;
  285. background-color: #E8F2FF;
  286. color: #000;
  287. line-height: 30px;
  288. border-bottom: 1px solid #edeff3;
  289. }
  290. .refresh-date{
  291. position: absolute;
  292. right: 14px;
  293. top: 10px;
  294. font-size: 12px;
  295. line-height: 30px;
  296. }
  297. }
  298. }
  299. .data-right-list {
  300. padding-top: 10px;
  301. li{
  302. display: flex;
  303. justify-content: flex-start;
  304. align-items: center;
  305. line-height: 36px;
  306. p{
  307. width: 80px;
  308. font-weight: bold;
  309. text-align: right;
  310. }
  311. span{
  312. width: 140px;
  313. display: block;
  314. text-align: right;
  315. i{
  316. font-style: normal;
  317. font-weight: bold;
  318. padding: 0 10px;
  319. color: #0348f3;
  320. }
  321. &.percentage{
  322. width: auto;
  323. }
  324. }
  325. }
  326. }
  327. .total-data{
  328. display: flex;
  329. justify-content: flex-start;
  330. align-items: center;
  331. position: absolute;
  332. right: 12px;
  333. top: 60px;
  334. font-size: 14px;
  335. padding: 4px 6px;
  336. color: #fff;
  337. background-color: rgba(0,0,0,.5);
  338. border-radius: 4px;
  339. p{
  340. margin-left: 10px;
  341. }
  342. }
  343. </style>