PipeReportList.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <template>
  2. <div>
  3. <el-tooltip
  4. placement="top"
  5. effect="light"
  6. popper-class="report-list-tooltip"
  7. :disabled="isExpanded"
  8. >
  9. <template #content>
  10. <div class="tooltip-report-list">
  11. <div
  12. v-for="item in row.reportDOList"
  13. :key="item?.id"
  14. class="tooltip-report-item"
  15. @click="handleClick(row, item)"
  16. >
  17. <span
  18. class="tooltip-dot"
  19. :style="{ backgroundColor: getStatusColor(item.taskStatus) }"
  20. ></span>
  21. <span class="tooltip-name">{{ getReportName(item) }}</span>
  22. <span v-if="item?.fee" class="tooltip-fee">({{ item?.fee }})</span>
  23. </div>
  24. </div>
  25. </template>
  26. <div
  27. ref="containerRef"
  28. :class="['report-list-container', { expanded: isExpanded }]"
  29. >
  30. <span
  31. v-for="item in row.reportDOList"
  32. :key="item?.id"
  33. class="report-item"
  34. >
  35. <el-icon v-if="item?.recheckStatus === 300"
  36. class="warning-icon" size="16"
  37. >
  38. <WarningFilled/>
  39. </el-icon>
  40. <span v-else
  41. class="color-dot"
  42. :style="{ backgroundColor: getStatusColor(item.taskStatus) }"
  43. ></span>
  44. <span
  45. class="report-name"
  46. :style="{ color: getStatusColor(item.taskStatus) }"
  47. @click="() => handleClick(row, item)"
  48. >
  49. {{ getReportName(item) }}
  50. </span>
  51. <span
  52. v-if="item?.fee"
  53. class="report-fee"
  54. :style="{ color: getStatusColor(item.taskStatus) }"
  55. >
  56. ({{ item?.fee }})
  57. </span>
  58. </span>
  59. </div>
  60. </el-tooltip>
  61. <div
  62. v-if="isOverflow || isExpanded"
  63. class="expand-toggle"
  64. @click="isExpanded = !isExpanded"
  65. >
  66. <span>{{ isExpanded ? '收起' : '全部展开' }}</span>
  67. <el-icon
  68. :style="{
  69. transition: 'transform 0.3s',
  70. transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'
  71. }"
  72. >
  73. <ArrowDown />
  74. </el-icon>
  75. </div>
  76. </div>
  77. </template>
  78. <script setup lang="ts">
  79. import { ref, onMounted, nextTick, onUpdated } from 'vue'
  80. import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
  81. import { useRouter } from 'vue-router'
  82. import { WarningFilled, ArrowDown } from '@element-plus/icons-vue'
  83. import { PressureTaskOrderTaskStatus } from '@/utils/constants'
  84. import { PipeTaskOrderApi, PipeTaskOrderOrderItemVO } from '@/api/pressure2/pipetaskorder'
  85. import { useUserStore } from '@/store/modules/user'
  86. interface ReportItem {
  87. id: string
  88. reportName: string
  89. taskStatus: number
  90. fee?: string | number
  91. itemPartId?: string
  92. [key: string]: any
  93. }
  94. const router = useRouter()
  95. const props = defineProps<{
  96. row
  97. }>()
  98. const containerRef = ref<HTMLElement>()
  99. const isOverflow = ref(false)
  100. const isExpanded = ref(false)
  101. const checkOverflow = () => {
  102. if (containerRef.value) {
  103. isOverflow.value = containerRef.value.scrollHeight > containerRef.value.clientHeight + 1
  104. }
  105. }
  106. const PartTypeList = getStrDictOptions(DICT_TYPE.PRESSURE2_BOILER_PART_TYPE)
  107. const userStore = useUserStore()
  108. const getTypeName = (type: string) => {
  109. const item = PartTypeList.find(item => item.value === type)
  110. return item ? item.label : ''
  111. }
  112. const getReportName = (item: ReportItem) => {
  113. if (!item.itemPartId || item.itemPartId === '0') {
  114. return item.reportName
  115. }
  116. return `${item.reportName}(${getTypeName(item.itemPartId)})`
  117. }
  118. const getStatusColor = (status: number): string => {
  119. const statusMap: Record<number, string> = {
  120. 100: '#5B9BD5',
  121. 400: '#70AD47',
  122. 500: '#9973C2',
  123. 520: '#FFC000',
  124. 600: '#ED7D31',
  125. 700: '#FF8DC7',
  126. 800: '#303133'
  127. }
  128. return statusMap[status] || '#A7D78B'
  129. }
  130. const handleClick = async (row, item: ReportItem) => {
  131. if (row.isClaim === false) {
  132. return
  133. }
  134. if (!canCheckInput(row)) {
  135. return
  136. }
  137. const res = await PipeTaskOrderApi.checkSchemeStatus(row.orderId)
  138. if (!res) {
  139. ElMessage.warning('请先完成检验方案的审核审批')
  140. return
  141. }
  142. if (row.taskStatus >= PressureTaskOrderTaskStatus.REPORT_INPUT) {
  143. if (!row.endCheckDate) {
  144. ElMessage.error('请添加结束检验时间再进行编制!')
  145. return
  146. }
  147. }
  148. localStorage.setItem('activePipeDetailItemId', item.id)
  149. router.push({
  150. name: 'PipeCheckerTaskDetail',
  151. query: { id: row.id, type: 'PipeMyTask' }
  152. })
  153. }
  154. onMounted(() => {
  155. nextTick(() => {
  156. setTimeout(checkOverflow, 100)
  157. })
  158. })
  159. onUpdated(() => {
  160. nextTick(checkOverflow)
  161. })
  162. const canCheckInput = (row: PipeTaskOrderOrderItemVO) => {
  163. const userId = userStore.user.id
  164. if (row.mainCheckerUser && row.mainCheckerUser.id === userId) {
  165. return true
  166. }
  167. if (row.checkUsers && row.checkUsers.length > 0) {
  168. return row.checkUsers.some(user => user.id === userId)
  169. }
  170. return false
  171. }
  172. </script>
  173. <style lang="scss" scoped>
  174. .report-list-container {
  175. display: block;
  176. line-height: 1.8;
  177. overflow: hidden;
  178. max-height: 5.4em;
  179. &.expanded {
  180. max-height: none;
  181. }
  182. }
  183. .report-item {
  184. display: inline-block;
  185. white-space: nowrap;
  186. margin-right: 12px;
  187. vertical-align: top;
  188. .color-dot {
  189. display: inline-block;
  190. width: 8px;
  191. height: 8px;
  192. border-radius: 50%;
  193. vertical-align: middle;
  194. margin-right: 4px;
  195. }
  196. .warning-icon {
  197. color: lightcoral;
  198. display: inline-block;
  199. vertical-align: middle;
  200. margin-right: 4px;
  201. }
  202. .report-name {
  203. cursor: pointer;
  204. transition: opacity 0.2s;
  205. &:hover {
  206. opacity: 0.8;
  207. text-decoration: underline;
  208. }
  209. }
  210. .report-fee {
  211. margin-left: 2px;
  212. }
  213. }
  214. .expand-toggle {
  215. display: inline-flex;
  216. align-items: center;
  217. gap: 2px;
  218. color: #409eff;
  219. font-size: 12px;
  220. cursor: pointer;
  221. user-select: none;
  222. margin-top: 2px;
  223. &:hover {
  224. color: #66b1ff;
  225. }
  226. }
  227. </style>
  228. <style lang="scss">
  229. .report-list-tooltip {
  230. max-width: 400px !important;
  231. padding: 12px 16px !important;
  232. }
  233. .tooltip-report-list {
  234. max-height: 300px;
  235. overflow-y: auto;
  236. }
  237. .tooltip-report-item {
  238. display: flex;
  239. align-items: center;
  240. line-height: 2;
  241. white-space: nowrap;
  242. cursor: pointer;
  243. padding: 2px 4px;
  244. border-radius: 4px;
  245. &:hover {
  246. background-color: #f5f7fa;
  247. }
  248. }
  249. .tooltip-dot {
  250. display: inline-block;
  251. width: 8px;
  252. height: 8px;
  253. border-radius: 50%;
  254. margin-right: 8px;
  255. flex-shrink: 0;
  256. }
  257. .tooltip-name {
  258. color: #303133;
  259. }
  260. .tooltip-fee {
  261. color: #909399;
  262. margin-left: 4px;
  263. }
  264. </style>