Detail.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <template>
  2. <el-dialog title="整改详情" :visible.sync="dialogVisible" width="760px" @open="load" :close-on-click-modal="false">
  3. <div class="detail-wrap" v-loading="loading">
  4. <div class="head" v-if="rounds.length">
  5. <div class="head-main">{{ rounds[0].storeName }} · {{ rounds[0].indicatorName }}</div>
  6. <div class="head-meta">
  7. <span>当前轮次:第 {{ rounds[rounds.length - 1].rectRound || 1 }} 轮</span>
  8. <span v-if="rounds[0].taskId">任务ID:{{ rounds[0].taskId }}</span>
  9. </div>
  10. </div>
  11. <el-timeline v-if="rounds.length">
  12. <el-timeline-item v-for="r in rounds" :key="r.rectId" :timestamp="'第 ' + (r.rectRound || 1) + ' 轮整改'" placement="top" :color="rectColor(r.status)">
  13. <div class="round-card">
  14. <div class="round-head">
  15. <span class="round-title">指标:{{ r.indicatorName }}</span>
  16. <el-tag size="mini" :style="rectStyle(r.status)">{{ rectText(r.status) }}</el-tag>
  17. <el-button v-if="r.status === 3" type="primary" size="mini" @click="$emit('recheck', r)">复检</el-button>
  18. </div>
  19. <!-- 下发通知 -->
  20. <div class="node">
  21. <div class="node-title"><i class="el-icon-message"></i> 下发整改通知<span class="node-time">{{ fmt(r.createDate, true) }}</span></div>
  22. <div class="node-content">
  23. <div v-if="r.noticeContent">{{ r.noticeContent }}</div>
  24. <div class="kv"><span>巡检得分:{{ fmtNum(r.inspectScore) }} / 及格分:{{ fmtNum(r.passScore) }}</span></div>
  25. <div class="kv"><span>截止日期:{{ fmt(r.deadlineDate, true) }}</span></div>
  26. <div class="kv" v-if="r.urgeCount"><span>已催办 {{ r.urgeCount }} 次(最近 {{ fmt(r.lastUrgeDate, true) }})</span></div>
  27. </div>
  28. </div>
  29. <!-- 门店反馈 -->
  30. <div class="node" :class="{ empty: !r.feedbackDate }">
  31. <div class="node-title"><i class="el-icon-shop"></i> 门店提交整改反馈<span class="node-time">{{ fmt(r.feedbackDate, true) }}</span></div>
  32. <div class="node-content" v-if="r.feedbackDate">
  33. <div v-if="r.feedbackContent">{{ r.feedbackContent }}</div>
  34. <div class="pic-row" v-if="pictures(r.feedbackPictures).length">
  35. <el-image
  36. v-for="(p, i) in pictures(r.feedbackPictures)"
  37. :key="i"
  38. :src="p"
  39. fit="cover"
  40. :preview-src-list="pictures(r.feedbackPictures)"
  41. class="thumb" />
  42. </div>
  43. </div>
  44. <div class="muted" v-else>门店尚未提交反馈</div>
  45. </div>
  46. <!-- 复检结果 -->
  47. <div class="node" :class="{ empty: !r.recheckDate }">
  48. <div class="node-title"><i class="el-icon-search"></i> 巡检员复检<span class="node-time">{{ fmt(r.recheckDate, true) }}</span></div>
  49. <div class="node-content" v-if="r.recheckDate">
  50. <div class="kv">
  51. <span>复检得分:{{ fmtNum(r.recheckScore) }}</span>
  52. <el-tag size="mini" :type="r.recheckResult === 1 ? 'success' : 'danger'" class="kv-tag">{{ r.recheckResult === 1 ? '复检通过' : '复检不通过' }}</el-tag>
  53. <span v-if="r.recheckUserName" class="kv-user">复检人:{{ r.recheckUserName }}</span>
  54. </div>
  55. <div v-if="r.recheckRmk">{{ r.recheckRmk }}</div>
  56. <div class="pic-row" v-if="pictures(r.recheckPictures).length">
  57. <el-image
  58. v-for="(p, i) in pictures(r.recheckPictures)"
  59. :key="i"
  60. :src="p"
  61. fit="cover"
  62. :preview-src-list="pictures(r.recheckPictures)"
  63. class="thumb" />
  64. </div>
  65. </div>
  66. <div class="muted" v-else>尚未复检</div>
  67. </div>
  68. </div>
  69. </el-timeline-item>
  70. </el-timeline>
  71. <div class="empty" v-else>未找到整改记录</div>
  72. </div>
  73. <span slot="footer">
  74. <el-button @click="dialogVisible = false">关闭</el-button>
  75. </span>
  76. </el-dialog>
  77. </template>
  78. <script>
  79. import { post, fmt, fmtNum, splitPictures, RECT_STATUS } from '../common'
  80. export default {
  81. name: 'InspectRectificationDetail',
  82. props: {
  83. visible: Boolean,
  84. row: Object
  85. },
  86. computed: {
  87. dialogVisible: {
  88. get() { return this.visible },
  89. set(v) { this.$emit('update:visible', v) }
  90. }
  91. },
  92. data() {
  93. return { loading: false, rounds: [] }
  94. },
  95. methods: {
  96. load() {
  97. if (!this.row) return
  98. this.loading = true
  99. // 同任务同指标的多轮整改:通过 taskItemId 查询全部轮次
  100. const q = this.row.taskItemId
  101. ? { taskItemId: this.row.taskItemId, pageSize: 50, currentPage: 1 }
  102. : { taskId: this.row.taskId, indicatorId: this.row.indicatorId, pageSize: 50, currentPage: 1 }
  103. post(this.$axios, '/inspectManage/rectification/page', q).then(res => {
  104. const list = (res && res.list) || []
  105. this.rounds = list.length ? list.sort((a, b) => (a.rectRound || 1) - (b.rectRound || 1)) : [this.row]
  106. }).finally(() => { this.loading = false })
  107. },
  108. pictures(str) { return splitPictures(str) },
  109. rectText(v) { return (RECT_STATUS[v] || {}).text || '-' },
  110. rectStyle(v) {
  111. const st = RECT_STATUS[v]
  112. return { background: st.color, borderColor: st.color, color: '#fff' }
  113. },
  114. rectColor(v) { return (RECT_STATUS[v] || {}).color || '#909399' },
  115. fmt,
  116. fmtNum
  117. }
  118. }
  119. </script>
  120. <style scoped>
  121. .detail-wrap { max-height: 560px; overflow-y: auto; }
  122. .head { background: #f5f7fa; border-radius: 4px; padding: 12px 16px; margin-bottom: 16px; }
  123. .head-main { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
  124. .head-meta { display: flex; gap: 18px; color: #606266; font-size: 13px; }
  125. .round-card { border: 1px solid #ebeef5; border-radius: 6px; padding: 12px 14px; }
  126. .round-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
  127. .round-title { font-weight: 600; flex: 1; }
  128. .node { border-left: 3px solid #ebeef5; padding: 4px 0 12px 14px; margin-left: 4px; }
  129. .node.empty { border-left-color: #f0f2f5; }
  130. .node-title { color: #303133; font-weight: 600; margin-bottom: 6px; }
  131. .node-time { color: #909399; font-weight: 400; font-size: 12px; margin-left: 10px; }
  132. .node-content { color: #606266; font-size: 13px; line-height: 1.7; }
  133. .kv { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
  134. .kv-user { color: #909399; }
  135. .pic-row { display: flex; gap: 8px; margin-top: 8px; }
  136. .thumb { width: 56px; height: 56px; border-radius: 4px; }
  137. .muted { color: #909399; font-size: 12px; }
  138. .empty { color: #909399; padding: 30px; text-align: center; }
  139. </style>