index.vue 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623
  1. <template>
  2. <div class="main-container">
  3. <ibps-container
  4. class="page"
  5. >
  6. <template>
  7. <ibps-crud
  8. key="istree"
  9. ref="crud"
  10. :data="listData"
  11. :toolbars="listConfig.toolbars"
  12. :search-form="listConfig.searchForm"
  13. :pk-key="pkKey"
  14. :columns="listConfig.columns"
  15. :loading="loading"
  16. :pagination="pagination"
  17. :display-field="tableTitle"
  18. :index-row="false"
  19. @sort-change="handleSortChange"
  20. @action-event="handleAction"
  21. @pagination-change="handlePaginationChange"
  22. >
  23. <template
  24. slot="posSlot"
  25. slot-scope="{row}"
  26. >
  27. <ibps-user-selector
  28. v-model="row.bianZhiBuMen"
  29. type="position"
  30. readonly-text="text"
  31. :multiple="true"
  32. :disabled="true"
  33. />
  34. </template>
  35. <template
  36. slot="userSlot"
  37. slot-scope="{row}"
  38. >
  39. <ibps-user-selector
  40. v-model="row.guanLiRen"
  41. type="user"
  42. readonly-text="text"
  43. :multiple="true"
  44. :disabled="true"
  45. />
  46. </template>
  47. <template
  48. slot="deviceSlot"
  49. slot-scope="{row}"
  50. >
  51. <ibps-custom-dialog
  52. v-model="row.weiHuFangShi"
  53. size="mini"
  54. template-key="sbbqdhk"
  55. multiple
  56. :disabled="true"
  57. type="dialog"
  58. class="custom-dialog"
  59. placeholder="请选择"
  60. icon="el-icon-search"
  61. />
  62. </template>
  63. <template
  64. slot="placeSlot"
  65. slot-scope="{row}"
  66. >
  67. <ibps-custom-dialog
  68. v-model="row.cunFangWeiZhi"
  69. size="mini"
  70. template-key="fjxzkdd"
  71. multiple
  72. :disabled="true"
  73. type="dialog"
  74. class="custom-dialog"
  75. placeholder="请选择"
  76. icon="el-icon-search"
  77. />
  78. </template>
  79. <template
  80. slot="customButton"
  81. slot-scope="{row}"
  82. >
  83. <el-button type="text" icon="el-icon-edit-outline" @click="goEdit(row)">修改</el-button>
  84. <!-- <el-button type="text" icon="el-icon-view" @click="goLook(row)">查阅</el-button> -->
  85. <el-button type="text" icon="ibps-icon-table" @click="goLookForm(row)">表单</el-button>
  86. </template>
  87. <template
  88. slot="expandSlot"
  89. slot-scope="{row}"
  90. >
  91. <el-row :gutter="20" style="height:145px;padding:0 20px 0 0" type="flex" align="middle">
  92. <el-col :span="5" :push="2">
  93. <el-row>
  94. <el-col :span="3">
  95. <el-image
  96. class="icon-image"
  97. :src="images[0]"
  98. fit="contain"
  99. />
  100. </el-col>
  101. <el-col :span="21">
  102. <div class="title">验收信息</div>
  103. <div class="ctx">
  104. <div class="item">接收日期:{{ row.jieShouRiQi || '/' }}</div>
  105. <div class="item">验收日期:{{ row.yanShouRiQi || '/' }}</div>
  106. <div class="item">核查日期:{{ row.biXuSheShi || '/' }}</div>
  107. </div>
  108. </el-col>
  109. </el-row>
  110. </el-col>
  111. <el-col :span="5" :push="2">
  112. <el-row>
  113. <el-col :span="3">
  114. <el-image
  115. class="icon-image"
  116. :src="images[1]"
  117. fit="contain"
  118. />
  119. </el-col>
  120. <el-col :span="21">
  121. <div class="title">建档信息</div>
  122. <div class="ctx">
  123. <div class="item">
  124. <div class="cusitem">
  125. <span class="span">建档人:</span>
  126. <ibps-user-selector
  127. :value="row.bianZhiRen"
  128. type="user"
  129. readonly-text="text"
  130. :multiple="true"
  131. :disabled="true"
  132. size="mini"
  133. style="width:100px"
  134. />
  135. </div>
  136. </div>
  137. <div class="item">
  138. <div class="cusitem">
  139. <span class="span">建档部门:</span>
  140. <ibps-user-selector
  141. :value="row.bianZhiBuMen"
  142. type="position"
  143. readonly-text="text"
  144. :disabled="true"
  145. :multiple="false"
  146. size="mini"
  147. style="width:100px"
  148. />
  149. </div>
  150. </div>
  151. <div class="item">建档时间:{{ row.bianZhiShiJian || '/' }}</div>
  152. </div>
  153. </el-col>
  154. </el-row>
  155. </el-col>
  156. <el-col :span="5" :push="2">
  157. <el-row>
  158. <el-col :span="3">
  159. <el-image
  160. class="icon-image"
  161. :src="images[2]"
  162. fit="contain"
  163. />
  164. </el-col>
  165. <el-col :span="21">
  166. <div class="title">维护信息</div>
  167. <div class="ctx">
  168. <div class="item">是否维护:{{ row.shiFouWeiHu || '/' }}</div>
  169. <div class="item">是否24H开机:{{ row.jianKongYiJu || '/' }}</div>
  170. <div class="item">是否限用:{{ row.xiaoZhunWuCha || '/' }}</div>
  171. </div>
  172. </el-col>
  173. </el-row>
  174. </el-col>
  175. <el-col :span="5" :push="2">
  176. <el-row>
  177. <el-col :span="3">
  178. <el-image
  179. class="icon-image"
  180. :src="images[3]"
  181. fit="contain"
  182. />
  183. </el-col>
  184. <el-col :span="21">
  185. <div class="title">校准信息</div>
  186. <div class="ctx">
  187. <div class="item">是否校准:{{ row.shiFouXiaoZhun || '/' }}</div>
  188. <div class="item">校准周期:{{ row.xiaoZhunZQ?`${row.xiaoZhunZQ}月` : '/' }}</div>
  189. <div class="item">最近校准时间:{{ row.yiXiaoRiQi || '/' }}</div>
  190. </div>
  191. </el-col>
  192. </el-row>
  193. </el-col>
  194. <el-col :span="4" :push="1">
  195. <el-row>
  196. <el-col :span="24">
  197. <el-image
  198. class="device-image"
  199. :src="ImageUrl(row)"
  200. fit="fill"
  201. :preview-src-list="ImageAllUrl(row)"
  202. :title="`[${row.sheBeiMingCheng}]设备首图,点击查看更多`"
  203. >
  204. <div slot="error" class="image-slot">
  205. <el-empty class="device-image" description="暂无图片" :image-size="70" />
  206. </div>
  207. </el-image>
  208. </el-col>
  209. </el-row>
  210. </el-col>
  211. </el-row>
  212. </template>
  213. <!-- 搜索条件 -->
  214. <template slot="pos">
  215. <ibps-user-selector
  216. v-model="search.pos"
  217. type="position"
  218. readonly-text="text"
  219. :multiple="true"
  220. size="mini"
  221. :filter="filter"
  222. filtrate
  223. />
  224. </template>
  225. <template slot="time">
  226. <el-date-picker
  227. v-model="search.time"
  228. size="mini"
  229. type="daterange"
  230. :picker-options="pickerOptions"
  231. range-separator="至"
  232. start-placeholder="开始日期"
  233. end-placeholder="结束日期"
  234. align="right"
  235. value-format="yyyy-MM-dd"
  236. />
  237. </template>
  238. <template slot="nowNumber">
  239. <el-input v-model="search.nowNumber" size="mini" />
  240. </template>
  241. <template slot="preNumber">
  242. <el-input v-model="search.preNumber" size="mini" />
  243. </template>
  244. <template slot="deviceName">
  245. <el-input v-model="search.deviceName" size="mini" />
  246. </template>
  247. <template slot="deviceType">
  248. <el-select v-model="search.deviceType" placeholder="请选择" size="mini" :clearable="true">
  249. <el-option
  250. v-for="item in ['检验系统','通用设备','软件','信息系统']"
  251. :key="item"
  252. :label="item"
  253. :value="item"
  254. />
  255. </el-select>
  256. </template>
  257. <template slot="deviceStatus">
  258. <el-select v-model="search.deviceStatus" placeholder="请选择" size="mini" :clearable="true">
  259. <el-option
  260. v-for="item in ['合格','限用','停用','报废']"
  261. :key="item"
  262. :label="item"
  263. :value="item"
  264. />
  265. </el-select>
  266. </template>
  267. <template slot="place">
  268. <el-input v-model="search.place" size="mini" />
  269. </template>
  270. <template slot="managePeople">
  271. <ibps-user-selector
  272. v-model="search.managePeople"
  273. type="user"
  274. readonly-text="text"
  275. :multiple="true"
  276. size="mini"
  277. :filter="filter"
  278. filtrate
  279. />
  280. </template>
  281. <template slot="deviceClass">
  282. <ibps-custom-dialog
  283. v-model="search.deviceClass"
  284. size="mini"
  285. template-key="sbbqdhk"
  286. multiple
  287. :disabled="false"
  288. type="dialog"
  289. class="custom-dialog"
  290. placeholder="请选择"
  291. icon="el-icon-search"
  292. />
  293. </template>
  294. </ibps-crud>
  295. </template>
  296. </ibps-container>
  297. <DeviceDialog v-if="deviceDialogShow" :params="params" @close="close" />
  298. <input id="" ref="file1" type="file" name="" accept=".xlsx,.xls" @change="handleUploadChange1">
  299. <input id="" ref="file2" type="file" name="" accept=".xlsx,.xls" @change="handleUploadChange2">
  300. <custom-dialog
  301. :visible="customDialogVisible"
  302. :value="[]"
  303. template-key="sbfzpz"
  304. :dynamic-params="{}"
  305. @close="(visible) => (customDialogVisible = visible)"
  306. />
  307. <bpmn-formrender
  308. :visible="npmDialogFormVisible"
  309. def-id="1120718364969271296"
  310. @close="visible => npmDialogFormVisible = visible"
  311. />
  312. <DeviceTag :scan-visible="printVisible" :obj="printObj" @scanOff="scanOff" />
  313. <el-dialog
  314. :close-on-click-modal="false"
  315. :close-on-press-escape="false"
  316. :top="'3vh'"
  317. :width="'90%'"
  318. class="js-custom-dialog"
  319. append-to-body
  320. :fullscreen="false"
  321. :visible.sync="iframeVisible"
  322. >
  323. <iframe :src="srcUrl" :height="'100%'" :width="'100%'" frameborder="0" scrolling="no" />
  324. </el-dialog>
  325. </div>
  326. </template>
  327. <script>
  328. import image01 from '@/assets/images/device/01.png'
  329. import image02 from '@/assets/images/device/02.png'
  330. import image03 from '@/assets/images/device/03.png'
  331. import image04 from '@/assets/images/device/04.png'
  332. import { getImage } from '@/api/platform/file/attachment'
  333. import xlsx from 'xlsx'
  334. import fs from 'file-saver'
  335. import DataTemplateFormrenderDialog from '@/business/platform/data/templaterender/form/dialog.vue'
  336. import ActionUtils from '@/utils/action'
  337. import FixHeight from '@/mixins/height'
  338. import ibpsUserSelector from '@/business/platform/org/selector'
  339. import DeviceDialog from './deviceDialog.vue'
  340. import { queryequipmentCard, removeEquipmentCard, getequipmentCard, saveEquipmentCard } from '@/api/platform/device/device'
  341. import CustomDialog from '@/business/platform/data/templaterender/custom-dialog/dialog'
  342. import dayjs from 'dayjs'
  343. import DeviceTag from '@/views/system/jbdScan/goods/deviceTag.vue'
  344. export default {
  345. components: {
  346. DeviceTag,
  347. DataTemplateFormrenderDialog,
  348. DeviceDialog,
  349. ibpsUserSelector,
  350. CustomDialog,
  351. IbpsCustomDialog: () => import('@/business/platform/data/templaterender/custom-dialog')
  352. },
  353. mixins: [FixHeight],
  354. data () {
  355. const { userId, level = {}, position } = this.$store.getters || {}
  356. return {
  357. filter: [{
  358. descVal: '1',
  359. includeSub: true,
  360. old: 'position',
  361. partyId: this.$store.getters.userInfo.employee.positions,
  362. partyName: '',
  363. scriptContent: '',
  364. type: 'user',
  365. userType: 'position'
  366. }],
  367. images: [image01, image02, image03, image04],
  368. ImportDeviceType: '',
  369. iframeVisible: false,
  370. srcUrl: '',
  371. printObj: [],
  372. printVisible: false,
  373. DialogVisible: true,
  374. npmDialogFormVisible: false,
  375. customDialogVisible: false,
  376. pickerOptions: {
  377. shortcuts: [{
  378. text: '最近一周',
  379. onClick (picker) {
  380. const end = new Date()
  381. const start = new Date()
  382. start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
  383. picker.$emit('pick', [start, end])
  384. }
  385. }, {
  386. text: '最近一个月',
  387. onClick (picker) {
  388. const end = new Date()
  389. const start = new Date()
  390. start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
  391. picker.$emit('pick', [start, end])
  392. }
  393. }, {
  394. text: '最近三个月',
  395. onClick (picker) {
  396. const end = new Date()
  397. const start = new Date()
  398. start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
  399. picker.$emit('pick', [start, end])
  400. }
  401. }]
  402. },
  403. params: {},
  404. deviceDialogShow: false,
  405. position: position,
  406. level: level.second || level.first,
  407. userId: userId,
  408. search: {
  409. pos: '',
  410. time: [],
  411. nowNumber: '',
  412. preNumber: '',
  413. deviceName: '',
  414. deviceType: '',
  415. deviceStatus: '',
  416. place: '',
  417. managePeople: '',
  418. deviceClass: ''
  419. },
  420. loading: false,
  421. pkKey: 'id', // 主键 如果主键不是pk需要传主键
  422. pkValue: '',
  423. templateKey: '',
  424. visible: false,
  425. categoryKey: '',
  426. tableTitle: '设备基本信息列表', // 标题
  427. listData: [],
  428. selectListData: [], // 全部数据
  429. bianlistData: {
  430. dataResult: [],
  431. pageResult: {
  432. limit: 0,
  433. page: 0,
  434. totalCount: 0,
  435. totalPages: 0
  436. }
  437. },
  438. listConfig: {
  439. // 工具栏
  440. toolbars: [
  441. { key: 'search' },
  442. { key: 'customAdd', label: '设备建档', icon: 'ibps-icon-plus', type: 'success' },
  443. { key: 'customBpm', label: '设备台账', icon: 'ibps-icon-file-text', type: 'info' },
  444. { key: 'customPrint', label: '打印标签', icon: 'ibps-icon-cog', type: 'warning' },
  445. { key: 'customExport', label: '导出数据', icon: 'ibps-icon-sign-in', type: 'primary' },
  446. { key: 'customImport', label: '导入数据', icon: 'ibps-icon-sign-in', type: 'primary' },
  447. { key: 'customSetting', label: '设置分组配置', icon: 'ibps-icon-cogs', type: 'info' },
  448. { key: 'customRemove', label: '删除', icon: 'ibps-icon-close', type: 'danger' }
  449. ],
  450. // 查询条件
  451. searchForm: {
  452. forms: [
  453. { prop: '', label: '部门', fieldType: 'slot', slotName: 'pos' }, // user 插槽
  454. { prop: '', label: '建档时间', fieldType: 'slot', slotName: 'time' },
  455. { prop: '', label: '设备编号', fieldType: 'slot', slotName: 'nowNumber' },
  456. { prop: '', label: '原设备编号', fieldType: 'slot', slotName: 'preNumber' },
  457. { prop: '', label: '设备名称', fieldType: 'slot', slotName: 'deviceName' },
  458. { prop: '', label: '设备类型', fieldType: 'slot', slotName: 'deviceType' },
  459. { prop: '', label: '设备状态', fieldType: 'slot', slotName: 'deviceStatus' },
  460. { prop: '', label: '放置地点', fieldType: 'slot', slotName: 'place' },
  461. { prop: '', label: '管理人', fieldType: 'slot', slotName: 'managePeople' },
  462. { prop: '', label: '设备分组', fieldType: 'slot', slotName: 'deviceClass' }
  463. ]
  464. },
  465. // 表格字段配置
  466. columns: [
  467. { type: 'expand', slotName: 'expandSlot' },
  468. { prop: 'bianZhiBuMen', label: '部门', slotName: 'posSlot', sortable: true },
  469. { prop: 'bianZhiShiJian', label: '建档时间', sortable: true },
  470. { prop: 'sheBeiShiBieH', label: '设备编号', sortable: true },
  471. { prop: 'yuanSheBeiBian', label: '原设备编号', sortable: true },
  472. { prop: 'sheBeiMingCheng', label: '设备名称', sortable: true },
  473. { prop: 'sheBeiLeiXing', label: '设备类型', sortable: true },
  474. { prop: 'guiGeXingHao', label: '规格型号', sortable: true },
  475. { prop: 'sheBeiZhuangTa', label: '设备状态', sortable: true },
  476. { prop: 'guanLiRen', label: '保管人', slotName: 'userSlot', sortable: true },
  477. { prop: 'weiHuFangShi', label: '设备分组', slotName: 'deviceSlot', sortable: true },
  478. { prop: 'cunFangWeiZhi', label: '放置地点', slotName: 'placeSlot', sortable: true },
  479. { prop: '', label: '操作', width: 130, slotName: 'customButton' }
  480. ]
  481. },
  482. pagination: {
  483. limit: 20, page: 1
  484. },
  485. sorts: [{ field: 'BIAN_ZHI_SHI_JIAN', order: 'desc' }],
  486. sqlWhere: {},
  487. searchWhere: {},
  488. deviceColumns: {
  489. bianZhiBuMen: '部门',
  490. sheBeiMingCheng: '设备名称',
  491. sheBeiShiBieH: '设备编号(导入无需填写)',
  492. yuanSheBeiBian: '原设备编号(必填,且不可重复)',
  493. sheBeiZhuangTa: '设备状态(合格/停用/限用)',
  494. sheBeiLeiXing: '设备类型(检验系统/通用设备/软件/信息系统)',
  495. guiGeXingHao: '规格型号',
  496. cunFangDiDian: '存放地点',
  497. guanLiRen: '保管人',
  498. ziChanBianHao: '资产编号',
  499. gongYingShang: '供应商',
  500. lianXiFangShi: '联系方式',
  501. changShang: '厂商',
  502. chuChangRiQi: '出厂日期',
  503. jiShenXuHao: '机身序号',
  504. zhuCeZhengHao: '注册证号',
  505. ceLiangGongZuo: '测量范围',
  506. huanJingYaoQiu: '环境要求',
  507. dianYuanYaoQiu: '电源要求',
  508. yanShouRiQi: '验收日期',
  509. jieShouRiQi: '接收日期',
  510. jieShouZhuangTai: '接收时状态(新设备/二手或翻新设备)',
  511. qiYongRiQi: '投入日期',
  512. shiFouXiaoZhun: '是否校准(是/否)',
  513. yiXiaoRiQi: '已校日期',
  514. xiaoZhunZQ: '检定/校准周期(以月为单位)',
  515. xiaoZhunYouXia: '校准有效期至',
  516. jianDingXiao: '检定/校准参数',
  517. zuiDaYunCha: 'U/精确度/最大允差',
  518. zhengShuBianHa: '证书编号',
  519. xiuZhengZhiXiu: '修正值/修正因子',
  520. // wenDuYingYong:'温度应用修正值',
  521. // shiDuYingYong:'湿度应用修正值',
  522. shiFouWeiHu: '是否维护(是/否)',
  523. biXuDeHuanJin: '核查人',
  524. biXuSheShi: '核查日期',
  525. weiHuFangShi: '设备分组',
  526. heChaXiaoZhun: '使用年限(年)'
  527. },
  528. projectColums: {
  529. yuanSheBeiBian: '设备编号*',
  530. sheBeiMingCheng: '设备名称*',
  531. weiHuLeiXing: '维护类型*(日保养/周保养/月保养/季度保养/半年保养/年保养/按需保养)',
  532. weiHuRiQi: '维护日期*',
  533. weiHuXiangMuC: '维护项目*'
  534. },
  535. dateFieldRange: ['chuChangRiQi', 'yanShouRiQi', 'jieShouRiQi', 'qiYongRiQi', 'yiXiaoRiQi', 'xiaoZhunYouXia', 'biXuSheShi'],
  536. requiredFieldMap: {
  537. bianZhiBuMen: '部门',
  538. sheBeiMingCheng: '设备名称',
  539. yuanSheBeiBian: '原设备编号',
  540. sheBeiZhuangTa: '设备状态',
  541. sheBeiLeiXing: '设备类型',
  542. shiFouWeiHu: '是否维护',
  543. shiFouXiaoZhun: '是否校准'
  544. },
  545. dateFieldsMap: {
  546. 'chuChangRiQi': '出厂日期',
  547. 'yanShouRiQi': '验收日期',
  548. 'jieShouRiQi': '接收日期',
  549. 'qiYongRiQi': '投入日期',
  550. 'yiXiaoRiQi': '已校日期',
  551. 'xiaoZhunYouXia': '校准有效期至',
  552. 'biXuSheShi': '核查日期'
  553. },
  554. validationRules: {
  555. '设备状态': {
  556. field: 'sheBeiZhuangTa',
  557. range: ['合格', '停用', '限用']
  558. },
  559. '设备类型': {
  560. field: 'sheBeiLeiXing',
  561. range: ['检验系统', '通用设备', '软件', '信息系统']
  562. },
  563. '接收时状态': {
  564. field: 'jieShouZhuangTai',
  565. range: ['新设备', '二手或翻新设备']
  566. },
  567. '是否校准': {
  568. field: 'shiFouXiaoZhun',
  569. range: ['是', '否']
  570. },
  571. '是否维护': {
  572. field: 'shiFouWeiHu',
  573. range: ['是', '否']
  574. }
  575. },
  576. numberFieldsMap: {
  577. 'xiaoZhunZQ': '检定/校准周期(以月为单位)',
  578. 'heChaXiaoZhun': '使用年限(年)'
  579. },
  580. maintenanceRequiredFieldMap: {
  581. yuanSheBeiBian: '原设备编号',
  582. sheBeiMingCheng: '设备名称',
  583. weiHuLeiXing: '维护类型',
  584. weiHuRiQi: '维护日期',
  585. weiHuXiangMuC: '维护项目'
  586. },
  587. maintenanceValidationRules: {
  588. '维护类型': {
  589. field: 'weiHuLeiXing',
  590. range: ['日保养', '周保养', '月保养', '季度保养', '半年保养', '年保养', '按需保养']
  591. }
  592. },
  593. maintenanceDateValidationRules: {
  594. '日保养': this.generateDayRule(),
  595. '周保养': this.generateRule(7, `每周`, ``),
  596. '月保养': this.generateRule(28, `每月第`, `日`),
  597. '半年保养': this.generateRule(6, `每半年第`, `个月`),
  598. '季度保养': this.generateRule(3, `每季度第`, `个月`),
  599. '年保养': this.generateRule(12, `每年第`, `个月`),
  600. '按需保养': ['/']
  601. }
  602. }
  603. },
  604. mounted () {
  605. this.getDatas()
  606. },
  607. methods: {
  608. ImageAllUrl (row) {
  609. if (row && row.buMen) {
  610. const imgId = row.buMen.split(',')
  611. return imgId.map(item => getImage(item))
  612. }
  613. return []
  614. },
  615. ImageUrl (row) {
  616. if (row && row.buMen) {
  617. const imgId = row.buMen.split(',')[0]
  618. return getImage(imgId)
  619. }
  620. return ''
  621. },
  622. async getDatas () {
  623. this.loading = true
  624. const parameters = {
  625. relation: 'AND',
  626. parameters: []
  627. }
  628. // 增加地点过滤
  629. const obj = { relation: 'AND', parameters: [] }
  630. obj.parameters.push({ key: 'Q^di_dian_^S', value: this.level, param: this.$utils.guid() })
  631. parameters.parameters.push(obj)
  632. // 部门搜索(可多选)
  633. if (this.search.pos) {
  634. const obj = { relation: 'OR', parameters: [] }
  635. this.search.pos.split(',').forEach(item => {
  636. obj.parameters.push({ key: 'Q^bian_zhi_bu_men_^S', value: item, param: this.$utils.guid() })
  637. })
  638. parameters.parameters.push(obj)
  639. }
  640. // 建档时间搜索
  641. if (this.search.time && this.search.time.length === 2) {
  642. const obj = { relation: 'AND', parameters: [] }
  643. obj.parameters.push({ key: 'Q^bian_zhi_shi_jian^DL^yyyy-MM-dd', value: this.search.time[0], param: this.$utils.guid() })
  644. obj.parameters.push({ key: 'Q^bian_zhi_shi_jian^DG^yyyy-MM-dd', value: this.search.time[1], param: this.$utils.guid() })
  645. parameters.parameters.push(obj)
  646. }
  647. // 设备编号搜索
  648. if (this.search.nowNumber) {
  649. const obj = { relation: 'AND', parameters: [] }
  650. obj.parameters.push({ key: 'Q^she_bei_shi_bie_h^SL', value: this.search.nowNumber, param: this.$utils.guid() })
  651. parameters.parameters.push(obj)
  652. }
  653. // 原设备编号搜索
  654. if (this.search.preNumber) {
  655. const obj = { relation: 'AND', parameters: [] }
  656. obj.parameters.push({ key: 'Q^yuan_she_bei_bian^SL', value: this.search.preNumber, param: this.$utils.guid() })
  657. parameters.parameters.push(obj)
  658. }
  659. // 设备名称搜索
  660. if (this.search.deviceName) {
  661. const obj = { relation: 'AND', parameters: [] }
  662. obj.parameters.push({ key: 'Q^she_bei_ming_cheng_^SL', value: this.search.deviceName, param: this.$utils.guid() })
  663. parameters.parameters.push(obj)
  664. }
  665. // 设备类型搜索
  666. if (this.search.deviceType) {
  667. const obj = { relation: 'AND', parameters: [] }
  668. obj.parameters.push({ key: 'Q^she_bei_lei_xing_^S', value: this.search.deviceType, param: this.$utils.guid() })
  669. parameters.parameters.push(obj)
  670. }
  671. // 设备状态搜索
  672. if (this.search.deviceStatus) {
  673. const obj = { relation: 'AND', parameters: [] }
  674. obj.parameters.push({ key: 'Q^she_bei_zhuang_ta^S', value: this.search.deviceStatus, param: this.$utils.guid() })
  675. parameters.parameters.push(obj)
  676. }
  677. // 放置地点搜索
  678. if (this.search.place) {
  679. const obj = { relation: 'AND', parameters: [] }
  680. obj.parameters.push({ key: 'Q^cun_fang_di_dian_^SL', value: this.search.place, param: this.$utils.guid() })
  681. parameters.parameters.push(obj)
  682. }
  683. // 保管人搜索(可多选)
  684. if (this.search.managePeople) {
  685. const obj = { relation: 'OR', parameters: [] }
  686. this.search.managePeople.split(',').forEach(item => {
  687. obj.parameters.push({ key: 'Q^guan_li_ren_^S', value: item, param: this.$utils.guid() })
  688. })
  689. parameters.parameters.push(obj)
  690. }
  691. // 设备分组搜索(可多选)
  692. if (this.search.deviceClass) {
  693. const obj = { relation: 'OR', parameters: [] }
  694. this.search.deviceClass.split(',').forEach(item => {
  695. obj.parameters.push({ key: 'Q^wei_hu_fang_shi_^S', value: item, param: this.$utils.guid() })
  696. })
  697. parameters.parameters.push(obj)
  698. }
  699. const params = {
  700. requestPage: {
  701. pageNo: this.pagination.page,
  702. limit: this.pagination.limit
  703. },
  704. sorts: this.sorts
  705. }
  706. if (parameters.parameters.length > 0) {
  707. params.parameters = [parameters]
  708. }
  709. const { data: { dataResult, pageResult }} = await queryequipmentCard(params)
  710. this.bianlistData.pageResult = pageResult
  711. this.bianlistData.dataResult = dataResult
  712. ActionUtils.handleListData(this, this.bianlistData) // 调用内置方法
  713. this.loading = false
  714. },
  715. // 查看表单
  716. goLookForm (row) {
  717. const first = this.$store.getters.level.first
  718. this.srcUrl = this.$reportPath.replace('show', 'pdf') + '设备/设备档案卡.rpx&id_=' + row.id + '&org_=' + first
  719. this.iframeVisible = true
  720. },
  721. // 按钮事件处理
  722. handleAction (command, position, selection, data, index, button) {
  723. switch (command) {
  724. case 'search':// 查询
  725. this.getDatas()
  726. break
  727. case 'customAdd':
  728. this.handleCustomAdd()
  729. break
  730. case 'customSetting':
  731. this.handleCustomSetting()
  732. break
  733. case 'customRemove':
  734. this.handleCustomRemove(selection)
  735. break
  736. case 'customExport':
  737. this.handleCustomExport(selection, data)
  738. break
  739. case 'customImport':
  740. this.handleCustomImport()
  741. break
  742. case 'customBpm':
  743. this.handleCustomBpm()
  744. break
  745. case 'customPrint':
  746. this.handleCustomPrint(selection)
  747. break
  748. default:
  749. break
  750. }
  751. },
  752. // 打印标签
  753. handleCustomPrint (selection = []) {
  754. if (selection.length === 0) {
  755. return this.$message.warning('请先选择需要打印标签的数据!')
  756. }
  757. this.printObj = selection
  758. this.printVisible = true
  759. },
  760. // 关闭标签
  761. scanOff () {
  762. this.printVisible = false
  763. },
  764. // 设备台账
  765. handleCustomBpm () {
  766. this.npmDialogFormVisible = true
  767. },
  768. // 处理分页事件
  769. async handlePaginationChange (page) {
  770. ActionUtils.setPagination(this.pagination, page)
  771. this.getDatas()
  772. },
  773. // 处理排序
  774. handleSortChange (sort) {
  775. function removeUnderscores (str) {
  776. return str.replace(/^_+|_+$/g, '')
  777. }
  778. const { order, sortBy } = sort
  779. let s = ''
  780. switch (sortBy) {
  781. case 'BIAN_ZHI_SHI_JIAN_':
  782. case 'SHE_BEI_SHI_BIE_H_':
  783. case 'YUAN_SHE_BEI_BIAN_':
  784. case 'SHE_BEI_ZHUANG_TA_':
  785. s = removeUnderscores(sortBy)
  786. break
  787. default:
  788. s = sortBy
  789. }
  790. let o = null
  791. if (order === 'descending') {
  792. o = 'desc'
  793. } else if (order === 'ascending') {
  794. o = 'asc'
  795. }
  796. this.sorts = [{ field: s, order: o }]
  797. this.getDatas()
  798. },
  799. handleCustomAdd () {
  800. this.params = {}
  801. this.deviceDialogShow = true
  802. },
  803. close () {
  804. this.deviceDialogShow = false
  805. this.getDatas()
  806. },
  807. goEdit (row) {
  808. this.params = row
  809. this.deviceDialogShow = true
  810. },
  811. handleCustomSetting () {
  812. this.customDialogVisible = true
  813. },
  814. handleCustomRemove (selection) {
  815. console.log('selection', selection)
  816. if (!selection || selection.length === 0) {
  817. return this.$message.warning('请选择要删除的数据!')
  818. }
  819. this.$confirm('确定删除所选项?删除后无法恢复!', '提示', {
  820. confirmButtonText: '继续',
  821. cancelButtonText: '取消',
  822. type: 'warning'
  823. }).then(async () => {
  824. await removeEquipmentCard({
  825. ids: selection + ''
  826. })
  827. // 删除后刷新
  828. await this.getDatas()
  829. this.$message.success('删除成功!')
  830. }).catch(() => {})
  831. },
  832. // 导出
  833. handleCustomExport (selection, data) {
  834. this.$confirm('请选择导出的类型', '提示', {
  835. confirmButtonText: '导出设备',
  836. cancelButtonText: '导出维护项目',
  837. closeOnClickModal: false,
  838. closeOnPressEscape: false,
  839. distinguishCancelAndClose: true,
  840. type: 'info'
  841. }).then(() => {
  842. this.ExportDevice(selection, data)
  843. }).catch((action) => {
  844. if (action === 'close') return
  845. if (action === 'cancel') {
  846. this.ExportProject(selection, data)
  847. }
  848. })
  849. },
  850. // 导入
  851. handleCustomImport () {
  852. this.$confirm('确请选择导入的类型', '提示', {
  853. confirmButtonText: '导入设备',
  854. cancelButtonText: '导入维护项目',
  855. closeOnClickModal: false,
  856. closeOnPressEscape: false,
  857. distinguishCancelAndClose: true,
  858. type: 'info'
  859. }).then(() => {
  860. this.ImportDevice()
  861. }).catch((action) => {
  862. if (action === 'close') return
  863. if (action === 'cancel') {
  864. this.$confirm('请选择设备维护项目导入类型', '提示', {
  865. confirmButtonText: '增量添加',
  866. cancelButtonText: '全量替换',
  867. closeOnClickModal: false,
  868. closeOnPressEscape: false,
  869. distinguishCancelAndClose: true,
  870. type: 'info'
  871. }).then(() => {
  872. this.ImportDeviceType = '增量添加'
  873. this.ImportProject()
  874. }).catch((action) => {
  875. if (action === 'close') return
  876. if (action === 'cancel') {
  877. this.ImportDeviceType = '全量替换'
  878. this.ImportProject()
  879. }
  880. })
  881. }
  882. })
  883. },
  884. // 导入设备
  885. ImportDevice () {
  886. this.$refs.file1.click()
  887. console.log('导入设备')
  888. },
  889. // 导入维护项目
  890. ImportProject () {
  891. this.$refs.file2.click()
  892. console.log('导入维护项目')
  893. },
  894. getTimeStamp () {
  895. return dayjs().format('YYYYMMDDHHmmss')
  896. },
  897. xlsx (json, fields, filename = '.xlsx') { // 导出xlsx
  898. json.forEach(item => {
  899. for (const i in item) {
  900. if (fields.hasOwnProperty(i)) {
  901. item[fields[i]] = item[i]
  902. }
  903. delete item[i] // 删除原先的对象属性
  904. }
  905. })
  906. const sheetName = filename // excel的文件名称
  907. const wb = xlsx.utils.book_new() // 工作簿对象包含一SheetNames数组,以及一个表对象映射表名称到表对象。XLSX.utils.book_new实用函数创建一个新的工作簿对象。
  908. const ws = xlsx.utils.json_to_sheet(json, { header: Object.values(fields) }) // 将JS对象数组转换为工作表。
  909. wb.SheetNames.push(sheetName)
  910. wb.Sheets[sheetName] = ws
  911. const defaultCellStyle = { font: { name: 'Verdana', sz: 13, color: 'FF00FF88' }, fill: { fgColor: { rgb: 'FFFFAA00' }}}// 设置表格的样式
  912. const wopts = { bookType: 'xlsx', bookSST: false, type: 'binary', cellStyles: true, defaultCellStyle: defaultCellStyle, showGridLines: false } // 写入的样式
  913. const wbout = xlsx.write(wb, wopts)
  914. const blob = new Blob([this.s2ab(wbout)], { type: 'application/octet-stream' })
  915. fs.saveAs(blob, filename + '.xlsx')
  916. },
  917. s2ab (s) {
  918. let buf
  919. if (typeof ArrayBuffer !== 'undefined') {
  920. buf = new ArrayBuffer(s.length)
  921. const view = new Uint8Array(buf)
  922. for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff
  923. return buf
  924. } else {
  925. buf = new Array(s.length)
  926. for (let i = 0; i !== s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF
  927. return buf
  928. }
  929. },
  930. async switchExportData (data) {
  931. const deviceGroupSql = `select id_,wei_hu_gang_wei_ from t_sbwhgwpzb` // 设备分组信息
  932. const { variables: { data: deviceGroupData }} = await this.$common.request('sql', deviceGroupSql)
  933. const exportData = JSON.parse(JSON.stringify(data))
  934. for (let i = 0; i < exportData.length; i++) {
  935. const item = exportData[i]
  936. item.bianZhiBuMen = this.switchIdToDept(item.bianZhiBuMen.split(',')[0])
  937. item.guanLiRen = this.switchIdToUserName(item.guanLiRen.split(',')[0])
  938. item.biXuDeHuanJin = this.switchIdToUserName(item.biXuDeHuanJin.split(',')[0])
  939. item.weiHuFangShi = this.switchDeviceIdToName(item.weiHuFangShi, deviceGroupData)
  940. }
  941. return exportData
  942. },
  943. // 设备分组id 转 设备分组名称
  944. switchDeviceIdToName (val, deviceGroupList) {
  945. const result = []
  946. const valList = val?.split(',') || []
  947. valList.forEach(item => result.push((deviceGroupList?.find(i => i.id_ === item)?.wei_hu_gang_wei_) || ''))
  948. return result.join(',')
  949. },
  950. // 部门id 转 部门名称
  951. switchIdToDept (id) {
  952. const { deptList } = this.$store.getters
  953. const temp = deptList.find(item => item.positionId === id)
  954. return temp ? temp.positionName : ''
  955. },
  956. // 部门名称 转 部门id
  957. switchDeptToId (dep) {
  958. const { deptList } = this.$store.getters
  959. const temp = deptList.find(item => item.positionName === dep)
  960. return temp ? temp.positionId : ''
  961. },
  962. // 人员id 转人员名称
  963. switchIdToUserName (id) {
  964. const { userList } = this.$store.getters
  965. const temp = userList.find(item => item.userId === id)
  966. return temp ? temp.userName : ''
  967. },
  968. // 人员名称 转 人员id
  969. switchUserNameToId (name) {
  970. const { userList } = this.$store.getters
  971. const temp = userList.find(item => item.userName === name)
  972. return temp ? temp.userId : ''
  973. },
  974. // 导出设备
  975. async ExportDevice (selection, data = []) {
  976. const exportData = await this.switchExportData(data)
  977. this.xlsx(exportData, this.deviceColumns, '设备档案卡基本数据' + this.getTimeStamp())
  978. this.$message.success('导出设备成功!')
  979. },
  980. // 导出维护项目
  981. async ExportProject (selection = []) {
  982. let exportData = []
  983. console.log('导出维护项目')
  984. if (selection.length > 0) {
  985. const sql = `select b.yuan_she_bei_bian as yuanSheBeiBian,b.she_bei_ming_cheng_ as sheBeiMingCheng,a.parent_id_,a.wei_hu_xiang_mu_c as weiHuXiangMuC,a.wei_hu_ri_qi_ as weiHuRiQi,a.wei_hu_lei_xing_ as weiHuLeiXing,a.ri_qi_shu_zi_ as riQiShuZi from t_whzqjxm a,t_sbdj b where a.parent_id_=b.id_ and a.parent_id_ in (${selection.map(i => `'${i}'`).join(',')})`
  986. const { variables: { data }} = await this.$common.request('sql', sql)
  987. exportData = data
  988. }
  989. this.xlsx(exportData, this.projectColums, '设备维护项目数据' + this.getTimeStamp())
  990. this.$message.success('导出维护项目成功!')
  991. },
  992. // value 转 key
  993. switchV2K (value, obj) {
  994. const key = Object.keys(obj).find(key => obj[key] === value)
  995. return key || ''
  996. },
  997. // 转换对象的key
  998. switchDeviceObj (data, originalObj) {
  999. const result = []
  1000. // data.forEach(item => {
  1001. // const obj = {}
  1002. // for (const key in item) {
  1003. // obj[this.switchV2K(key, originalObj)] = item[key]
  1004. // }
  1005. // result.push(obj)
  1006. // })
  1007. data.forEach(item => {
  1008. const obj = {}
  1009. for (const key in originalObj) {
  1010. // 对日期格式的数据做兼容处理
  1011. if (item[originalObj[key]] instanceof Date) {
  1012. obj[key] = dayjs(item[originalObj[key]]).add(8, 'hour').format('YYYY-MM-DD') || ''
  1013. } else {
  1014. obj[key] = String(item[originalObj[key]] || '')
  1015. }
  1016. }
  1017. result.push(obj)
  1018. })
  1019. return result
  1020. },
  1021. /* 读取文件 将文件转换为二进制 */
  1022. readFile (file) {
  1023. return new Promise(resolve => {
  1024. const reader = new FileReader()
  1025. reader.readAsBinaryString(file)
  1026. reader.onload = ev => {
  1027. resolve(ev.target.result)
  1028. }
  1029. })
  1030. },
  1031. checkDeviceRequiredFieldsIfEmpty (list, requiredMap) {
  1032. const msgList = []
  1033. list.forEach((item, index) => {
  1034. const invalidFieldNames = []
  1035. Object.entries(requiredMap).forEach(([field, name]) => {
  1036. if (item.weiHuLeiXing === '按需保养' && field === 'weiHuRiQi') {
  1037. console.log('按需pass1')
  1038. } else {
  1039. if (!item[field]) {
  1040. invalidFieldNames.push(name)
  1041. }
  1042. }
  1043. })
  1044. if (invalidFieldNames.length > 0) {
  1045. msgList.push({ row: index + 2, field: invalidFieldNames })
  1046. }
  1047. })
  1048. return msgList
  1049. },
  1050. /**
  1051. * 专门发送提示
  1052. * @param {*} allResult
  1053. * @returns
  1054. */
  1055. sendWarningMessages (allResult, mark = 'range') {
  1056. if (allResult.length < 1) {
  1057. return
  1058. }
  1059. console.log('%c Msg Obj %c', 'background:#FF5733; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;', 'background:transparent', allResult)
  1060. const item = allResult[0]
  1061. switch (mark) {
  1062. case 'required':
  1063. this.$message.warning(`第${item.row}行,字段【${item.field.join(',')}】的值不能为空!`)
  1064. break
  1065. case 'range':
  1066. this.$message.warning(`第${item.row}行,字段【${item.field}】的值【${item.value}】不在限定范围内!`)
  1067. break
  1068. case 'dateFormat':
  1069. this.$message.warning(`第${item.row}行,字段【${item.field}】日期格式错误!格式支持【2024-01-01】、【2024/01/01】,请检查您的数据!`)
  1070. break
  1071. case 'duplicateOriginalDevice':
  1072. this.$message.warning(`${item.field}!`)
  1073. break
  1074. default:
  1075. throw new Error(`${mark}类型未定义!`)
  1076. }
  1077. },
  1078. /**
  1079. * 根据规则校验字段的限定范围
  1080. * @param {*} list
  1081. */
  1082. checkFieldsRange (list, rules) {
  1083. const msgList = []
  1084. for (const ruleKey in rules) {
  1085. const rule = rules[ruleKey]
  1086. const fieldName = ruleKey
  1087. list.forEach((item, index) => {
  1088. const fieldValue = item[rule.field]
  1089. if (fieldValue && !rule.range.includes(fieldValue)) {
  1090. msgList.push({ row: index + 2, field: fieldName, value: fieldValue })
  1091. }
  1092. })
  1093. }
  1094. return msgList
  1095. },
  1096. /**
  1097. * 校验日期字段填写的格式
  1098. * @param {*} list
  1099. * @returns
  1100. */
  1101. checkDateFields (list) {
  1102. const dateRegex = /^(\d{4})[-/](0[1-9]|1[0-2])[-/](0[1-9]|[12]\d|3[01])$/
  1103. for (let i = 0; i < list.length; i++) {
  1104. const row = list[i]
  1105. for (const field in this.dateFieldsMap) {
  1106. if (row[field] && !dateRegex.test(row[field])) {
  1107. console.error('error field:', row[field])
  1108. return [{ row: i + 2, field: this.dateFieldsMap[field] }]
  1109. }
  1110. }
  1111. }
  1112. return []
  1113. },
  1114. checkDuplicateOriginalDeviceNo (arr) {
  1115. const occurrences = {}
  1116. arr.forEach((item, index) => {
  1117. const key = item.yuanSheBeiBian
  1118. if (occurrences[key]) {
  1119. occurrences[key].push(index + 2)
  1120. } else {
  1121. occurrences[key] = [index + 2]
  1122. }
  1123. })
  1124. // 检查是否有重复项(数组长度大于1)
  1125. for (const [key, indices] of Object.entries(occurrences)) {
  1126. if (indices.length > 1) {
  1127. return [{ field: `发现重复的原设备编号:${key} 在第 ${indices.join(', ')} 行` }]
  1128. }
  1129. }
  1130. return []
  1131. },
  1132. /**
  1133. * 负责导入设备数据的第一部分校验,全部成功则返回true
  1134. * @param {*} data
  1135. * @returns
  1136. */
  1137. deviceInvalidPartOne (data) {
  1138. // 校验必填信息
  1139. const invalidResult = this.checkDeviceRequiredFieldsIfEmpty(data, this.requiredFieldMap)
  1140. if (invalidResult.length > 0) {
  1141. this.sendWarningMessages(invalidResult, 'required')
  1142. return false
  1143. }
  1144. // 根据规则校验字段的限定范围
  1145. const allResult = this.checkFieldsRange(data, this.validationRules)
  1146. if (allResult.length > 0) {
  1147. this.sendWarningMessages(allResult, 'range')
  1148. return false
  1149. }
  1150. // 校验日期字段是否符合要求
  1151. const dateResult = this.checkDateFields(data)
  1152. if (dateResult.length > 0) {
  1153. this.sendWarningMessages(dateResult, 'dateFormat')
  1154. return false
  1155. }
  1156. // 校验是否存在重复的原设备编号
  1157. const duplicateOriginalDeviceResult = this.checkDuplicateOriginalDeviceNo(data)
  1158. if (duplicateOriginalDeviceResult.length > 0) {
  1159. this.sendWarningMessages(duplicateOriginalDeviceResult, 'duplicateOriginalDevice')
  1160. return false
  1161. }
  1162. return true
  1163. },
  1164. /**
  1165. * 将日期字段信息格式化为 yyyy-MM-dd
  1166. * @param {*} list
  1167. * @returns
  1168. */
  1169. formatDateFieldsToReal (list) {
  1170. list.forEach(item => {
  1171. this.dateFieldRange.forEach(field => {
  1172. item[field] = item[field]?.replace(/\//g, '-')
  1173. })
  1174. })
  1175. return list
  1176. },
  1177. getNextAlias () {
  1178. return new Promise((resolve, reject) => {
  1179. this.$common.getNextIdByAlias({
  1180. 'alias': 'sbbh'
  1181. }).then(response => {
  1182. resolve(response.data)
  1183. }).catch((error) => {
  1184. reject(error)
  1185. })
  1186. })
  1187. },
  1188. /**
  1189. * 过滤出来excel 的原设备编号存在当前数据库中的数据
  1190. * @param {*} list 导入的数据
  1191. */
  1192. async filterOriginalDeviceNo (list, currentPosition) {
  1193. const uniqueArr = Array.from(new Set(list.map(i => i.yuanSheBeiBian.trim())))
  1194. const sql = `select id_,yuan_she_bei_bian from t_sbdj where find_in_set(yuan_she_bei_bian,'${uniqueArr.join(',')}')and di_dian_ = '${currentPosition}'`
  1195. const res = await this.$common.request('sql', sql)
  1196. const { data = [] } = res.variables || {}
  1197. const originalDeviceNoList = data.map(i => i.yuan_she_bei_bian.trim())
  1198. // 给要更新的数据加上id (接口需要!!!)
  1199. data.forEach(item => {
  1200. const temp = list.find(i => i.yuanSheBeiBian === item.yuan_she_bei_bian)
  1201. temp.id = item.id_
  1202. })
  1203. return originalDeviceNoList || ''
  1204. },
  1205. /**
  1206. *
  1207. * @param {*} list excel数据
  1208. * @param {*} currentTime 当前时间
  1209. * @param {*} currentApartment 当前部门ID
  1210. * @param {*} currentUser 当前用户ID
  1211. * @param {*} currentPosition 当前地点ID
  1212. */
  1213. async handleBasicData (list, currentTime, currentApartment, currentUser, currentPosition, deptList) {
  1214. // 使用map生成一个异步操作的数组
  1215. const promises = list.map(async (element) => {
  1216. element.bianZhiShiJian = currentTime
  1217. element.bianZhiRen = currentUser
  1218. element.diDian = currentPosition
  1219. element.shiFouGuoShen = '已完成'
  1220. const o = deptList?.find(i => i.positionName === element.bianZhiBuMen.trim())
  1221. const { positionId = currentApartment } = o || {}
  1222. element.bianZhiBuMen = positionId
  1223. if (!element.id) {
  1224. // 获取下一个编号
  1225. element.sheBeiShiBieH = await this.getNextAlias()
  1226. }
  1227. })
  1228. // 使用Promise.all并发执行所有异步操作
  1229. await Promise.all(promises)
  1230. },
  1231. /**
  1232. *
  1233. * @param {*} list excel数据
  1234. * @param {*} positionList 现有房间信息
  1235. * @param {*} supplierList 现有供应商信息
  1236. * @param {*} employeeList 现有人员信息
  1237. * @returns
  1238. */
  1239. handleExcelData (list, positionList, supplierList, employeeList, deviceGroupList) {
  1240. if (list.length < 1) {
  1241. return
  1242. }
  1243. this.handleSupplierInfo(list, supplierList)
  1244. this.handlePositionInfo(list, positionList)
  1245. this.handlePersonInfo(list, employeeList)
  1246. this.handleDeviceGroupInfo(list, deviceGroupList)
  1247. },
  1248. /**
  1249. *
  1250. * @param {*} list excel数据
  1251. * @param {*} supplierList 现有供应商信息
  1252. */
  1253. handleSupplierInfo (list, supplierList) {
  1254. list.forEach(element => {
  1255. if (element.gongYingShang.trim()) {
  1256. const supplier = supplierList.find(i => i.gong_ying_shang_m === element.gongYingShang.trim())
  1257. if (supplier) {
  1258. element.shiFouQiJianH = supplier.id_
  1259. } else {
  1260. element.shiFouQiJianH = ''
  1261. element.gongYingShang = ''
  1262. }
  1263. } else {
  1264. element.shiFouQiJianH = ''
  1265. }
  1266. })
  1267. },
  1268. /**
  1269. *
  1270. * @param {*} list excel数据
  1271. * @param {*} positionList 现有房间信息
  1272. */
  1273. handlePositionInfo (list, positionList) {
  1274. list.forEach(element => {
  1275. if (element.cunFangDiDian !== '') {
  1276. const postion = positionList.find(i => (i.fang_jian_ming_ha.trim() || '') === element.cunFangDiDian.trim())
  1277. if (postion) {
  1278. const positionId = postion.id_
  1279. element.cunFangWeiZhi = positionId
  1280. } else {
  1281. element.cunFangWeiZhi = ''
  1282. element.cunFangDiDian = ''
  1283. }
  1284. } else {
  1285. element.cunFangWeiZhi = ''
  1286. }
  1287. })
  1288. },
  1289. handlePersonInfo (list, employeeList) {
  1290. list.forEach(element => {
  1291. // 处理保管人
  1292. if (element.guanLiRen !== '') {
  1293. const person = employeeList.find(i => i.userName === element.guanLiRen.trim())
  1294. if (person) {
  1295. const personId = person.userId
  1296. element.guanLiRen = personId
  1297. } else {
  1298. element.guanLiRen = ''
  1299. }
  1300. } else {
  1301. element.guanLiRen = ''
  1302. }
  1303. // 处理核查人
  1304. if (element.biXuDeHuanJin !== '') {
  1305. const checkPerson = employeeList.find(i => i.userName === element.biXuDeHuanJin.trim())
  1306. if (checkPerson) {
  1307. const checkPersonId = checkPerson.userId
  1308. element.biXuDeHuanJin = checkPersonId
  1309. } else {
  1310. element.biXuDeHuanJin = ''
  1311. }
  1312. } else {
  1313. element.biXuDeHuanJin = ''
  1314. }
  1315. })
  1316. },
  1317. handleDeviceGroupInfo (list, deviceGroupList) {
  1318. list.forEach(element => {
  1319. const result = []
  1320. const { weiHuFangShi } = element
  1321. const valList = weiHuFangShi.trim()?.split(',')
  1322. valList.forEach(item => result.push((deviceGroupList?.find(i => i.wei_hu_gang_wei_ === item)?.id_) || ''))
  1323. element.weiHuFangShi = result.join(',')
  1324. })
  1325. },
  1326. async handleUploadChange1 (file) {
  1327. const dataBinary = await this.readFile(file.target.files[0])
  1328. file.target.value = null // 注意上传后要将input的值设为空
  1329. const workBook = xlsx.read(dataBinary, { type: 'binary', cellDates: true })
  1330. const workSheet = workBook.Sheets[workBook.SheetNames[0]]
  1331. const data = xlsx.utils.sheet_to_json(workSheet)
  1332. let importData = this.switchDeviceObj(data, this.deviceColumns)
  1333. importData.forEach(i => {
  1334. delete i.sheBeiShiBieH // 设备编号需自动生成
  1335. })
  1336. const currentPosition = this.level
  1337. const { userList = [], deptList = [] } = this.$store.getters || {}
  1338. const positionSql = `select id_,fang_jian_ming_ha from t_jjqfjb where di_dian_ = ${currentPosition}` // 房间信息
  1339. const supplierSql = `select id_,gong_ying_shang_m from t_gysxxb where di_dian_ = ${currentPosition}` // 供应商信息
  1340. const deviceGroupSql = `select id_,suo_shu_bu_men_,wei_hu_gang_wei_ from t_sbwhgwpzb where di_dian_ = ${currentPosition}` // 设备分组信息
  1341. const currentTime = dayjs().format('YYYY-MM-DD HH:mm')
  1342. const currentApartment = this.$store.getters.userInfo.employee.positions
  1343. const currentUser = this.userId
  1344. const partOneInvalidResult = this.deviceInvalidPartOne(importData)
  1345. if (!partOneInvalidResult) return
  1346. importData = this.formatDateFieldsToReal(importData)
  1347. console.log('%c partOne doCheck is completed! %c the result is %c', 'background:#35495E; padding: 1px; border-radius: 3px 0 0 3px; color: #fff;', 'background:#FF5733; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;', 'background:transparent', importData)
  1348. this.loading = true
  1349. Promise.all([this.$common.request('sql', positionSql), this.$common.request('sql', supplierSql), this.$common.request('sql', deviceGroupSql)]).then(async ([res1, res2, res3]) => {
  1350. const { data: positionList = [] } = res1.variables || {}
  1351. const { data: supplierList = [] } = res2.variables || {}
  1352. const { data: deviceGroupList = [] } = res3.variables || {}
  1353. // 根据原设备编号去重,检验原设备编号是否在数据库中存在
  1354. const originalDeviceNoList = await this.filterOriginalDeviceNo(importData, currentPosition)
  1355. await this.handleBasicData(importData, currentTime, currentApartment, currentUser, currentPosition, deptList)
  1356. this.handleExcelData(importData, positionList, supplierList, userList, deviceGroupList)
  1357. // 分离出 已存在的设备,和新设备
  1358. const newDeviceList = importData.filter(i => !originalDeviceNoList.includes(i.yuanSheBeiBian.trim()))
  1359. const existDeviceList = importData.filter(i => originalDeviceNoList.includes(i.yuanSheBeiBian.trim()))
  1360. console.log('%c new device %c', 'background:#FF5733; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;', 'background:transparent', newDeviceList)
  1361. console.log('%c already exist device %c', 'background:#43f80c; padding: 1px; border-radius: 0 3px 3px 0; color: #fff;', 'background:transparent', existDeviceList)
  1362. this.loading = false
  1363. this.$confirm(`<span style="color:#f56c6c; font-size: 18px; font-weight: 600;">
  1364. 经系统判定</span><br>1.预期新导入设备的数量为 ${newDeviceList.length} 台!<br>
  1365. 2.预期更新已存在的设备数量为 ${existDeviceList.length} 台!<br>
  1366. <span style="color:#f56c6c;">Tips:请确认数据无误再点击确定进行导入</span><br><span style="color:#f56c6c; font-size: 18px; font-weight: 600;">请谨慎操作!</span>`, '提示', {
  1367. confirmButtonText: '确定',
  1368. cancelButtonText: '取消',
  1369. dangerouslyUseHTMLString: true,
  1370. type: 'warning'
  1371. }).then(async () => {
  1372. await this.doImportDevice(importData)
  1373. this.loading = true
  1374. setTimeout(() => {
  1375. this.loading = false
  1376. this.$message.success('设备数据导入成功!')
  1377. this.getDatas()
  1378. }, 1000)
  1379. }).catch(() => { })
  1380. }).catch(() => {
  1381. this.loading = false
  1382. })
  1383. },
  1384. async doImportDevice (existDeviceList, currentPosition) {
  1385. this.loading = true
  1386. const allRequests = []
  1387. for (let index = 0; index < existDeviceList.length; index++) {
  1388. const item = existDeviceList[index]
  1389. let params = {}
  1390. if (item.id) {
  1391. // 获取设备数据
  1392. const { data: itemData } = await getequipmentCard({ id: item.id })
  1393. params = { ...itemData, ...item } // 合并数据
  1394. } else {
  1395. params = item // 直接使用当前 item
  1396. }
  1397. console.log(params)
  1398. // 将每个 saveEquipmentCard 请求加入到 allRequests 数组中
  1399. allRequests.push(saveEquipmentCard(params))
  1400. }
  1401. // 等待所有异步请求完成
  1402. await Promise.all(allRequests)
  1403. this.loading = false
  1404. },
  1405. generateDayRule () {
  1406. const days = ['每周1', '每周2', '每周3', '每周4', '每周5', '每周6', '每周7']
  1407. let combinations = []
  1408. for (let length = 1; length <= days.length; length++) {
  1409. this.generateCombinations([], days, combinations)
  1410. }
  1411. combinations = combinations.map(comb => '每周' + comb.map(item => item.slice(2)).join(','))
  1412. combinations.push('每天')
  1413. return combinations
  1414. },
  1415. generateRule (num, prefix, suffix) {
  1416. return Array.from({ length: num }, (_, i) => prefix + `${i + 1}` + suffix)
  1417. },
  1418. generateCombinations (current, remaining, results) {
  1419. if (remaining.length === 0) {
  1420. results.push(current)
  1421. return
  1422. }
  1423. const first = remaining[0]
  1424. const rest = remaining.slice(1)
  1425. // 包括当前数字和不包括当前数字两种情况
  1426. this.generateCombinations(current.concat([first]), rest, results)
  1427. this.generateCombinations(current, rest, results)
  1428. },
  1429. /**
  1430. * 负责导入设备维护项目数据的第一部分校验,全部成功则返回true
  1431. * @param {*} data
  1432. * @returns
  1433. */
  1434. maintenanceInvalidPartOne (data) {
  1435. // 1、对数据进行清洗校验(设备编号不能为空,维护周期、维护项目亦不可为空)
  1436. const invalidResult = this.checkDeviceRequiredFieldsIfEmpty(data, this.maintenanceRequiredFieldMap)
  1437. if (invalidResult.length > 0) {
  1438. this.sendWarningMessages(invalidResult, 'required')
  1439. return false
  1440. }
  1441. // 根据规则校验字段的限定范围
  1442. const allResult = this.checkFieldsRange(data, this.maintenanceValidationRules)
  1443. if (allResult.length > 0) {
  1444. this.sendWarningMessages(allResult, 'range')
  1445. return false
  1446. }
  1447. // 根据规则校验维护周期对应的维护日期的限定范围
  1448. const result = this.checkMaintenanceDateRange(data, this.maintenanceDateValidationRules)
  1449. if (result.length > 0) {
  1450. this.sendWarningMessages(result, 'range')
  1451. return false
  1452. }
  1453. return true
  1454. },
  1455. /**
  1456. * 根据规则校验维护周期对应的维护日期的限定范围
  1457. */
  1458. checkMaintenanceDateRange (list, rules) {
  1459. const msgList = []
  1460. list.forEach(({ weiHuLeiXing: type, weiHuRiQi: exactDate }, index) => {
  1461. if (type === '按需保养') {
  1462. console.log('按需pass2')
  1463. } else {
  1464. if (!rules[type].includes(exactDate)) {
  1465. msgList.push({ row: index + 2, field: '维护日期', value: exactDate })
  1466. }
  1467. }
  1468. })
  1469. return msgList
  1470. },
  1471. async handleUploadChange2 (file) {
  1472. const dataBinary = await this.readFile(file.target.files[0])
  1473. file.target.value = null // 注意上传后要将input的值设为空
  1474. const workBook = xlsx.read(dataBinary, { type: 'binary', cellDates: true })
  1475. const workSheet = workBook.Sheets[workBook.SheetNames[0]]
  1476. const data = xlsx.utils.sheet_to_json(workSheet)
  1477. const importData = this.switchDeviceObj(data, this.projectColums)
  1478. console.log(importData)
  1479. importData.forEach(item => {
  1480. if (item.weiHuLeiXing === '按需保养') {
  1481. item.weiHuRiQi = '/'
  1482. }
  1483. })
  1484. const currentPosition = this.level
  1485. const { userList = [], deptList = [] } = this.$store.getters || {}
  1486. const positionSql = `select id_,fang_jian_ming_ha from t_jjqfjb where di_dian_ = ${currentPosition}` // 房间信息
  1487. const supplierSql = `select id_,gong_ying_shang_m from t_gysxxb where di_dian_ = ${currentPosition}` // 供应商信息
  1488. const deviceGroupSql = `select id_,suo_shu_bu_men_,wei_hu_gang_wei_ from t_sbwhgwpzb where di_dian_ = ${currentPosition}` // 设备分组信息
  1489. const currentTime = dayjs().format('YYYY-MM-DD HH:mm')
  1490. const currentApartment = this.$store.getters.userInfo.employee.positions
  1491. const currentUser = this.userId
  1492. const partOneInvalidResult = this.maintenanceInvalidPartOne(importData)
  1493. if (!partOneInvalidResult) return
  1494. // 2、根据原设备编号去重,检验原设备编号是否在数据库中存在,如有不存在的数据,不进行导入,并提示用户
  1495. const uniqueArr = Array.from(new Set(importData.map(i => i.yuanSheBeiBian.trim())))
  1496. /* 3、根据去重的设备编号去查对应的设备ID,然后拼接data数据,赋值设备ID*/
  1497. const sql = `select id_,yuan_she_bei_bian from t_sbdj where find_in_set(yuan_she_bei_bian,'${uniqueArr.join(',')}')and di_dian_ = ${currentPosition}`
  1498. this.$common.request('sql', sql).then(async res => {
  1499. const deviceNoWithIdlist = res.variables.data
  1500. console.log(deviceNoWithIdlist, ' <=> ', uniqueArr)
  1501. const deviceNoSet = new Set(deviceNoWithIdlist.map(i => i.yuan_she_bei_bian))
  1502. const missStr = uniqueArr.filter(i => !deviceNoSet.has(i)).join(',') || ''
  1503. if (missStr !== '') {
  1504. this.$message.error(`设备维护项目数据中包含不存在于设备档案的原设备编号!具体原设备编号为:${missStr}`)
  1505. return
  1506. }
  1507. importData.forEach(item => {
  1508. item.id = deviceNoWithIdlist.find(i => i.yuan_she_bei_bian === item.yuanSheBeiBian).id_
  1509. })
  1510. const resultList = []
  1511. importData.forEach(item => {
  1512. const flag = item.weiHuLeiXing === '日保养'
  1513. const match = item.weiHuRiQi?.match(/\d+/g)
  1514. const o = {
  1515. id: item.id,
  1516. weiHuLeiXing: item.weiHuLeiXing.trim(),
  1517. weiHuRiQi: item.weiHuRiQi?.trim() || '',
  1518. weiHuXiangMuC: item.weiHuXiangMuC.trim(),
  1519. riQiShuZi: match ? (flag ? match.join(',') : match[0]) : ''
  1520. }
  1521. if (o.weiHuLeiXing === '日保养' && o.weiHuRiQi === '每天') o.riQiShuZi = '1,2,3,4,5,6,7'
  1522. resultList.push(o)
  1523. })
  1524. // 4、根据用户选择 进行全量替换|增量添加
  1525. await this.doProjectImport(deviceNoWithIdlist, resultList, this.ImportDeviceType)
  1526. this.$message.success('维护项目数据' + this.ImportDeviceType + '成功!')
  1527. })
  1528. },
  1529. async doProjectImport (deviceNoWithIdlist, resultList, type) {
  1530. this.loading = true
  1531. const allRequests = []
  1532. deviceNoWithIdlist.forEach(async item => {
  1533. const { data: itemData } = await getequipmentCard({ id: item.id_ })
  1534. const temp = resultList.filter(i => i.id === item.id_).map(ii => {
  1535. delete ii.id
  1536. return ii
  1537. })
  1538. let params = {}
  1539. if (type === '增量添加') { // 增量
  1540. params = {
  1541. ...itemData,
  1542. maintenanceItemPoList: [...itemData.maintenanceItemPoList, ...temp]
  1543. }
  1544. } else if (type === '全量替换') { // 全量
  1545. params = {
  1546. ...itemData,
  1547. maintenanceItemPoList: temp
  1548. }
  1549. }
  1550. console.log('params', params)
  1551. allRequests.push(saveEquipmentCard(params))
  1552. })
  1553. await Promise.all(allRequests)
  1554. this.loading = false
  1555. }
  1556. }
  1557. }
  1558. </script>
  1559. <style lang="scss" scoped>
  1560. .icon-image{
  1561. width: 36px;
  1562. }
  1563. .device-image{
  1564. width: 152px;
  1565. height: 110px;
  1566. }
  1567. .title{
  1568. font-size: 12px;
  1569. font-weight: 900;
  1570. color: #333;
  1571. margin: 0 0 14px 20px;
  1572. }
  1573. .ctx{
  1574. margin: 0 0 0 20px;
  1575. .item{
  1576. .cusitem{
  1577. margin: -8px 0;
  1578. display: flex;
  1579. align-items: center;
  1580. }
  1581. .span{
  1582. min-width:60px
  1583. }
  1584. margin: 6px 0;
  1585. color: #999;
  1586. }
  1587. }
  1588. ::v-deep {
  1589. .el-form-item__label{
  1590. text-align: left;
  1591. font-size: 12px !important;
  1592. }
  1593. .el-form-item__ctx{
  1594. font-size: 12px !important;
  1595. }
  1596. }
  1597. </style>