myTask.vue 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  1. <template>
  2. <ContentWrap>
  3. <!-- 搜索工作栏 -->
  4. <el-form
  5. class="-mb-15px"
  6. :model="queryParams"
  7. ref="queryFormRef"
  8. :inline="true"
  9. label-width="100px"
  10. >
  11. <el-row :gutter="20" class="flex-wrap" style="margin-right: 0">
  12. <el-form-item label="工程号" prop="projectNo">
  13. <el-input
  14. v-model="queryParams.projectNo"
  15. placeholder="请输入工程号"
  16. clearable
  17. @keyup.enter="handleQuery"
  18. class="!w-240px"
  19. />
  20. </el-form-item>
  21. <el-form-item label="主报告状态" prop="taskStatusList">
  22. <el-select
  23. multiple
  24. v-model="queryParams.taskStatusList"
  25. placeholder="请选择主报告状态"
  26. clearable
  27. class="!w-240px"
  28. >
  29. <el-option
  30. v-for="(item, key) in PressureCheckerMyTaskStatusMap"
  31. :key="key"
  32. :label="item"
  33. :value="key"
  34. />
  35. </el-select>
  36. </el-form-item>
  37. <el-form-item label="任务单号" prop="orderNo">
  38. <el-input
  39. v-model="queryParams.orderNo"
  40. placeholder="请输入任务单号"
  41. clearable
  42. @keyup.enter="handleQuery"
  43. class="!w-240px"
  44. />
  45. </el-form-item>
  46. <el-form-item label="使用单位" prop="unitName">
  47. <el-input
  48. v-model="queryParams.unitName"
  49. placeholder="请输入使用单位"
  50. clearable
  51. @keyup.enter="handleQuery"
  52. class="!w-240px"
  53. />
  54. </el-form-item>
  55. <el-collapse-transition>
  56. <div v-show="isSearchExpanded">
  57. <el-form-item label="检验性质" prop="checkType">
  58. <el-select
  59. v-model="queryParams.checkType"
  60. placeholder="请选择检验性质"
  61. clearable
  62. class="!w-240px"
  63. >
  64. <el-option
  65. v-for="(item, key) in PressurePipeCheckTypeMap"
  66. :key="key"
  67. :label="item"
  68. :value="key"
  69. />
  70. </el-select>
  71. </el-form-item>
  72. <el-form-item label="检验时间" prop="checkDate">
  73. <el-date-picker
  74. v-model="queryParams.checkDate"
  75. value-format="YYYY-MM-DD HH:mm:ss"
  76. type="daterange"
  77. start-placeholder="开始日期"
  78. end-placeholder="结束日期"
  79. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  80. class="!w-240px"
  81. />
  82. </el-form-item>
  83. <!-- <el-form-item label="检验员" prop="inspectorName">-->
  84. <!-- <el-input-->
  85. <!-- v-model="queryParams.inspectorName"-->
  86. <!-- placeholder="请输入检验员名称"-->
  87. <!-- clearable-->
  88. <!-- @keyup.enter="handleQuery"-->
  89. <!-- class="!w-240px"-->
  90. <!-- />-->
  91. <!-- </el-form-item>-->
  92. <el-form-item label="检验员" prop="checkUserIds">
  93. <el-select
  94. class="!w-240px"
  95. v-model="queryParams.checkUserIds"
  96. readonly
  97. clearable
  98. placeholder="请选择检验员"
  99. multiple
  100. popper-class="user-select-popper"
  101. @click.stop.prevent="() => handleOpenUserDialog(recheckStrIdsOpts, 'checkUserIds')"
  102. >
  103. <el-option
  104. v-for="child in recheckStrIdsOpts"
  105. :key="child && child.id"
  106. :label="child.nickName"
  107. :value="child.id"
  108. />
  109. </el-select>
  110. </el-form-item>
  111. <!-- <el-form-item label="排期人员" prop="manager">-->
  112. <!-- <el-input-->
  113. <!-- v-model="queryParams.manager"-->
  114. <!-- placeholder="请输入排期人员"-->
  115. <!-- clearable-->
  116. <!-- @keyup.enter="handleQuery"-->
  117. <!-- class="!w-240px"-->
  118. <!-- />-->
  119. <!-- </el-form-item>-->
  120. <!-- <el-form-item label="项目负责人" prop="manager">-->
  121. <!-- <el-input-->
  122. <!-- v-model="queryParams.manager"-->
  123. <!-- placeholder="请输入项目负责人"-->
  124. <!-- clearable-->
  125. <!-- @keyup.enter="handleQuery"-->
  126. <!-- class="!w-240px"-->
  127. <!-- />-->
  128. <!-- </el-form-item>-->
  129. <el-form-item label="项目负责人" prop="managerIds">
  130. <el-select
  131. class="!w-240px"
  132. v-model="queryParams.managerIds"
  133. readonly
  134. clearable
  135. placeholder="请选择项目负责人"
  136. multiple
  137. popper-class="user-select-popper"
  138. @click.stop.prevent="() => handleOpenUserDialog(recheckStrIdsOpts, 'managerIds')"
  139. >
  140. <el-option
  141. v-for="child in recheckStrIdsOpts"
  142. :key="child && child.id"
  143. :label="child.nickName"
  144. :value="child.id"
  145. />
  146. </el-select>
  147. </el-form-item>
  148. <!-- 出厂编号 -->
  149. <!-- <el-form-item label="出厂编号" prop="remainingDays">-->
  150. <!-- <el-input-->
  151. <!-- v-model="queryParams.remainingDays"-->
  152. <!-- placeholder="请输入出厂编号"-->
  153. <!-- clearable-->
  154. <!-- @keyup.enter="handleQuery"-->
  155. <!-- class="!w-240px"-->
  156. <!-- />-->
  157. <!-- </el-form-item>-->
  158. <!-- 剩余期限 -->
  159. <!-- <el-form-item label="剩余期限" prop="remainingDays">-->
  160. <!-- <el-input-->
  161. <!-- v-model="queryParams.remainingDays"-->
  162. <!-- placeholder="请输入剩余期限"-->
  163. <!-- clearable-->
  164. <!-- @keyup.enter="handleQuery"-->
  165. <!-- class="!w-240px"-->
  166. <!-- />-->
  167. <!-- </el-form-item>-->
  168. <!-- <el-form-item label="主检人" prop="mainCheckerIds">-->
  169. <!-- <el-input-->
  170. <!-- v-model="queryParams.mainCheckerIds"-->
  171. <!-- placeholder="请选择"-->
  172. <!-- clearable-->
  173. <!-- @keyup.enter="handleQuery"-->
  174. <!-- class="!w-240px"-->
  175. <!-- />-->
  176. <!-- </el-form-item>-->
  177. <el-form-item label="主检人" prop="mainCheckerIds">
  178. <el-select
  179. class="!w-240px"
  180. v-model="queryParams.mainCheckerIds"
  181. readonly
  182. clearable
  183. placeholder="请选择主检人"
  184. multiple
  185. popper-class="user-select-popper"
  186. @click.stop.prevent="() => handleOpenUserDialog(recheckStrIdsOpts, 'mainCheckerIds')"
  187. >
  188. <el-option
  189. v-for="child in recheckStrIdsOpts"
  190. :key="child && child.id"
  191. :label="child.nickName"
  192. :value="child.id"
  193. />
  194. </el-select>
  195. </el-form-item>
  196. </div>
  197. </el-collapse-transition>
  198. </el-row>
  199. <!-- 按钮区保持不变 -->
  200. <el-row class="flex justify-end mt-2">
  201. <el-form-item>
  202. <el-button @click="handleQuery">
  203. <Icon icon="ep:search" class="mr-5px"/>
  204. 搜索
  205. </el-button>
  206. <el-button @click="resetQuery">
  207. <Icon icon="ep:refresh" class="mr-5px"/>
  208. 重置
  209. </el-button>
  210. <el-button type="primary" @click="showSettingDialog">
  211. <Icon icon="ep:user" class="mr-5px"/>
  212. 审核配置
  213. </el-button>
  214. <el-button link @click="isSearchExpanded = !isSearchExpanded">
  215. <el-icon>
  216. <ArrowUp v-if="isSearchExpanded"/>
  217. <ArrowDown v-else/>
  218. </el-icon>
  219. {{ isSearchExpanded ? '收起' : '展开' }}
  220. </el-button>
  221. </el-form-item>
  222. </el-row>
  223. </el-form>
  224. <!-- <el-radio-group v-model="filterStatus" @change="handleStatusFilter" style="margin-top: 20px;">-->
  225. <!-- <el-radio-button label="全部" value="all"/>-->
  226. <!-- <el-radio-button label="已认领" value="claim"/>-->
  227. <!-- <el-radio-button label="待认领" value="unclaim"/>-->
  228. <!-- </el-radio-group>-->
  229. </ContentWrap>
  230. <!-- 列表 -->
  231. <ContentWrap>
  232. <el-table v-loading="loading" :data="list" :stripe="true" ref="MyTaskTableListRef"
  233. border
  234. class-name="cursor-pointer" @row-dblclick="handleRowDblclick">
  235. <el-table-column type="selection" align="center" width="55"/>
  236. <el-table-column
  237. label="剩余期限 (工作日)"
  238. align="center"
  239. prop="remainingDays"
  240. min-width="140px"
  241. />
  242. <el-table-column label="任务单号" align="center" prop="orderNo" min-width="150px"/>
  243. <el-table-column label="工程号" align="center" prop="projectNoList" min-width="200px">
  244. <template #default="{ row }">
  245. <div class="project-info"
  246. v-for="(item, index) in row.projectNoList"
  247. :key="item?.id || index">
  248. <el-tag type="success" class="project-name-tag">{{ item }}</el-tag>
  249. </div>
  250. </template>
  251. </el-table-column>
  252. <el-table-column label="使用单位" align="center" prop="unitName" min-width="150px"/>
  253. <el-table-column label="检验性质" align="center" prop="checkType" min-width="120px">
  254. <template #default="scope">
  255. {{ PressurePipeCheckTypeMap[scope.row.checkType] }}
  256. </template>
  257. </el-table-column>
  258. <!-- 检验项目 -->
  259. <el-table-column align="center" prop="reportDOList" :min-width="200">
  260. <!-- <template #default="scope">
  261. <div v-if="scope.row.reportDOList && scope.row.reportDOList.length > 0">
  262. <div class="reportDOList-item">
  263. &lt;!&ndash; 数据大于2条时,使用展开收起功能 &ndash;&gt;
  264. <div v-if="scope.row.reportDOList.length > 2">
  265. &lt;!&ndash; 始终显示的前2条数据 &ndash;&gt;
  266. <div
  267. v-for="(item, index) in scope.row.reportDOList.slice(0, 2)"
  268. :key="item?.id || index"
  269. class="report-item"
  270. >
  271. <div style="color: #015293">
  272. {{ index + 1 }}、{{ item?.reportName }}
  273. </div>
  274. <div v-if="item?.fee" style="color: #015293">
  275. (费用:{{ item?.fee }})
  276. </div>
  277. </div>
  278. &lt;!&ndash; 可展开的剩余数据 &ndash;&gt;
  279. <div
  280. class="expandable-content"
  281. :style="{
  282. maxHeight: isExpanded(scope.row)
  283. ? `${(scope.row.reportDOList.length - 2) * 40}px`
  284. : '0px',
  285. transition: 'max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
  286. overflow: 'hidden'
  287. }"
  288. >
  289. <div
  290. v-for="(item, index) in scope.row.reportDOList.slice(2)"
  291. :key="item?.id || `extra-${index}`"
  292. class="report-item-animated"
  293. :style="{
  294. opacity: isExpanded(scope.row) ? 1 : 0,
  295. transform: isExpanded(scope.row) ? 'translateY(0)' : 'translateY(-10px)',
  296. transition: `all 0.3s ease ${index * 50}ms`,
  297. padding: '2px 0'
  298. }"
  299. >
  300. <div link type="primary" style="color: #015293">
  301. {{ index + 3 }}、{{ item?.reportName }}
  302. </div>
  303. <div v-if="item?.fee" style="color: #015293">
  304. (费用:{{ item?.fee }})
  305. </div>
  306. </div>
  307. </div>
  308. &lt;!&ndash; 展开收起按钮 &ndash;&gt;
  309. <div class="expand-control" style="text-align: center; margin-top: 8px">
  310. <el-button
  311. size="small"
  312. link
  313. type="primary"
  314. @click="toggleExpand(scope.row)"
  315. class="expand-button"
  316. :style="{
  317. transition: 'all 0.2s ease'
  318. }"
  319. >
  320. <span style="margin-right: 4px">
  321. {{
  322. isExpanded(scope.row)
  323. ? '收起'
  324. : `查看更多(${scope.row.reportDOList.length - 2}条)`
  325. }}
  326. </span>
  327. <el-icon
  328. :style="{
  329. width: '12px',
  330. height: '12px',
  331. display: 'inline-block',
  332. transition: 'transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
  333. transform: isExpanded(scope.row) ? 'rotate(180deg)' : 'rotate(0deg)'
  334. }"
  335. >
  336. <ArrowDown />
  337. </el-icon>
  338. </el-button>
  339. </div>
  340. </div>
  341. &lt;!&ndash; 数据小于等于2条时,直接显示所有数据 &ndash;&gt;
  342. <div v-else>
  343. <div
  344. v-for="(item, index) in scope.row.reportDOList"
  345. :key="item?.id || index"
  346. class="report-item"
  347. >
  348. <div style="color: #015293">
  349. {{ index + 1 }}、{{ item?.reportName }}
  350. </div>
  351. <div v-if="item?.fee" style="color: #015293">
  352. (费用:{{ item?.fee }})
  353. </div>
  354. </div>
  355. </div>
  356. </div>
  357. </div>
  358. <div v-else class="empty-data">-</div>
  359. </template>-->
  360. <template #header>
  361. <span class="table-header-content">
  362. 检验项目
  363. <el-tooltip placement="bottom" effect="light" popper-class="status-help-tooltip">
  364. <template #content>
  365. <div class="status-help-content">
  366. <div class="help-title">状态说明</div>
  367. <div class="status-list">
  368. <div
  369. v-for="item in statusList"
  370. :key="item.status"
  371. class="status-item"
  372. >
  373. <div class="color-dot" :style="{ backgroundColor: item.color }"></div>
  374. <span class="status-label">{{ item.label }}</span>
  375. </div>
  376. </div>
  377. </div>
  378. </template>
  379. <el-icon class="help-icon">
  380. <QuestionFilled/>
  381. </el-icon>
  382. </el-tooltip>
  383. </span>
  384. </template>
  385. <template #default="scope">
  386. <PipeReportList :row="scope.row"/>
  387. </template>
  388. </el-table-column>
  389. <!-- <el-table-column label="任务状态" align="center" prop="isClaim" min-width="150px">-->
  390. <!-- <template #default="scope">-->
  391. <!-- <el-tag :type="getTypeColor(scope.row.isClaim ? 400 : 100)">{{-->
  392. <!-- PressureTaskOrderTaskStatusMap[scope.row.isClaim ? 400 : 100]-->
  393. <!-- }}-->
  394. <!-- </el-tag>-->
  395. <!-- </template>-->
  396. <!-- </el-table-column>-->
  397. <el-table-column label="主报告状态" align="center" prop="taskStatus" min-width="150px">
  398. <template #default="scope">
  399. <el-tag :type="getTypeColor(scope.row.taskStatus)">{{
  400. PressureCheckerMyTaskStatusMap[scope.row.taskStatus]
  401. }}
  402. </el-tag>
  403. </template>
  404. </el-table-column>
  405. <el-table-column label="检验时间" align="center" prop="checkDate" min-width="120px">
  406. <template #default="scope">
  407. {{ formatArrayDate(scope.row.checkDate) }}
  408. </template>
  409. </el-table-column>
  410. <el-table-column label="项目负责人" align="center" prop="manager" min-width="120px">
  411. <template #default="scope">
  412. {{
  413. scope.row.manager
  414. ? scope.row.manager.nickname + ' (' + scope.row.manager.employeeNo + ')'
  415. : '-'
  416. }}
  417. </template>
  418. </el-table-column>
  419. <!-- 主检人 -->
  420. <el-table-column label="主检人" align="center" prop="mainInspector" min-width="120px">
  421. <template #default="scope">
  422. {{
  423. scope.row.mainCheckerUser
  424. ? scope.row.mainCheckerUser.nickname +
  425. ' (' +
  426. scope.row.mainCheckerUser.employeeNo +
  427. ')'
  428. : '-'
  429. }}
  430. </template>
  431. </el-table-column>
  432. <el-table-column label="检验员" align="center" prop="checkUsers" min-width="150px">
  433. <template #default="scope">
  434. <div v-if="scope.row.checkUsers && scope.row.checkUsers.length > 0">
  435. <div v-for="user in scope.row.checkUsers" :key="user.id">
  436. {{ user.nickname }} ({{ user.employeeNo }})
  437. </div>
  438. </div>
  439. <div v-else>-</div>
  440. </template>
  441. </el-table-column>
  442. <!--排期人员 -->
  443. <!-- <el-table-column label="排期人员" align="center" prop="planCheckUsers" min-width="120px">-->
  444. <!-- <template #default="scope">-->
  445. <!-- {{-->
  446. <!-- scope.row.planCheckUsers-->
  447. <!-- ? scope.row.planCheckUsers.nickname +-->
  448. <!-- ' (' +-->
  449. <!-- scope.row.planCheckUsers.employeeNo +-->
  450. <!-- ')'-->
  451. <!-- : '-'-->
  452. <!-- }}-->
  453. <!-- </template>-->
  454. <!-- </el-table-column>-->
  455. <el-table-column label="操作" align="center" min-width="150px" fixed="right">
  456. <template #default="scope">
  457. <div class="flex flex-col gap-1">
  458. <!-- <el-button-->
  459. <!-- v-if="!scope.row.mainCheckerUser"-->
  460. <!-- link-->
  461. <!-- type="primary"-->
  462. <!-- @click="handleClaim(scope.row.id)"-->
  463. <!-- >-->
  464. <!-- 认领-->
  465. <!-- </el-button>-->
  466. <el-button
  467. link
  468. type="primary"
  469. :disabled="!canCheckInput(scope.row)"
  470. @click="handleCheckInput(scope.row.id,scope.row.orderId)">
  471. 检验录入
  472. </el-button>
  473. <el-button
  474. link
  475. type="primary"
  476. @click="printProject(scope.row.reportDOList)"
  477. >
  478. 打印项目
  479. </el-button>
  480. <!-- <el-button-->
  481. <!-- v-if="scope.row.taskStatus == 400 && scope.row.isClaim == true && scope.row.mainCheckerUser && userStore.user.id === scope.row.mainCheckerUser.id"-->
  482. <!-- link-->
  483. <!-- type="primary"-->
  484. <!-- @click="handleCancelClaim(scope.row.id)"-->
  485. <!-- >-->
  486. <!-- 取消认领-->
  487. <!-- </el-button>-->
  488. <el-button v-if="scope.row.mainCheckerUser && userStore.user.id === scope.row.mainCheckerUser.id" link type="primary" @click="handleFinishCheck(scope.row.id,scope.row.endCheckDate)">
  489. 结束检验
  490. </el-button>
  491. </div>
  492. </template>
  493. </el-table-column>
  494. </el-table>
  495. <!-- 分页 -->
  496. <Pagination
  497. :total="total"
  498. v-model:page="queryParams.pageNo"
  499. v-model:limit="queryParams.pageSize"
  500. @pagination="getList"
  501. />
  502. </ContentWrap>
  503. <SettingDialog ref="formRef" />
  504. <!-- 结束检验弹窗 -->
  505. <endCheckForm ref="endCheckFormRef" @success="handleScheduleSuccess" />
  506. <!-- 选择人员公共弹窗 -->
  507. <CustomDialog
  508. v-model="customUserDialogVisible"
  509. :dialogAttrs="{
  510. zIndex: 10006
  511. }"
  512. @confirm="handleUserConfirm"
  513. >
  514. <el-input
  515. v-model="userQueryData.nickName"
  516. clearable
  517. placeholder="请输入名称"
  518. @keyup.enter="handleFetchUserList"
  519. style="margin-bottom: 14px"
  520. />
  521. <SmartTable
  522. ref="userTableRef"
  523. v-model:pageNo="userQueryData.pageNo"
  524. v-model:pagesize="userQueryData.pageSize"
  525. :total="userQueryData.total"
  526. v-model:columns="userColumns"
  527. :data="userTableList"
  528. :buttons="[]"
  529. :showSettingTools="false"
  530. :showSearch="false"
  531. :showRefresh="false"
  532. @on-page-size-change="onPageSizeChange"
  533. @on-page-no-change="onPageNoChange"
  534. />
  535. </CustomDialog>
  536. <CustomDialog
  537. v-model="printProjectDialogVisible"
  538. :close-on-click-modal="true"
  539. >
  540. <el-table
  541. :data="printProjectList"
  542. style="width: 100%"
  543. @selection-change="handleSelectionChange"
  544. >
  545. <el-table-column
  546. type="selection"
  547. align="center"
  548. />
  549. <el-table-column
  550. label="序号"
  551. width="60"
  552. align="center"
  553. type="index"
  554. />
  555. <el-table-column
  556. label="项目"
  557. align="center"
  558. prop="reportName"
  559. />
  560. <el-table-column
  561. label="项目状态"
  562. align="center"
  563. prop="taskStatus"
  564. >
  565. <template #default="scope">
  566. <el-tag :type="getTypeColor(scope.row.taskStatus)">
  567. {{ PressureTaskOrderTaskStatusMap[scope.row.taskStatus] }}
  568. </el-tag>
  569. </template>
  570. </el-table-column>
  571. </el-table>
  572. <template #footer>
  573. <el-button type="success" @click="handlePrint">打印</el-button>
  574. <el-button type="danger" @click="handleDownload">下载</el-button>
  575. </template>
  576. </CustomDialog>
  577. </template>
  578. <script setup lang="ts">
  579. import {ref, reactive, onMounted, computed} from 'vue'
  580. import {formatArrayDate} from '@/utils/formatTime'
  581. //import SettingDialog from './components/SettingDialog.vue'
  582. import {PipeTaskOrderApi, PipeTaskOrderOrderItemVO} from '@/api/pressure2/pipetaskorder'
  583. import {
  584. PressureCheckerMyTaskStatus,
  585. PressureCheckerMyTaskStatusMap, PressurePipeCheckTypeMap,
  586. PressureTaskOrderTaskStatus, PressureTaskOrderTaskStatusMap
  587. } from '@/utils/constants'
  588. import {ElMessageBox, ElMessage} from 'element-plus'
  589. import {useRoute, useRouter} from 'vue-router'
  590. import {ArrowDown, ArrowUp, QuestionFilled} from "@element-plus/icons-vue";
  591. import { useUserStore } from '@/store/modules/user'
  592. import {useEmitt} from "@/hooks/web/useEmitt";
  593. import endCheckForm from './components/endCheckForm.vue'
  594. import SmartTable from "@/components/SmartTable/SmartTable";
  595. import { getUserList } from '@/api/common/user'
  596. import SettingDialog from "@/views/pressure/checker/components/SettingDialog.vue";
  597. import {PipeInputApi} from "@/api/pressure2/pipeInput";
  598. import 'https://printjs-4de6.kxcdn.com/print.min.js'
  599. import PipeReportList from "@/views/pressure2/pipeReportPreparationList/PipeReportList.vue";
  600. const { emitter } = useEmitt()
  601. const router = useRouter()
  602. const route = useRoute()
  603. const userStore = useUserStore()
  604. const loginUser = useUserStore().user;
  605. const getTypeColor = (status: string | number) => {
  606. const statusMap = {
  607. [PressureTaskOrderTaskStatus.WAIT_CONFIRM]: 'primary',
  608. [PressureTaskOrderTaskStatus.CANCELLED]: 'info',
  609. [PressureTaskOrderTaskStatus.AUDITING_EDIT]: 'warning',
  610. [PressureTaskOrderTaskStatus.AUDITING_CANCEL]: 'warning',
  611. [PressureTaskOrderTaskStatus.AUDITING_TIME]: 'warning',
  612. [PressureTaskOrderTaskStatus.CONFIRMED]: 'success',
  613. [PressureTaskOrderTaskStatus.RECORD_INPUT]: 'warning',
  614. [PressureTaskOrderTaskStatus.RECORD_CHECK]: 'warning',
  615. [PressureTaskOrderTaskStatus.REPORT_INPUT]: 'warning',
  616. [PressureTaskOrderTaskStatus.REPORT_AUDIT]: 'warning',
  617. [PressureTaskOrderTaskStatus.REPORT_APPROVE]: 'warning',
  618. [PressureTaskOrderTaskStatus.REPORT_END]: 'success'
  619. }
  620. return statusMap[status] || 'info'
  621. }
  622. const statusList = [
  623. { status: PressureCheckerMyTaskStatus.CONFIRMED, label: '待录入', color: '#5B9BD5' },
  624. { status: PressureCheckerMyTaskStatus.RECORD_INPUT, label: '记录录入', color: '#70AD47' },
  625. { status: PressureCheckerMyTaskStatus.RECORD_CHECK, label: '记录校核', color: '#9973C2' },
  626. { status: PressureCheckerMyTaskStatus.REPORT_INPUT, label: '报告编制', color: '#FFC000' },
  627. { status: PressureCheckerMyTaskStatus.REPORT_AUDIT, label: '报告审核', color: '#ED7D31' },
  628. { status: PressureCheckerMyTaskStatus.REPORT_APPROVE, label: '报告审批', color: '#FF8DC7' },
  629. { status: PressureCheckerMyTaskStatus.REPORT_END, label: '报告办结', color: '#303133' }
  630. ]
  631. /** 承压任务单 列表 */
  632. defineOptions({name: 'PipeMyTask'})
  633. const isSearchExpanded = ref(false)
  634. // 状态筛选
  635. const filterStatus = ref('all') // 默认选中全部
  636. const loading = ref(true)
  637. const list = ref<PipeTaskOrderOrderItemVO[]>([])
  638. const total = ref(0)
  639. const queryParams = reactive<Recordable>({
  640. pageNo: 1,
  641. pageSize: 10,
  642. unitCode: undefined,
  643. unitName: undefined,
  644. orderNo: undefined,
  645. checkType: undefined,
  646. checkDate: [],
  647. checkUserIds: [],
  648. mainCheckerIds: [],
  649. managerIds: [],
  650. isClaim: 'all',
  651. taskStatusList: undefined,
  652. remainingDays: undefined
  653. })
  654. const queryFormRef = ref()
  655. const formRef = ref()
  656. const endCheckFormRef = ref()
  657. const showSettingDialog = () => {
  658. formRef.value.open()
  659. }
  660. const MyTaskTableListRef = ref() // table的实例
  661. /** 查询列表 */
  662. const getList = async () => {
  663. loading.value = true
  664. try {
  665. const params: any = {...queryParams}
  666. const data = await PipeTaskOrderApi.getTaskOrderOrderItemPage(params)
  667. list.value = data.list
  668. total.value = data.total
  669. } catch (error) {
  670. console.error('获取我的任务列表失败:', error)
  671. ElMessage.error('获取我的任务列表失败')
  672. list.value = []
  673. total.value = 0
  674. } finally {
  675. loading.value = false
  676. }
  677. }
  678. /** 搜索按钮操作 */
  679. const handleQuery = () => {
  680. queryParams.pageNo = 1
  681. getList()
  682. }
  683. /** 重置按钮操作 */
  684. const resetQuery = () => {
  685. queryFormRef.value.resetFields()
  686. handleQuery()
  687. }
  688. // 判断是否可以检验录入:当前用户是检验员或主检人
  689. const canCheckInput = (row: PipeTaskOrderOrderItemVO) => {
  690. const userId = userStore.user.id
  691. // 检查是否是主检人
  692. if (row.mainCheckerUser && row.mainCheckerUser.id === userId) {
  693. return true
  694. }
  695. // 检查是否是检验员
  696. if (row.checkUsers && row.checkUsers.length > 0) {
  697. return row.checkUsers.some(user => user.id === userId)
  698. }
  699. return false
  700. }
  701. // 检验录入
  702. const handleCheckInput = (id: string,orderId: string) => {
  703. router.push({ name: 'PipeCheckerTaskDetail', query: { id, orderId:orderId, type: 'PipeMyTask' } })
  704. }
  705. // 添加结束检验时间
  706. const handleFinishCheck = (id: string,endCheckDate: any) => {
  707. endCheckFormRef.value.open(id,endCheckDate)
  708. }
  709. const printProjectDialogVisible = ref(false)
  710. const printProjectList = ref([])
  711. const selectionProject = ref([])
  712. const printProject = (reportDOList) => {
  713. printProjectDialogVisible.value = true
  714. printProjectList.value = reportDOList
  715. }
  716. const handleSelectionChange = (selection) => {
  717. // 根据表格的序号重新排序 selection
  718. const sortedSelection = selection.map(item => {
  719. // 在原始数据中查找该项的索引
  720. const index = printProjectList.value.findIndex(v => v.id === item.id)
  721. return {
  722. ...item,
  723. _index: index // 临时存储原始索引
  724. }
  725. })
  726. // 按照索引排序
  727. sortedSelection.sort((a, b) => a._index - b._index)
  728. // 移除临时索引字段
  729. selectionProject.value = sortedSelection.map(({ _index, ...rest }) => rest)
  730. }
  731. const handleDownload = async () => {
  732. let data: any[] = []
  733. console.log(selectionProject)
  734. selectionProject.value.forEach(
  735. (item) => {
  736. data.push({
  737. taskStatus: item.taskStatus,
  738. resultTemplateId: item.resultTemplateId,
  739. templateId: item.templateId,
  740. reportTemplateId: item.reportTemplateId,
  741. reportUrl: item.reportUrl,
  742. id: item.id,
  743. })
  744. }
  745. )
  746. try {
  747. // 调用 API 获取 ZIP blob
  748. const zipBlob = await PipeInputApi.handleDownload(data)
  749. if (zipBlob) {
  750. // 创建临时 URL
  751. const zipUrl = URL.createObjectURL(zipBlob)
  752. // 创建隐藏的 a 标签触发下载
  753. const link = document.createElement('a')
  754. link.href = zipUrl
  755. link.download = '管道检测录入报告.zip'
  756. document.body.appendChild(link)
  757. link.click()
  758. // 清理 DOM 和 URL
  759. document.body.removeChild(link)
  760. URL.revokeObjectURL(zipUrl)
  761. ElMessage.success('下载成功')
  762. } else {
  763. ElMessage.error('获取下载文件失败')
  764. }
  765. } catch (error) {
  766. console.error('下载失败:', error)
  767. ElMessage.error('下载失败')
  768. }
  769. }
  770. const handlePrint = async () => {
  771. let data: any[] = []
  772. selectionProject.value.forEach(
  773. (item) => {
  774. data.push({
  775. taskStatus: item.taskStatus,
  776. resultTemplateId: item.resultTemplateId,
  777. templateId: item.templateId,
  778. reportTemplateId: item.reportTemplateId,
  779. reportUrl: item.reportUrl,
  780. id: item.id,
  781. })
  782. }
  783. )
  784. let loadingInstance = ElLoading.service({
  785. lock: true,
  786. text: '正在打印...',
  787. spinner: 'el-icon-loading',
  788. })
  789. try {
  790. // 调用 API 获取 PDF blob
  791. const pdfBlob = await PipeInputApi.handlePrint(data)
  792. if (pdfBlob) {
  793. // 创建临时 URL
  794. const pdfUrl = URL.createObjectURL(pdfBlob)
  795. // 使用 printJS 打印
  796. printJS({
  797. printable: pdfUrl,
  798. type: 'pdf',
  799. showModal: false,
  800. onPrintDialogClose: () => {
  801. // 打印对话框关闭后释放 URL
  802. URL.revokeObjectURL(pdfUrl)
  803. }
  804. })
  805. } else {
  806. ElMessage.error('获取打印文件失败')
  807. }
  808. } catch (error) {
  809. console.error('打印失败:', error)
  810. ElMessage.error('打印失败')
  811. }finally {
  812. loadingInstance.close()
  813. }
  814. }
  815. /** 修改成功处理 */
  816. const handleScheduleSuccess = () => {
  817. //通知父组件刷新数据
  818. getList()
  819. }
  820. const handleRowDblclick = (row: Record<string, any>) => {
  821. if (row.isClaim === false) {
  822. return
  823. }
  824. router.push({ name: 'PipeCheckerTaskDetail', query: { id: row.id, type: 'PipeReportPreparationList' } })
  825. }
  826. const handleClaim = (id: string) => {
  827. ElMessageBox.confirm('是否确认认领?', '提示', {
  828. confirmButtonText: '确定',
  829. cancelButtonText: '取消',
  830. type: 'warning'
  831. })
  832. .then(() => {
  833. PipeTaskOrderApi.claim({id: id}).then(() => {
  834. ElMessage.success('认领成功')
  835. getList()
  836. })
  837. })
  838. .catch(() => {
  839. })
  840. }
  841. //取消认领
  842. const handleCancelClaim = (id: string) => {
  843. ElMessageBox.confirm('是否取消认领?', '提示', {
  844. confirmButtonText: '确定',
  845. cancelButtonText: '取消',
  846. type: 'warning'
  847. })
  848. .then(() => {
  849. PipeTaskOrderApi.cancelClaim({id: id}).then(() => {
  850. ElMessage.success('取消认领成功')
  851. getList()
  852. })
  853. })
  854. .catch(() => {
  855. })
  856. }
  857. /** 处理状态筛选 */
  858. const handleStatusFilter = () => {
  859. // 设置状态筛选
  860. queryParams.isClaim = filterStatus.value
  861. // 重置页码并触发查询
  862. queryParams.pageNo = 1
  863. getList()
  864. }
  865. // 存储展开状态的响应式数据
  866. const expandedRows = ref(new Set())
  867. // 判断行是否展开
  868. const isExpanded = (row) => {
  869. return expandedRows.value.has(row.id || JSON.stringify(row))
  870. }
  871. // 切换展开状态
  872. const toggleExpand = (row) => {
  873. const rowKey = row.id || JSON.stringify(row)
  874. if (expandedRows.value.has(rowKey)) {
  875. expandedRows.value.delete(rowKey)
  876. } else {
  877. expandedRows.value.add(rowKey)
  878. }
  879. }
  880. // 人员选择弹窗
  881. const userTableRef = ref()
  882. const userInfo = computed(() => userStore.user)
  883. const fieldKey = ref('')
  884. const customUserDialogVisible = ref(false)
  885. const checkFormOptions = ref<any[]>([])
  886. interface UserListQuery {
  887. nickName: string
  888. pageNo: number
  889. pageSize: number
  890. total?: number
  891. }
  892. const userQueryData = reactive<UserListQuery>({
  893. nickName: '',
  894. pageNo: 1,
  895. pageSize: 10,
  896. total: 0
  897. })
  898. const recheckStrIdsOpts = ref<any[]>([
  899. { id: userInfo.value.id, nickName: userInfo.value?.nickname }
  900. ])
  901. const userTableList = ref<any[]>([])
  902. const userColumns = ref<any[]>([
  903. {
  904. type: 'selection',
  905. width: '50px'
  906. },
  907. {
  908. label: '工号',
  909. prop: 'employeeNo'
  910. },
  911. {
  912. label: '姓名',
  913. prop: 'nickname'
  914. },
  915. {
  916. label: '部门',
  917. prop: 'deptName'
  918. }
  919. ])
  920. const handleUserConfirm = () => {
  921. const selectRows = userTableRef.value.getTableRef().getSelectionRows()
  922. // 过滤组合合成options
  923. const currOptions = checkFormOptions.value.map((item) => item.id) || []
  924. selectRows
  925. .filter((item) => !currOptions.includes(item.id))
  926. .forEach((item) => {
  927. checkFormOptions.value.push({
  928. id: item.id,
  929. nickName: item.nickname,
  930. employeeNo: item.employeeNo
  931. })
  932. })
  933. queryParams[fieldKey.value] = [
  934. ...new Set([...queryParams[fieldKey.value], ...selectRows.map((row) => row.id)])
  935. ]
  936. customUserDialogVisible.value = false
  937. }
  938. // 打开用户选择框
  939. const handleOpenUserDialog = (options: any, key: string) => {
  940. checkFormOptions.value = options
  941. userQueryData.nickName = ''
  942. fieldKey.value = key
  943. userQueryData.pageNo = 1
  944. userQueryData.pageSize = 10
  945. handleFetchUserList()
  946. }
  947. // 获取用户信息
  948. const handleFetchUserList = async () => {
  949. const queryParams: UserListQuery = {
  950. ...userQueryData
  951. }
  952. delete queryParams.total
  953. const result = await getUserList(queryParams)
  954. userTableList.value = result.list
  955. userQueryData.total = result.total
  956. customUserDialogVisible.value = true
  957. }
  958. const onPageSizeChange = (val) => {
  959. userQueryData.pageSize = val
  960. handleFetchUserList()
  961. }
  962. const onPageNoChange = (val) => {
  963. userQueryData.pageNo = val
  964. handleFetchUserList()
  965. }
  966. watch(() => route.path, async () => {
  967. if (route.path === '/gdjy/my-task/pipe') {
  968. await getList()
  969. }
  970. })
  971. /** 初始化 **/
  972. onMounted(() => {
  973. getList()
  974. emitter.on('refresh-my-task-pipe', ()=> {
  975. getList();
  976. })
  977. })
  978. onUnmounted(() => {
  979. emitter.off('refresh-my-task-pipe')
  980. })
  981. </script>
  982. <style lang="scss" scoped>
  983. .project-info {
  984. display: flex;
  985. flex-direction: column;
  986. align-items: center;
  987. }
  988. .project-no {
  989. width: 100%;
  990. text-align: center;
  991. margin-bottom: 2px;
  992. }
  993. .project-name-tag {
  994. max-width: 100%;
  995. display: inline-flex;
  996. .project-name-text {
  997. display: inline-block;
  998. overflow: hidden;
  999. text-overflow: ellipsis;
  1000. white-space: nowrap;
  1001. max-width: 180px;
  1002. }
  1003. }
  1004. </style>