index.vue 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. <template>
  2. <div class="app-container">
  3. <el-radio-group v-model="tabPosition" style="margin: 5px">
  4. <el-radio-button label="first">{{ $t('mes.lockers.cabinetLocation') }}</el-radio-button>
  5. <el-radio-button label="second">{{ $t('mes.lockers.cabinetList') }}</el-radio-button>
  6. </el-radio-group>
  7. <!-- 优化后带样式的无数据提示盒子 -->
  8. <div
  9. v-if="jobconfig.imageUrl==''"
  10. style="
  11. position: absolute;
  12. top: 40%;
  13. left: 40%;
  14. font-size: 18px;
  15. color: #666;
  16. text-align: center;
  17. "
  18. >
  19. {{ $t('mes.lockers.noDataTip') }}
  20. </div>
  21. <div
  22. style="
  23. display: flex;
  24. justify-content: center;
  25. align-items: center;
  26. position: relative;
  27. "
  28. v-show="tabPosition == 'first'"
  29. >
  30. <!-- 缩放容器 -->
  31. <div
  32. ref="mapContainer"
  33. :style="{
  34. transform: `scale(${scaleFactor})`,
  35. transformOrigin: 'top left',
  36. width: '1250px',
  37. height: '700px',
  38. position: 'relative',
  39. }"
  40. >
  41. <img
  42. :style="{width:jobconfig.width+'px',height:jobconfig.height+'px'}"
  43. :src="jobconfig.imageUrl"
  44. alt=""
  45. />
  46. <!-- <img-->
  47. <!-- v-for="(cabinet, index) in TicketListPage"-->
  48. <!-- :key="cabinet.cabinetId"-->
  49. <!-- :style="{-->
  50. <!-- width: '35px',-->
  51. <!-- height: '35px',-->
  52. <!-- position: 'absolute',-->
  53. <!-- cursor: 'pointer',-->
  54. <!-- // 图标垂直居中-->
  55. <!-- top: `${deptXLGCenter.top - 53}px`,-->
  56. <!-- // 图标水平居中,动态计算偏移-->
  57. <!-- left: `${-->
  58. <!-- deptXLGCenter.left - -->
  59. <!-- (TicketListPage.length * 35 + (TicketListPage.length - 1) * 5) /-->
  60. <!-- 2 +-->
  61. <!-- index * 40-->
  62. <!-- }px`,-->
  63. <!-- }"-->
  64. <!-- :src="require(`@/assets/images/${imageMap[cabinet.status]}.jpg`)"-->
  65. <!-- alt=""-->
  66. <!-- @click="handleCabinetClick(cabinet)"-->
  67. <!-- />-->
  68. <div v-for="(item, index) in jobconfigPoint.records" :key="item.id">
  69. <div
  70. class="deptXLG"
  71. :style="{left:item.x+'px',top:item.y+'px'}"
  72. >
  73. {{ item.entityName }}
  74. </div>
  75. <!-- // 使图标位于岗位上方-->
  76. <img
  77. v-for="(cabinet, index) in TicketListPage[item.entityId] || []"
  78. :key="cabinet.cabinetId"
  79. :style="{
  80. width: '35px',
  81. height: '35px',
  82. position: 'absolute',
  83. cursor: 'pointer',
  84. top: (item.y - 40) + 'px', // 让图标浮在岗位的上方
  85. left: (
  86. item.x -
  87. ((TicketListPage[item.entityId] ? TicketListPage[item.entityId].length * 35 : 0) - 53) / 2 + // 计算总宽度并居中,减去单个图标宽度,确保居中
  88. index * 40 // 处理图标间隔
  89. ) + 'px'
  90. }"
  91. :src="imageMap[cabinet.status]"
  92. alt=""
  93. @click="handleCabinetClick(cabinet)"
  94. />
  95. </div>
  96. <!-- 左侧警告部分内容-->
  97. <img style="width: 40px;height: 40px;position: absolute;top:2%;right: -4%" :src="this.ExceptionTableImage"
  98. alt=""
  99. @click="showExTable"
  100. >
  101. <div v-if="exceptionTableVisible"
  102. style="width: 430px;height: 300px;position: absolute;top:2%;right:0;background: white "
  103. >
  104. <div style="display: flex">
  105. <img :src="this.ExceptionTableImage2" style="width: 20px;height: 20px;margin: 10px" alt="">
  106. <span style="margin: 10px">{{ $t('mes.lockers.exceptionInfo') }}</span>
  107. </div>
  108. <el-table :data="exceptionTable">
  109. <el-table-column :label="$t('mes.lockers.cabinet')" prop="loanFromName"></el-table-column>
  110. <el-table-column :label="$t('mes.lockers.exceptionType')" prop="exceptionType"></el-table-column>
  111. <el-table-column :label="$t('mes.lockers.exceptionInfo')" prop="status"></el-table-column>
  112. </el-table>
  113. </div>
  114. </div>
  115. </div>
  116. <!-- 物资列表 -->
  117. <div v-if="tabPosition == 'second'" class="CabinetListcon">
  118. <div class="left">
  119. <!-- 岗位树 -->
  120. <div class="deptTree">
  121. <div class="head-container">
  122. <el-input
  123. v-model="queryParams.workstationName"
  124. :placeholder="$t('mes.lockers.workstationNamePlaceholder')"
  125. clearable
  126. size="small"
  127. prefix-icon="el-icon-search"
  128. style="margin-bottom: 20px"
  129. @clear="handleClear"
  130. />
  131. </div>
  132. <div class="head-container">
  133. <el-tree
  134. :data="workstationOptions"
  135. :props="defaultProps"
  136. :expand-on-click-node="false"
  137. :filter-node-method="filterNode"
  138. ref="treeData"
  139. node-key="id"
  140. default-expand-all
  141. @node-click="handleNodeClick"
  142. highlight-current
  143. />
  144. </div>
  145. </div>
  146. </div>
  147. <div class="right">
  148. <el-row>
  149. <el-form
  150. :model="queryParams"
  151. ref="queryForm"
  152. size="small"
  153. :inline="true"
  154. v-show="showSearch"
  155. label-width="100px"
  156. >
  157. <el-form-item :label="$t('mes.lockers.cabinetId')" prop="cabinetId">
  158. <el-input
  159. v-model="queryParams.cabinetId"
  160. :placeholder="$t('mes.lockers.cabinetIdPlaceholder')"
  161. clearable
  162. oninput="value=value.replace(/[^\d.]/g,'')"
  163. @keyup.enter.native="handleQuery"
  164. />
  165. </el-form-item>
  166. <el-form-item :label="$t('mes.lockers.cabinetName')" prop="cabinetName">
  167. <el-input
  168. v-model="queryParams.cabinetName"
  169. :placeholder="$t('mes.lockers.cabinetNamePlaceholder')"
  170. clearable
  171. @keyup.enter.native="handleQuery"
  172. />
  173. </el-form-item>
  174. <!-- <el-form-item label="物资柜状态" prop="status">-->
  175. <!-- <el-select v-model="queryParams.status" placeholder="物资柜状态">-->
  176. <!-- <el-option-->
  177. <!-- v-for="dict in dict.type.cabinet_status"-->
  178. <!-- :key="dict.value"-->
  179. <!-- :label="dict.label"-->
  180. <!-- :value="dict.value"-->
  181. <!-- />-->
  182. <!-- </el-select>-->
  183. <!-- </el-form-item>-->
  184. <el-form-item>
  185. <el-button
  186. v-no-more-click
  187. type="primary"
  188. icon="el-icon-search"
  189. size="mini"
  190. @click="handleQuery"
  191. >{{ $t('common.search') }}
  192. </el-button
  193. >
  194. <el-button
  195. v-no-more-click
  196. icon="el-icon-refresh"
  197. size="mini"
  198. @click="resetQuery"
  199. >{{ $t('common.reset') }}
  200. </el-button
  201. >
  202. </el-form-item>
  203. </el-form>
  204. </el-row>
  205. <el-row :gutter="10" class="mb8">
  206. <el-col :span="1.5">
  207. <el-button
  208. v-no-more-click
  209. type="primary"
  210. plain
  211. icon="el-icon-plus"
  212. size="mini"
  213. @click="handleAdd"
  214. v-hasPermi="['iscs:cabinet:add']"
  215. >{{ $t('common.add') }}
  216. </el-button>
  217. </el-col>
  218. <right-toolbar
  219. :showSearch.sync="showSearch"
  220. @queryTable="getList"
  221. ></right-toolbar>
  222. </el-row>
  223. <el-table
  224. v-loading="loading"
  225. :data="CabinetList"
  226. @selection-change="handleSelectionChange"
  227. >
  228. <!-- <el-table-column type="selection" width="55" align="center"/>-->
  229. <el-table-column :label="$t('mes.lockers.cabinetId')" align="center" prop="cabinetId">
  230. </el-table-column>
  231. <el-table-column :label="$t('mes.lockers.cabinetName')" prop="cabinetName" width="150"/>
  232. <el-table-column :label="$t('mes.lockers.cabinetPicture')" prop="cabinetPicture" width="100">
  233. <template slot-scope="scope">
  234. <div class="img-box" v-if="scope.row.cabinetPicture">
  235. <el-image
  236. style="width: 75px; height: 75px"
  237. :preview-teleported="true"
  238. class="images"
  239. :hide-on-click-modal="true"
  240. :src="scope.row.cabinetPicture"
  241. :zoom-rate="1.2"
  242. :preview-src-list="[scope.row.cabinetPicture]"
  243. :initial-index="1"
  244. >
  245. </el-image>
  246. <i class="el-icon-zoom-in" id="eyeicon"></i>
  247. </div>
  248. <span v-else>-</span>
  249. </template>
  250. </el-table-column>
  251. <el-table-column :label="$t('mes.lockers.cabinetStatus')" align="center" prop="status">
  252. <template slot-scope="scope">
  253. <dict-tag
  254. :options="dict.type.cabinet_status"
  255. :value="scope.row.status"
  256. />
  257. </template>
  258. </el-table-column>
  259. <el-table-column :label="$t('mes.lockers.exceptionType')" prop="exReason" width="100">
  260. <template slot-scope="scope">
  261. <dict-tag
  262. :options="dict.type.exception_reason"
  263. :value="scope.row.exReason"
  264. />
  265. </template>
  266. </el-table-column>
  267. <el-table-column :label="$t('mes.lockers.cabinetDetail')" align="center">
  268. <template slot-scope="scope">
  269. <el-button
  270. v-no-more-click
  271. size="mini"
  272. type="text"
  273. @click="handleLook(scope.row)"
  274. >{{ $t('common.view') }}
  275. </el-button>
  276. </template>
  277. </el-table-column>
  278. <el-table-column
  279. :label="$t('common.operation')"
  280. align="center"
  281. class-name="small-padding fixed-width"
  282. >
  283. <template slot-scope="scope">
  284. <el-button
  285. v-no-more-click
  286. size="mini"
  287. type="text"
  288. icon="el-icon-edit"
  289. @click="handleUpdate(scope.row)"
  290. v-hasPermi="['iscs:cabinet:edit']"
  291. >{{ $t('common.edit') }}
  292. </el-button>
  293. <el-button
  294. v-no-more-click
  295. size="mini"
  296. type="text"
  297. icon="el-icon-delete"
  298. @click="handleDelete(scope.row)"
  299. v-hasPermi="['iscs:cabinet:remove']"
  300. >{{ $t('common.delete') }}
  301. </el-button>
  302. </template>
  303. </el-table-column>
  304. </el-table>
  305. <pagination
  306. v-show="total > 0"
  307. :total="total"
  308. :page.sync="queryParams.current"
  309. :limit.sync="queryParams.size"
  310. @pagination="getList"
  311. />
  312. </div>
  313. </div>
  314. <!-- 添加或修改物资柜对话框 -->
  315. <el-dialog :visible.sync="open" width="510px" append-to-body>
  316. <div slot="title" class="dialog-title">
  317. <i></i>
  318. <span class="title">{{ title }}</span>
  319. </div>
  320. <el-form ref="form" :model="form" :rules="rules" label-width="110px">
  321. <el-form-item :label="$t('mes.lockers.cabinetCode')" prop="cabinetCode">
  322. <el-input
  323. v-model="form.cabinetCode"
  324. :placeholder="$t('mes.lockers.cabinetCodePlaceholder')"
  325. style="width: 200px; margin-right: 10px"
  326. />
  327. <el-switch
  328. v-model="autoGenFlag"
  329. active-color="#13ce66"
  330. :active-text="$t('mes.lockers.autoGenerate')"
  331. @change="handleAutoGenChange(autoGenFlag)"
  332. >
  333. </el-switch>
  334. </el-form-item>
  335. <el-form-item :label="$t('mes.lockers.cabinetName')" prop="cabinetName">
  336. <el-input
  337. style="width: 348px"
  338. v-model="form.cabinetName"
  339. :placeholder="$t('mes.lockers.cabinetNamePlaceholder')"
  340. />
  341. </el-form-item>
  342. <el-form-item :label="$t('mes.lockers.workstation')" prop="workstationId">
  343. <treeselect
  344. style="width: 348px"
  345. v-model="form.workstationId"
  346. :options="marsOptions"
  347. :normalizer="Marsnormalizer"
  348. :placeholder="$t('mes.lockers.workstationPlaceholder')"
  349. />
  350. </el-form-item>
  351. <el-form-item :label="$t('mes.lockers.cabinetPicture')" prop="cabinetPicture">
  352. <ImageUploadSingle
  353. :limit="1"
  354. :value="form.cabinetPicture"
  355. :fileSize="5"
  356. @onUploaded="handleIconUplaoded"
  357. @onRemoved="handleIconRemoved"
  358. ></ImageUploadSingle>
  359. </el-form-item>
  360. <el-form-item :label="$t('common.remark')" prop="remark">
  361. <el-input
  362. v-model="form.remark"
  363. type="textarea"
  364. :placeholder="$t('common.pleaseInput') + $t('common.remark')"
  365. style="width: 348px"
  366. />
  367. </el-form-item>
  368. </el-form>
  369. <div slot="footer" class="dialog-footer">
  370. <el-button
  371. v-no-more-click
  372. type="primary"
  373. @click="cancel"
  374. v-if="optType == 'view'"
  375. >{{ $t('common.back') }}
  376. </el-button>
  377. <el-button v-no-more-click type="primary" @click="submitForm" v-else
  378. >{{ $t('common.confirm') }}
  379. </el-button>
  380. <el-button v-no-more-click @click="cancel">{{ $t('common.cancel') }}</el-button>
  381. </div>
  382. </el-dialog>
  383. </div>
  384. </template>
  385. <script>
  386. import {
  387. getMaterialsCabinet,
  388. addMaterialsCabinet,
  389. updateMaterialsCabinet,
  390. deleteMaterialsCabinet,
  391. selectMaterialsCabinetById
  392. } from '@/api/mes/material/lockers.js'
  393. import Treeselect from '@riophae/vue-treeselect'
  394. import '@riophae/vue-treeselect/dist/vue-treeselect.css'
  395. import { genCode } from '@/api/system/autocode/rule'
  396. import { listMarsDept } from '@/api/system/marsdept'
  397. import { listLoto } from '@/api/mes/lotoStation/lotoStation'
  398. import { listMaterials } from '@/api/mes/material/information'
  399. import { MaterialsLoanExceptionPage } from '@/api/mes/material/exception'
  400. import { selectIsMapById } from '@/api/system/mapconfig'
  401. import { getIsMapPointPage } from '@/api/system/mappoint'
  402. import { getIsSystemAttributeByKey } from '@/api/system/configuration'
  403. export default {
  404. name: 'Team',
  405. components: {
  406. Treeselect
  407. },
  408. dicts: ['material_status', 'cabinet_status', 'exception_reason'],
  409. data() {
  410. return {
  411. jobconfig: null,//接口传递地图与宽高数据
  412. jobconfigPoint: null,//接口传递的岗位位置信息
  413. //自动生成编码
  414. autoGenFlag: false,
  415. optType: undefined,
  416. tabPosition: 'first', //顶部切换
  417. // 遮罩层
  418. loading: true,
  419. // 选中数组
  420. ids: [],
  421. codes: [],
  422. // 非单个禁用
  423. single: true,
  424. // 非多个禁用
  425. multiple: true,
  426. // 显示搜索条件
  427. showSearch: true,
  428. // 总条数
  429. total: 0,
  430. // 班组表格数据
  431. CabinetList: [],
  432. // 弹出层标题
  433. title: '',
  434. // 是否显示弹出层
  435. open: false,
  436. // 查询参数
  437. createTime: '',
  438. queryParams: {
  439. current: 1,
  440. size: 10,
  441. workstationName: undefined,
  442. workstationId: undefined,
  443. cabinetId: null,
  444. cabinetName: null,
  445. status: null
  446. },
  447. // queryParamsList: {
  448. // current: 1,
  449. // size: 10,
  450. // cabinetId: null,
  451. // cabinetName: null,
  452. // status: null,
  453. // },
  454. imageMap: {
  455. 0: 'table_map2', //正常
  456. 1: 'table_map1', //使用中
  457. 2: 'table_map3' //异常
  458. },
  459. // 表单参数
  460. form: {},
  461. marsOptions: [], //岗位
  462. TicketListPage: [], //R&R岗位
  463. scaleFactor: 1, // 缩放比例,初始值为1
  464. exceptionTableVisible: false,//地图显示异常物资柜具体信息
  465. exceptionTable: [],//地图异常数据table数据
  466. workstationOptions: [], //岗位
  467. defaultProps: {
  468. children: 'children',
  469. label: 'label'
  470. },
  471. sysAttrValue: null,//从基础数据接口里拿到物资柜底图的mapId
  472. ExceptionTableImage: '',//列表异常的图标
  473. ExceptionTableImage2: ''//列表异常的图标2
  474. }
  475. },
  476. watch: {
  477. 'queryParams.workstationId': function(newVal, oldVal) {
  478. if (newVal) {
  479. const data = {
  480. current: 1,
  481. size: -1,
  482. workstationId: this.queryParams.workstationId
  483. }
  484. getMaterialsCabinet(data).then((response) => {
  485. this.CabinetList = response.data.records
  486. })
  487. }
  488. },
  489. tabPosition: function(newVal, oldVal) {
  490. if (newVal) {
  491. this.getList()
  492. }
  493. }
  494. },
  495. created() {
  496. this.getList()
  497. this.getOtherList()
  498. this.getExpection()
  499. },
  500. methods: {
  501. // 显示异常的物资柜信息
  502. showExTable() {
  503. this.exceptionTableVisible = !this.exceptionTableVisible
  504. },
  505. /** 查询物资柜信息列表 */
  506. getList() {
  507. this.loading = true
  508. getMaterialsCabinet(this.queryParams).then((response) => {
  509. this.CabinetList = response.data.records
  510. console.log(response, '所有物资柜')
  511. this.total = response.data.total
  512. this.loading = false
  513. })
  514. const sysAttrKey1 = 'icon.cabinet.normal'
  515. const sysAttrKey2 = 'icon.cabinet.borrowed'
  516. const sysAttrKey3 = 'icon.cabinet.abnormal'
  517. const sysAttrKey4 = 'sys.exception.icon'
  518. const sysAttrKey5 = 'sys.exception2.icon'
  519. Promise.all([
  520. getIsSystemAttributeByKey(sysAttrKey1),
  521. getIsSystemAttributeByKey(sysAttrKey2),
  522. getIsSystemAttributeByKey(sysAttrKey3),
  523. getIsSystemAttributeByKey(sysAttrKey4),
  524. getIsSystemAttributeByKey(sysAttrKey5)
  525. ]).then((responses) => {
  526. this.imageMap[0] = responses[0].data.sysAttrValue // 正常
  527. this.imageMap[1] = responses[1].data.sysAttrValue // 使用中
  528. this.imageMap[2] = responses[2].data.sysAttrValue // 异常
  529. this.ExceptionTableImage = responses[3].data.sysAttrValue
  530. this.ExceptionTableImage2 = responses[4].data.sysAttrValue
  531. console.log(this.imageMap, this.ExceptionTableImage, this.ExceptionTableImage2, 'imageMap')
  532. })
  533. },
  534. getExpection() {
  535. // 调用 listMaterials 接口获取所有物资的信息
  536. listMaterials({ pages: 1, size: -1 }).then(response => {
  537. const materialsData = response.data.records || []
  538. // 处理损坏、过期的物资
  539. const damagedOrExpiredMaterials = materialsData.filter(material => material.status === '1' || material.status === '2')
  540. const damagedOrExpiredCabinets = Array.from(new Set(damagedOrExpiredMaterials.map(material => material.cabinetName)))
  541. console.log(damagedOrExpiredMaterials, 'damagedOrExpiredMaterials')
  542. // 处理归还异常的物资
  543. const misplacedMaterials = materialsData.filter(material => material.status === '3')
  544. const misplacedCabinets = Array.from(new Set(misplacedMaterials.map(material => material.cabinetName)))
  545. console.log(misplacedCabinets, 'misplacedCabinets')
  546. // 整合归还异常的柜子信息
  547. const misplacedCabinetDetails = misplacedCabinets.map(cabinet => ({
  548. loanFromName: cabinet,
  549. exceptionType: this.$t('mes.lockers.misplacedCabinet'),
  550. status: this.$t('mes.lockers.misplacedCount', { count: misplacedMaterials.filter(material => material.cabinetName === cabinet).length })
  551. }))
  552. // 整合损坏、过期的柜子信息
  553. const damagedOrExpiredCabinetDetails = damagedOrExpiredCabinets.map(cabinet => ({
  554. loanFromName: cabinet,
  555. exceptionType: this.$t('mes.lockers.expiredDamaged'),
  556. status: this.$t('mes.lockers.expiredDamagedCount', { count: damagedOrExpiredMaterials.filter(material => material.cabinetName === cabinet).length })
  557. }))
  558. // 调用 MaterialsLoanExceptionPage 接口获取柜门未关闭的数据
  559. return MaterialsLoanExceptionPage({
  560. pages: 1,
  561. size: -1,
  562. exceptionType: 1, // 1表示柜门未关
  563. status: 0 // 0表示未处理
  564. }).then(response1 => {
  565. const unClosedCabinets = response1.data.records || []
  566. if (unClosedCabinets) {
  567. // 整合柜门未关闭的柜子信息
  568. const unClosedCabinetDetails = unClosedCabinets.map(cabinet => ({
  569. loanFromName: cabinet.loanFromName,
  570. exceptionType: this.$t('mes.lockers.timeoutUnclosed'),
  571. status: this.$t('mes.lockers.timeoutUnclosedStatus', { time: this.calculateTimeDifference(cabinet.occurTime) })
  572. }))
  573. // 合并所有结果
  574. const result = [
  575. ...misplacedCabinetDetails,
  576. ...damagedOrExpiredCabinetDetails,
  577. ...unClosedCabinetDetails
  578. ]
  579. const resultData = result.filter((item) => {
  580. return item.loanFromName !== null
  581. })
  582. this.exceptionTable = resultData
  583. } else {
  584. // 合并所有结果
  585. const result = [
  586. ...misplacedCabinetDetails,
  587. ...damagedOrExpiredCabinetDetails
  588. ]
  589. const resultData = result.filter((item) => {
  590. return item.loanFromName !== null
  591. })
  592. this.exceptionTable = resultData
  593. }
  594. })
  595. }).catch(error => {
  596. console.error('Error fetching data:', error)
  597. })
  598. },
  599. getOtherList() {
  600. const data = {
  601. pasge: 1,
  602. size: -1
  603. }
  604. getMaterialsCabinet(data).then((response) => {
  605. console.log(response, '所有物资柜')
  606. let cabinetByWorkstation = {}
  607. response.data.records.forEach((cabinet) => {
  608. if (!cabinetByWorkstation[cabinet.workstationId]) {
  609. cabinetByWorkstation[cabinet.workstationId] = []
  610. }
  611. cabinetByWorkstation[cabinet.workstationId].push(cabinet)
  612. })
  613. this.TicketListPage = cabinetByWorkstation
  614. this.total = response.data.total
  615. this.loading = false
  616. })
  617. listMarsDept(data).then((response) => {
  618. // 新增岗位单选
  619. const data = response.data.records.filter((item) => {
  620. return item.parentId == '0'
  621. })
  622. this.marsOptions = this.handleTree(data, 'workstationId', 'parentId')
  623. // mars岗位树数据
  624. this.workstationOptions = this.transformToTree(data)
  625. // 使用递归函数查找匹配的节点
  626. const selectedTreeNode = this.findNodeById(
  627. this.workstationOptions,
  628. this.queryParams.workstationId
  629. )
  630. // 调用 handleNodeClick 方法
  631. if (selectedTreeNode) {
  632. this.handleNodeClick(selectedTreeNode)
  633. } else {
  634. console.log('未找到匹配的节点')
  635. }
  636. })
  637. // 获取物资柜地图与物资柜对应状态的柜子图片
  638. const sysAttrKey = 'sys.map.cabinet'
  639. getIsSystemAttributeByKey(sysAttrKey).then(response => {
  640. console.log(response, '获取物资柜底图')
  641. this.sysAttrValue = response.data.sysAttrValue
  642. // 这里获取全局配置地图参数里的作业票地图
  643. selectIsMapById(this.sysAttrValue).then((res) => {
  644. console.log(res, '作业票地图 图片数据')
  645. this.jobconfig = res.data
  646. })
  647. const dataMap = {
  648. pages: 1,
  649. size: -1,
  650. mapId: this.sysAttrValue
  651. }
  652. console.log(dataMap,'chaxuncanshu ')
  653. getIsMapPointPage(dataMap).then((res) => {
  654. console.log(res, '作业票地图岗位位置信息接口')
  655. this.jobconfigPoint = res.data
  656. })
  657. })
  658. },
  659. //辅助函数计算超时时间
  660. calculateTimeDifference(occurTime) {
  661. if (!occurTime) return this.$t('mes.lockers.unknown')
  662. // 将时间字符串转换为 Date 对象
  663. const occurDate = new Date(occurTime)
  664. if (isNaN(occurDate.getTime())) {
  665. console.error('Invalid date format:', occurTime)
  666. return this.$t('mes.lockers.unknown')
  667. }
  668. const currentTime = new Date().getTime()
  669. const timeDifference = (currentTime - occurDate.getTime()) / (1000 * 60) // 转换为分钟
  670. if (timeDifference < 1) {
  671. return `${(timeDifference * 60).toFixed(0)}${this.$t('mes.lockers.second')}`
  672. } else if (timeDifference < 60) {
  673. return `${timeDifference.toFixed(1)}${this.$t('mes.lockers.minute')}`
  674. } else {
  675. const hours = Math.floor(timeDifference / 60)
  676. const minutes = (timeDifference % 60).toFixed(0)
  677. return `${hours}${this.$t('mes.lockers.hour')}${minutes}${this.$t('mes.lockers.minute')}`
  678. }
  679. },
  680. // mars岗位树点击事件
  681. handleNodeClick(data) {
  682. this.queryParams.workstationId = data.id //这里给查询传递参数
  683. this.queryParams.workstationName = data.label //这里给回显框显示中文
  684. },
  685. /** 转换mars岗位树数据为树形结构 */
  686. transformToTree(records) {
  687. const recordMap = {} // 创建一个 Map 以存储所有记录
  688. const tree = [] // 最终返回的树形结构
  689. // 初始化所有记录到 Map
  690. records.forEach((record) => {
  691. recordMap[record.workstationId] = {
  692. id: record.workstationId,
  693. label: record.workstationName,
  694. children: []
  695. }
  696. })
  697. // 遍历记录并构建树
  698. records.forEach((record) => {
  699. const parentId = record.parentId
  700. if (parentId === '0') {
  701. // 如果是顶层节点,直接添加到树中
  702. tree.push(recordMap[record.workstationId])
  703. } else if (recordMap[parentId]) {
  704. // 如果有父节点,则将当前节点加入父节点的 children 中
  705. recordMap[parentId].children.push(recordMap[record.workstationId])
  706. }
  707. })
  708. return tree
  709. },
  710. // mars岗位数深层次遍历
  711. findNodeById(nodes, targetId) {
  712. for (let i = 0; i < nodes.length; i++) {
  713. const node = nodes[i]
  714. if (node.id === targetId) {
  715. return node
  716. }
  717. if (node.children && node.children.length > 0) {
  718. const foundNode = this.findNodeById(node.children, targetId)
  719. if (foundNode) {
  720. return foundNode
  721. }
  722. }
  723. }
  724. return null
  725. },
  726. /** 转换mars岗位数据结构 */
  727. Marsnormalizer(node) {
  728. if (node.children && !node.children.length) {
  729. delete node.children
  730. }
  731. return {
  732. id: node.workstationId,
  733. label: node.workstationName,
  734. children: node.children
  735. }
  736. },
  737. // 筛选节点
  738. filterNode(value, data) {
  739. if (!value) return true
  740. return data.label.indexOf(value) !== -1
  741. },
  742. // 岗位查询 清除事件
  743. handleClear() {
  744. this.queryParams.workstationId = ''
  745. this.queryParams.workstationName = ''
  746. this.getList()
  747. },
  748. // 物资柜跳转详情
  749. handleCabinetClick(cabinet) {
  750. this.$router.push({
  751. path: '/mes/material/lockers/DetailsIndex',
  752. query: {
  753. cabinetId: cabinet.cabinetId,
  754. cabinetName: cabinet.cabinetName
  755. }
  756. })
  757. console.log(cabinet, '地图跳转详情拿到的')
  758. },
  759. // 物资柜列表跳转详情
  760. handleLook(row) {
  761. this.$router.push({
  762. path: '/mes/material/lockers/DetailsIndex',
  763. query: { cabinetId: row.cabinetId, cabinetName: row.cabinetName }
  764. })
  765. console.log('列表详情')
  766. },
  767. // 取消按钮
  768. cancel() {
  769. this.open = false
  770. this.reset()
  771. },
  772. // 表单重置
  773. reset() {
  774. this.form = {
  775. cabinetCode: '',
  776. cabinetName: '',
  777. workstationId: '',
  778. remark: '',
  779. cabinetPicture: ''
  780. }
  781. this.resetForm('form')
  782. this.autoGenFlag = false
  783. },
  784. /** 搜索按钮操作 */
  785. handleQuery() {
  786. this.queryParams.current = 1
  787. this.getList()
  788. },
  789. /** 重置按钮操作 */
  790. resetQuery() {
  791. this.createTime = ''
  792. this.queryParams.cabinetCode = null
  793. this.queryParams.cabinetName = null
  794. this.queryParams.cabinetId = null
  795. this.queryParams.status = null
  796. this.resetForm('queryForm')
  797. this.handleQuery()
  798. },
  799. // 多选框选中数据
  800. handleSelectionChange(selection) {
  801. this.ids = selection.map((item) => item.cabinetId)
  802. this.codes = selection.map((item) => item.cabinetCode)
  803. this.single = selection.length !== 1
  804. this.multiple = !selection.length
  805. },
  806. /** 新增按钮操作 */
  807. handleAdd() {
  808. this.reset()
  809. this.open = true
  810. this.form.workstationId = null
  811. this.title = this.$t('mes.lockers.addCabinetInfo')
  812. this.optType = 'add'
  813. },
  814. /** 修改按钮操作 */
  815. handleUpdate(row) {
  816. this.reset()
  817. selectMaterialsCabinetById(row.cabinetId).then((response) => {
  818. this.form = response.data
  819. this.open = true
  820. this.title = this.$t('mes.lockers.editCabinetInfo')
  821. this.optType = 'edit'
  822. })
  823. },
  824. /** 提交按钮 */
  825. submitForm() {
  826. this.$refs['form'].validate((valid) => {
  827. if (valid) {
  828. if (this.form.cabinetId != null) {
  829. updateMaterialsCabinet(this.form).then((response) => {
  830. console.log(response, '修改返回')
  831. this.$modal.msgSuccess(this.$t('mes.lockers.editSuccess'))
  832. this.open = false
  833. this.getList()
  834. })
  835. } else {
  836. addMaterialsCabinet(this.form).then((response) => {
  837. console.log(response, '新增返回')
  838. this.$modal.msgSuccess(this.$t('mes.lockers.addSuccess'))
  839. this.open = false
  840. this.getList()
  841. })
  842. }
  843. }
  844. })
  845. },
  846. /** 删除按钮操作 */
  847. handleDelete(row) {
  848. const cabinetIds = row.cabinetId || this.ids
  849. const cabinetCodes = row.cabinetCode || this.codes
  850. this.$modal
  851. .confirm(this.$t('common.deleteConfirm'))
  852. .then(function() {
  853. return deleteMaterialsCabinet(cabinetIds)
  854. })
  855. .then(() => {
  856. this.getList()
  857. this.$modal.msgSuccess(this.$t('mes.lockers.deleteSuccess'))
  858. })
  859. .catch(() => {
  860. })
  861. },
  862. //图标上传成功
  863. handleIconUplaoded(imgUrl) {
  864. this.form.cabinetPicture = imgUrl[0].url
  865. },
  866. // 图标移除
  867. handleIconRemoved(imgUrl) {
  868. this.form.cabinetPicture = null
  869. },
  870. //自动生成编码
  871. handleAutoGenChange(autoGenFlag) {
  872. if (autoGenFlag) {
  873. genCode('MATERIALS_CABINET').then((response) => {
  874. this.form.cabinetCode = response
  875. })
  876. } else {
  877. this.form.cabinetCode = null
  878. }
  879. }
  880. }
  881. }
  882. </script>
  883. <style lang="scss" src="@/assets/styles/dialog-title.scss" scoped>
  884. </style>
  885. <style scoped lang="scss">
  886. .deptXLG {
  887. position: absolute;
  888. width: 65px;
  889. height: 25px;
  890. background: #70b26f;
  891. line-height: 25px;
  892. text-align: center;
  893. border-radius: 5px;
  894. color: #fff;
  895. cursor: pointer;
  896. }
  897. //图片放大
  898. .img-box {
  899. width: 75px;
  900. height: 75px;
  901. position: relative;
  902. #eyeicon {
  903. display: none;
  904. }
  905. }
  906. .img-box:hover {
  907. background: #000;
  908. .images {
  909. opacity: 0.6;
  910. }
  911. #eyeicon {
  912. display: block;
  913. position: absolute;
  914. top: 40%;
  915. left: 40%;
  916. z-index: 100;
  917. color: white;
  918. pointer-events: none;
  919. }
  920. }
  921. .el-input-width {
  922. width: 380px !important;
  923. }
  924. .app-container {
  925. width: 100%;
  926. height: 100%;
  927. // background: green;
  928. .CabinetListcon {
  929. width: 100%;
  930. height: 100%;
  931. display: flex;
  932. // background: pink;
  933. .left {
  934. width: 15%;
  935. height: 100%;
  936. margin-right: 10px;
  937. // background: rgb(175, 214, 175);
  938. .deptTree {
  939. width: 100%;
  940. height: 90%;
  941. // background: rgb(199, 252, 247);
  942. }
  943. }
  944. .right {
  945. width: 83%;
  946. height: 100%;
  947. // background: yellow;
  948. }
  949. }
  950. }
  951. </style>