detail.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. <template>
  2. <div v-if="active" class="register-detail">
  3. <nav-bar></nav-bar>
  4. <div class="page-container">
  5. <!-- 基本信息 -->
  6. <div class="card" v-if="taskInfo">
  7. <van-cell-group>
  8. <van-cell :title="taskInfo.taskName">
  9. <template #right-icon>
  10. <span :style="{ color: getState(getDictLabel(taskInfo.status, 'safety_check_status')) }">
  11. {{ getDictLabel(taskInfo.status, 'safety_check_status') }}
  12. </span>
  13. </template>
  14. </van-cell>
  15. <van-cell class="cell-item28" title="任务时间" :value="formatTime(taskInfo.planStartTime,taskInfo.planEndTime)" />
  16. <van-cell class="cell-item28" title="受检机构" :value="taskInfo.beCheckedOrgName" />
  17. <van-cell class="cell-item28" title="检查开始时间" :value="formatRegisterTime(taskInfo.startTime)" />
  18. <van-cell class="cell-item28" title="检查结束时间" :value="formatRegisterTime(taskInfo.endTime)" />
  19. <van-cell class="cell-item28" title="检查组成员" :value="taskInfo.checkTeam || '无'" />
  20. </van-cell-group>
  21. </div>
  22. <!-- 检查项目 -->
  23. <div class="card">
  24. <!-- 搜索框 -->
  25. <van-search v-model="itemName" class="van-hairline--top" placeholder="请输入检查内容" />
  26. <van-collapse v-model="activeNames" v-for="(v,i) in resultList" :key="v.itemId">
  27. <van-collapse-item :title="`${i+1}.${v.itemName}`" :name="v.itemName">
  28. <div v-for="(item, index) in v.pointList" :key="item.pointId" class="collapse-box" :class="{'van-hairline--bottom':item.status}">
  29. <van-cell :border="true">
  30. <template #title>
  31. <pre> <span>{{`${i+1}-${index+1}`}}.</span> {{ item.pointName }}</pre>
  32. </template>
  33. <template #right-icon>
  34. <span v-if="item.nfcList && item.nfcList.length" @click="clickNFCNum(item.nfcList)">
  35. <span style="color:#009240;">{{ getNfcState(item.nfcList) }}</span>/<span >{{item.nfcList.length}}</span>
  36. </span>
  37. <img
  38. v-if="item.nfcList && item.nfcList.length"
  39. :src="require('../../../assets/svg/NFC.svg')"
  40. class="nfc-icon"/>
  41. <span> </span>
  42. <span v-if="item.status != null">
  43. <van-tag v-if="item.status == '1'" type="warning">隐患</van-tag>
  44. <van-tag v-else type="success">正常</van-tag>
  45. </span>
  46. </template>
  47. </van-cell>
  48. <van-cell-group v-show="item.status =='1'" :border="false">
  49. <van-cell v-if="item.nfcList && item.nfcList.length > 0" :border="false">
  50. <div
  51. v-if="img.img"
  52. class="nfc-img"
  53. v-for="(img, i) in item.nfcList"
  54. :key="img.img"
  55. @click="preViewNFC(i)"
  56. >
  57. <img :src="imgUrl(img.img)" alt="" />
  58. <span>{{ img.checkName }}</span>
  59. </div>
  60. </van-cell>
  61. <van-cell title="情况描述">
  62. <template #label>
  63. <p class="text-style">{{item.remark}}</p>
  64. </template>
  65. </van-cell>
  66. <van-cell title="整改期限" :border="false" :value="`${item.rectificationDeadline}天`"></van-cell>
  67. <!-- <select-cell-->
  68. <!-- required-->
  69. <!-- :disabled="!enable"-->
  70. <!-- is-row-->
  71. <!-- title="整改期限"-->
  72. <!-- v-model="item.rectificationDeadline"-->
  73. <!-- :data-list="dateList"-->
  74. <!-- />-->
  75. <div v-if="item.imgData && item.imgData.length > 0" class="upload-box">
  76. <van-cell>
  77. <div
  78. class="nfc-img"
  79. v-for="(v, i) in item.imgData"
  80. :key="v.imgPath"
  81. @click="clickWarnImage(item.imgData, i)"
  82. >
  83. <img :src="imgUrl(v.imgPath)" alt="" />
  84. </div>
  85. </van-cell>
  86. </div>
  87. </van-cell-group>
  88. </div>
  89. </van-collapse-item>
  90. </van-collapse>
  91. </div>
  92. </div>
  93. <van-action-sheet v-model="total_show" @closed="closedNfcList">
  94. <div class="content">
  95. <van-tabs>
  96. <van-tab title="未扫描" name="b">
  97. <div v-if="unmetList.length > 0" class="nfc-list">
  98. <van-cell v-for="item in unmetList" :title="item.nfcName" :key="item.nfcCode">
  99. <!-- <img :src="require('../../../assets/svg/NFC.svg')" class="nfc-icon"/>-->
  100. <!-- <span >{{item.pointScan == 1?'必扫':'可选'}}</span>-->
  101. </van-cell>
  102. </div>
  103. <van-empty v-else description="" />
  104. </van-tab>
  105. <van-tab title="已扫描" name="a">
  106. <div v-if="fullList.length > 0" class="nfc-list">
  107. <van-cell v-for="item in fullList" :title="item.nfcName" :key="item.nfcCode">
  108. <span style="color: green"> {{item.scanMethod == 0?'NFC扫描':'拍照上传'}}</span>
  109. </van-cell>
  110. </div>
  111. <van-empty v-else description="" />
  112. </van-tab>
  113. </van-tabs>
  114. </div>
  115. </van-action-sheet>
  116. </div>
  117. </template>
  118. <script>
  119. import NavBar from '@/components/NavBar'
  120. import { imgUrl } from '@/utils'
  121. import { ImagePreview } from 'vant'
  122. import { mapGetters } from 'vuex'
  123. import {registerDetail} from './api'
  124. export default {
  125. name: 'securityDetail',
  126. components: { NavBar },
  127. data() {
  128. return {
  129. id: null,
  130. activeNames: ['1'],
  131. //基本信息
  132. taskInfo: [],
  133. //选中的nfc列表
  134. NFCList: [],
  135. //区域下检查内容列表
  136. checkList: [],
  137. //检查内容具体项列表
  138. checkItemList: [],
  139. //nfc扫描数量
  140. NFCNum: 0,
  141. //所有检查项数量
  142. allCheckNum: 0,
  143. //区域下检查项数量
  144. checkNum: 0,
  145. //nfc图片
  146. nfcImage: [],
  147. enable: false,
  148. stateList: [],
  149. dayList: [],
  150. itemName:null,
  151. preViewImages: {
  152. images: [],
  153. startPosition: 0
  154. },
  155. dicts: ['safety_check_status', 'rectification_deadline'],
  156. showPreView: false,
  157. selected: null,
  158. active: true,
  159. dateList:[],
  160. go: {
  161. type: 'replace',
  162. path: '/securityCheckRegister'
  163. },
  164. /* 以下为NFC弹窗详情数据*/
  165. total_show:false,
  166. fullList:[],
  167. unmetList:[],
  168. }
  169. },
  170. computed: {
  171. ...mapGetters(['dictionary',"roleList",'orgId']),
  172. resultList(){
  173. if (!this.itemName) {
  174. return this.checkList;
  175. }
  176. // 使用传入的值来过滤数据
  177. const filteredData = this.checkList.map(item => ({
  178. ...item,
  179. pointList:
  180. item.pointList.filter(point =>
  181. (point.itemName.includes(this.itemName) || point.pointName.includes(this.itemName))
  182. )
  183. })).filter(item => item.pointList.length > 0);
  184. return filteredData;
  185. },
  186. },
  187. mounted() {
  188. this.id = this.$route.query.id
  189. this.getData()
  190. },
  191. beforeDestroy() {
  192. window.openCameraCallBack = null
  193. window.openNFCScanCallBack = null
  194. },
  195. methods: {
  196. //长度校验
  197. validator(val) {
  198. let len = val.length;
  199. if( len > 5) {
  200. this.$toast.fail('问题情况输入长度不能超过200');
  201. return true
  202. }else {
  203. return false
  204. }
  205. },
  206. //获取NFC已扫描数据
  207. getNfcState(arr){
  208. arr = arr || [];
  209. let nums = arr.filter(v=>{return v.status === 1});
  210. return nums.length;
  211. },
  212. //调用nfc
  213. checkNFC(){
  214. //设置nfc调用后的回调
  215. window.openNFCScanCallBack = this.openNFCScanCallBack;
  216. //设置loading弹窗
  217. this.$toast.loading({
  218. duration: 0, // 持续展示 toast
  219. position: 'top',
  220. forbidClick: true,
  221. message: '请靠近NFC标签,进行扫描!',
  222. });
  223. let second = 30;
  224. this.timer = setInterval(() => {
  225. second--;
  226. if(!second){
  227. this.$toast.clear();
  228. clearInterval(this.timer);
  229. this.$toast.fail({
  230. message: '未扫描到任何信息!',
  231. });
  232. }
  233. }, 1000);
  234. //挂载nfc
  235. this.useNFC();
  236. },
  237. //调用nfc后的回调
  238. openNFCScanCallBack(nfcStr){
  239. //alert(JSON.stringify(nfcStr))
  240. clearInterval(this.timer);
  241. let nfcCode = '';
  242. try{
  243. let nfc = JSON.parse(nfcStr);
  244. nfcCode = nfc.content;
  245. }catch (e) {
  246. nfcCode = nfcStr.content;
  247. }
  248. // let nfc = JSON.parse(nfcStr);
  249. // let nfcCode = nfc.content;
  250. //alert(nfcCode)
  251. this.checkNfcFilter(nfcCode);
  252. },
  253. //验证nfc数据
  254. checkNfcFilter(nfcCode){
  255. //let areaId = null;
  256. let checkOk = false;
  257. //alert(JSON.stringify(this.NFCList,'NFCList'));
  258. this.NFCList.forEach(v => {
  259. if(v.nfcCode === nfcCode){
  260. if(v.status === 1){
  261. this.$toast.fail('NFC点位:' + v.nfcName + '已扫描,请勿重复扫描!');
  262. throw new Error('NFC点位:' + v.nfcName + '已扫描,请勿重复扫描!');
  263. }
  264. v.status = 1;
  265. v.scanMethod = 0;
  266. this.$toast('NFC点位:' + v.nfcName + '扫描成功!');
  267. checkOk = true;
  268. }
  269. });
  270. if(!checkOk){
  271. this.$toast.fail( "扫描结果不在本次检查范围内!");
  272. }
  273. },
  274. //是否显示nfc图标
  275. nfcState(item){
  276. if(item.nfcList && item.nfcList.length > 0){
  277. return item.nfcList.some(v=>{
  278. return v.status === 0
  279. })
  280. }
  281. return false
  282. },
  283. //格式化时间范围
  284. formatTime(start,end,format){
  285. format = format || 'YYYY年MM月DD日'
  286. return `${this.dayjs(start).format(format)} ~ ${this.dayjs(end).format(format)}`;
  287. },
  288. //格式化时间范围
  289. formatRegisterTime(time,format){
  290. if (!time){
  291. return '';
  292. }
  293. format = format || 'YYYY年MM月DD日 HH时mm分'
  294. return `${this.dayjs(time).format(format)}`;
  295. },
  296. //插入检查项
  297. addItem(val) {
  298. console.log(val, 'list')
  299. if (!val) return
  300. let str = JSON.parse(JSON.stringify(val))
  301. str.forEach(valItem => {
  302. console.log(this.checkList, 'checkList')
  303. // 查找是否有与 valItem.itemId 相同的项
  304. const existingItem = this.checkList.find(checkItem => checkItem.itemId === valItem.itemId)
  305. if (existingItem) {
  306. // // 如果存在相同 itemId 的项,查找 pointList 是否有与 valItem.pointId 相同的项
  307. const existingPoint = existingItem.pointList.find(pointItem => pointItem.pointId === valItem.id)
  308. if (!existingPoint) {
  309. console.log(existingItem, 'point添加成功')
  310. this.$nextTick(() => {
  311. valItem.isAdd = 1;
  312. existingItem.pointList.push(valItem)
  313. this.active = true
  314. })
  315. } else {
  316. this.$toast(existingPoint.pointName + '已添加')
  317. }
  318. } else {
  319. console.log(valItem, 'item添加成功')
  320. this.checkList.push({
  321. isAdd:1,
  322. itemId: valItem.itemId,
  323. itemName: valItem.itemName,
  324. pointList: [valItem]
  325. })
  326. this.active = true
  327. }
  328. })
  329. },
  330. goBack() {
  331. this.active = true
  332. },
  333. getState(state) {
  334. switch (state){
  335. case '待检查':
  336. return '#008cd6';
  337. case '进行中':
  338. return '#bc9f71';
  339. case '已完成':
  340. return '#009240';
  341. case '已逾期':
  342. return '#D7000F';
  343. }
  344. },
  345. addCheck() {
  346. this.active = false
  347. },
  348. clickWarnImage(arr, i) {
  349. this.preViewImages.images = arr.map(v => imgUrl(v.imgPath))
  350. this.preViewImages.startPosition = i
  351. ImagePreview(this.preViewImages)
  352. },
  353. preViewNFC(i) {
  354. this.preViewImages.images = this.nfcImage.map(v => imgUrl(v.img))
  355. this.preViewImages.startPosition = i
  356. ImagePreview(this.preViewImages)
  357. },
  358. getDicts(s) {
  359. return this.stateList.find(v => s == v.dictValue).dictLabel
  360. },
  361. //初始化数据
  362. getData() {
  363. let taskId = this.$route.query.id;
  364. registerDetail(taskId).then(res => {
  365. console.log(res, 'res')
  366. this.taskInfo = res.data;
  367. this.enable = this.taskInfo.status === 1 || this.taskInfo.status === 2; //是否可编辑
  368. this.checkList = res.data.checkList;
  369. this.dateList = this.getDictItem('rectification_deadline');
  370. //设置默认展开项
  371. this.activeNames = this.checkList.map(v => v.itemName);
  372. })
  373. },
  374. //点击NFC数字图标
  375. clickNFCNum(arr) {
  376. arr.forEach(v=>{
  377. if(v.status){
  378. this.fullList.push(v);
  379. }else {
  380. this.unmetList.push(v)
  381. }
  382. })
  383. this.total_show =true;
  384. },
  385. closedNfcList(){
  386. this.fullList = [];
  387. this.unmetList = [];
  388. },
  389. //清空数据
  390. clearData() {
  391. this.areaList = []
  392. this.taskInfo = []
  393. this.selectArea = []
  394. this.NFCList = []
  395. this.checkList = []
  396. this.checkItemList = []
  397. this.NFCNum = 0
  398. this.enable = false
  399. },
  400. //切换开关时添加操作时间
  401. switchChange(item) {
  402. console.log(item, '666')
  403. //item.resTime = formatDate(new Date());
  404. },
  405. //添加图片时的回调
  406. changeNfcImg(imgItem) {
  407. console.log(imgItem, this.NFCList, 'imgItem')
  408. this.NFCList.forEach(v => {
  409. if (v.nfcCode === imgItem.nfcCode) {
  410. v.img = imgItem.url
  411. v.status = 1
  412. v.scanMethod = 1
  413. this.nfcImage.push(v)
  414. }
  415. })
  416. console.log(this.NFCList, this.nfcImage, 'nfcObj')
  417. },
  418. }
  419. }
  420. </script>
  421. <style lang="scss">
  422. .register-detail{
  423. .van-collapse-item__content{
  424. padding: 0 30px 0px 30px;
  425. }
  426. .van-tabs__content{
  427. border-top:2px solid #eaeaea;
  428. }
  429. }
  430. </style>
  431. <style lang="scss" scoped>
  432. .register-detail {
  433. height: 100%;
  434. overflow: hidden;
  435. .page-container {
  436. height: calc(100vh - 92px);
  437. overflow: auto;
  438. padding: 20px;
  439. }
  440. .flex-box {
  441. padding: 20px;
  442. display: flex;
  443. justify-content: space-between;
  444. align-items: center;
  445. > span {
  446. margin: 0 20px;
  447. }
  448. >button{
  449. flex:.45;
  450. margin:0 10px;
  451. /* min-width: 30%;
  452. max-width: 50%; */
  453. }
  454. }
  455. .legend {
  456. background-color: #fff;
  457. padding: 0 20px;
  458. height: 80px;
  459. line-height: 80px;
  460. font-size: 30px;
  461. display: flex;
  462. justify-content: space-between;
  463. > span {
  464. color: orange;
  465. }
  466. }
  467. .card {
  468. margin-bottom: 20px;
  469. box-shadow: 0 10px 10px #eaeaea;
  470. &:last-child {
  471. margin-bottom: 0;
  472. }
  473. }
  474. .collapse-box{
  475. -padding-bottom: 10px;
  476. }
  477. .check-area {
  478. background-color: #f1f1f1;
  479. margin: 10px;
  480. padding: 20px;
  481. color: #aaa;
  482. border-radius: 6px;
  483. display: flex;
  484. justify-content: space-between;
  485. align-items: center;
  486. box-shadow: 0 2px 6px #ddd;
  487. }
  488. .nfc-icon {
  489. width: 50px;
  490. height: 50px;
  491. margin: 0 20px;
  492. }
  493. .custom-title {
  494. align-self: center;
  495. vertical-align: middle;
  496. }
  497. .upload-box {
  498. padding: 30px;
  499. }
  500. .warning-msg {
  501. color: orange;
  502. text-align: center;
  503. height: 80px;
  504. line-height: 80px;
  505. }
  506. .active {
  507. color: #fff;
  508. background-color: #1989fa;
  509. }
  510. .nfc-img {
  511. display: inline-block;
  512. width: 140px;
  513. height: 140px;
  514. margin: 0 10px;
  515. position: relative;
  516. > img {
  517. width: 100%;
  518. height: 100%;
  519. border: none;
  520. }
  521. > span {
  522. position: absolute;
  523. padding: 0 10px;
  524. bottom: 0;
  525. left: 0;
  526. display: block;
  527. width: 100%;
  528. background-color: rgba(0, 0, 0, 0.2);
  529. color: #eaeaea;
  530. font-size: 20px;
  531. overflow: hidden;
  532. text-overflow: ellipsis;
  533. white-space: nowrap;
  534. line-height: 30px;
  535. height: 30px;
  536. }
  537. }
  538. .nfc-list{
  539. min-height: 300px;
  540. max-height: 600px;
  541. overflow: auto;
  542. padding: 10px 0;
  543. }
  544. }
  545. </style>