myTask.vue 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  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. <template #append>
  522. <el-button @click="handleFetchUserList">
  523. <Icon icon="ep:search" />
  524. </el-button>
  525. </template>
  526. </el-input>
  527. <SmartTable
  528. ref="userTableRef"
  529. v-model:pageNo="userQueryData.pageNo"
  530. v-model:pagesize="userQueryData.pageSize"
  531. :total="userQueryData.total"
  532. v-model:columns="userColumns"
  533. :data="userTableList"
  534. :buttons="[]"
  535. :showSettingTools="false"
  536. :showSearch="false"
  537. :showRefresh="false"
  538. @on-page-size-change="onPageSizeChange"
  539. @on-page-no-change="onPageNoChange"
  540. />
  541. </CustomDialog>
  542. <CustomDialog
  543. v-model="printProjectDialogVisible"
  544. :close-on-click-modal="true"
  545. >
  546. <el-table
  547. :data="printProjectList"
  548. style="width: 100%"
  549. @selection-change="handleSelectionChange"
  550. >
  551. <el-table-column
  552. type="selection"
  553. align="center"
  554. />
  555. <el-table-column
  556. label="序号"
  557. width="60"
  558. align="center"
  559. type="index"
  560. />
  561. <el-table-column
  562. label="项目"
  563. align="center"
  564. prop="reportName"
  565. />
  566. <el-table-column
  567. label="项目状态"
  568. align="center"
  569. prop="taskStatus"
  570. >
  571. <template #default="scope">
  572. <el-tag :type="getTypeColor(scope.row.taskStatus)">
  573. {{ PressureTaskOrderTaskStatusMap[scope.row.taskStatus] }}
  574. </el-tag>
  575. </template>
  576. </el-table-column>
  577. </el-table>
  578. <template #footer>
  579. <el-button type="success" @click="handlePrint">打印</el-button>
  580. <el-button type="danger" @click="handleDownload">下载</el-button>
  581. </template>
  582. </CustomDialog>
  583. </template>
  584. <script setup lang="ts">
  585. import {ref, reactive, onMounted, computed} from 'vue'
  586. import {formatArrayDate} from '@/utils/formatTime'
  587. //import SettingDialog from './components/SettingDialog.vue'
  588. import {PipeTaskOrderApi, PipeTaskOrderOrderItemVO} from '@/api/pressure2/pipetaskorder'
  589. import {
  590. PressureCheckerMyTaskStatus,
  591. PressureCheckerMyTaskStatusMap, PressurePipeCheckTypeMap,
  592. PressureTaskOrderTaskStatus, PressureTaskOrderTaskStatusMap
  593. } from '@/utils/constants'
  594. import {ElMessageBox, ElMessage} from 'element-plus'
  595. import {useRoute, useRouter} from 'vue-router'
  596. import {ArrowDown, ArrowUp, QuestionFilled} from "@element-plus/icons-vue";
  597. import { useUserStore } from '@/store/modules/user'
  598. import {useEmitt} from "@/hooks/web/useEmitt";
  599. import endCheckForm from './components/endCheckForm.vue'
  600. import SmartTable from "@/components/SmartTable/SmartTable";
  601. import { getUserList } from '@/api/common/user'
  602. import SettingDialog from "@/views/pressure/checker/components/SettingDialog.vue";
  603. import {PipeInputApi} from "@/api/pressure2/pipeInput";
  604. import 'https://printjs-4de6.kxcdn.com/print.min.js'
  605. import PipeReportList from "@/views/pressure2/pipeReportPreparationList/PipeReportList.vue";
  606. const { emitter } = useEmitt()
  607. const router = useRouter()
  608. const route = useRoute()
  609. const userStore = useUserStore()
  610. const loginUser = useUserStore().user;
  611. const getTypeColor = (status: string | number) => {
  612. const statusMap = {
  613. [PressureTaskOrderTaskStatus.WAIT_CONFIRM]: 'primary',
  614. [PressureTaskOrderTaskStatus.CANCELLED]: 'info',
  615. [PressureTaskOrderTaskStatus.AUDITING_EDIT]: 'warning',
  616. [PressureTaskOrderTaskStatus.AUDITING_CANCEL]: 'warning',
  617. [PressureTaskOrderTaskStatus.AUDITING_TIME]: 'warning',
  618. [PressureTaskOrderTaskStatus.CONFIRMED]: 'success',
  619. [PressureTaskOrderTaskStatus.RECORD_INPUT]: 'warning',
  620. [PressureTaskOrderTaskStatus.RECORD_CHECK]: 'warning',
  621. [PressureTaskOrderTaskStatus.REPORT_INPUT]: 'warning',
  622. [PressureTaskOrderTaskStatus.REPORT_AUDIT]: 'warning',
  623. [PressureTaskOrderTaskStatus.REPORT_APPROVE]: 'warning',
  624. [PressureTaskOrderTaskStatus.REPORT_END]: 'success'
  625. }
  626. return statusMap[status] || 'info'
  627. }
  628. const statusList = [
  629. { status: PressureCheckerMyTaskStatus.CONFIRMED, label: '待录入', color: '#5B9BD5' },
  630. { status: PressureCheckerMyTaskStatus.RECORD_INPUT, label: '记录录入', color: '#70AD47' },
  631. { status: PressureCheckerMyTaskStatus.RECORD_CHECK, label: '记录校核', color: '#9973C2' },
  632. { status: PressureCheckerMyTaskStatus.REPORT_INPUT, label: '报告编制', color: '#FFC000' },
  633. { status: PressureCheckerMyTaskStatus.REPORT_AUDIT, label: '报告审核', color: '#ED7D31' },
  634. { status: PressureCheckerMyTaskStatus.REPORT_APPROVE, label: '报告审批', color: '#FF8DC7' },
  635. { status: PressureCheckerMyTaskStatus.REPORT_END, label: '报告办结', color: '#303133' }
  636. ]
  637. /** 承压任务单 列表 */
  638. defineOptions({name: 'PipeMyTask'})
  639. const isSearchExpanded = ref(false)
  640. // 状态筛选
  641. const filterStatus = ref('all') // 默认选中全部
  642. const loading = ref(true)
  643. const list = ref<PipeTaskOrderOrderItemVO[]>([])
  644. const total = ref(0)
  645. const queryParams = reactive<Recordable>({
  646. pageNo: 1,
  647. pageSize: 10,
  648. unitCode: undefined,
  649. unitName: undefined,
  650. orderNo: undefined,
  651. checkType: undefined,
  652. checkDate: [],
  653. checkUserIds: [],
  654. mainCheckerIds: [],
  655. managerIds: [],
  656. isClaim: 'all',
  657. taskStatusList: undefined,
  658. remainingDays: undefined
  659. })
  660. const queryFormRef = ref()
  661. const formRef = ref()
  662. const endCheckFormRef = ref()
  663. const showSettingDialog = () => {
  664. formRef.value.open()
  665. }
  666. const MyTaskTableListRef = ref() // table的实例
  667. /** 查询列表 */
  668. const getList = async () => {
  669. loading.value = true
  670. try {
  671. const params: any = {...queryParams}
  672. const data = await PipeTaskOrderApi.getTaskOrderOrderItemPage(params)
  673. list.value = data.list
  674. total.value = data.total
  675. } catch (error) {
  676. console.error('获取我的任务列表失败:', error)
  677. ElMessage.error('获取我的任务列表失败')
  678. list.value = []
  679. total.value = 0
  680. } finally {
  681. loading.value = false
  682. }
  683. }
  684. /** 搜索按钮操作 */
  685. const handleQuery = () => {
  686. queryParams.pageNo = 1
  687. getList()
  688. }
  689. /** 重置按钮操作 */
  690. const resetQuery = () => {
  691. queryFormRef.value.resetFields()
  692. handleQuery()
  693. }
  694. // 判断是否可以检验录入:当前用户是检验员或主检人
  695. const canCheckInput = (row: PipeTaskOrderOrderItemVO) => {
  696. const userId = userStore.user.id
  697. // 检查是否是主检人
  698. if (row.mainCheckerUser && row.mainCheckerUser.id === userId) {
  699. return true
  700. }
  701. // 检查是否是检验员
  702. if (row.checkUsers && row.checkUsers.length > 0) {
  703. return row.checkUsers.some(user => user.id === userId)
  704. }
  705. return false
  706. }
  707. // 检验录入
  708. const handleCheckInput = (id: string,orderId: string) => {
  709. router.push({ name: 'PipeCheckerTaskDetail', query: { id, orderId:orderId, type: 'PipeMyTask' } })
  710. }
  711. // 添加结束检验时间
  712. const handleFinishCheck = (id: string,endCheckDate: any) => {
  713. endCheckFormRef.value.open(id,endCheckDate)
  714. }
  715. const printProjectDialogVisible = ref(false)
  716. const printProjectList = ref([])
  717. const selectionProject = ref([])
  718. const printProject = (reportDOList) => {
  719. printProjectDialogVisible.value = true
  720. printProjectList.value = reportDOList
  721. }
  722. const handleSelectionChange = (selection) => {
  723. // 根据表格的序号重新排序 selection
  724. const sortedSelection = selection.map(item => {
  725. // 在原始数据中查找该项的索引
  726. const index = printProjectList.value.findIndex(v => v.id === item.id)
  727. return {
  728. ...item,
  729. _index: index // 临时存储原始索引
  730. }
  731. })
  732. // 按照索引排序
  733. sortedSelection.sort((a, b) => a._index - b._index)
  734. // 移除临时索引字段
  735. selectionProject.value = sortedSelection.map(({ _index, ...rest }) => rest)
  736. }
  737. const handleDownload = async () => {
  738. // 判空检查
  739. if (!selectionProject.value || selectionProject.value.length === 0) {
  740. ElMessage.warning('请先选择要下载的项目')
  741. return
  742. }
  743. let data: any[] = []
  744. console.log(selectionProject)
  745. selectionProject.value.forEach(
  746. (item) => {
  747. data.push({
  748. taskStatus: item.taskStatus,
  749. resultTemplateId: item.resultTemplateId,
  750. templateId: item.templateId,
  751. reportTemplateId: item.reportTemplateId,
  752. reportUrl: item.reportUrl,
  753. id: item.id,
  754. })
  755. }
  756. )
  757. let loadingInstance = ElLoading.service({
  758. lock: true,
  759. text: '正在下载...',
  760. spinner: 'el-icon-loading',
  761. })
  762. try {
  763. // 调用 API 获取 ZIP blob
  764. const zipBlob = await PipeInputApi.handleDownload(data)
  765. if (zipBlob) {
  766. // 创建临时 URL
  767. const zipUrl = URL.createObjectURL(zipBlob)
  768. // 创建隐藏的 a 标签触发下载
  769. const link = document.createElement('a')
  770. link.href = zipUrl
  771. link.download = '管道检测录入报告.zip'
  772. document.body.appendChild(link)
  773. link.click()
  774. // 清理 DOM 和 URL
  775. document.body.removeChild(link)
  776. URL.revokeObjectURL(zipUrl)
  777. ElMessage.success('下载成功')
  778. } else {
  779. ElMessage.error('获取下载文件失败')
  780. }
  781. } catch (error) {
  782. console.error('下载失败:', error)
  783. ElMessage.error('下载失败')
  784. } finally {
  785. loadingInstance.close()
  786. }
  787. }
  788. const handlePrint = async () => {
  789. // 判空检查
  790. if (!selectionProject.value || selectionProject.value.length === 0) {
  791. ElMessage.warning('请先选择要打印的项目')
  792. return
  793. }
  794. let data: any[] = []
  795. selectionProject.value.forEach(
  796. (item) => {
  797. data.push({
  798. taskStatus: item.taskStatus,
  799. resultTemplateId: item.resultTemplateId,
  800. templateId: item.templateId,
  801. reportTemplateId: item.reportTemplateId,
  802. reportUrl: item.reportUrl,
  803. id: item.id,
  804. })
  805. }
  806. )
  807. let loadingInstance = ElLoading.service({
  808. lock: true,
  809. text: '正在打印...',
  810. spinner: 'el-icon-loading',
  811. })
  812. try {
  813. // 调用 API 获取 PDF blob
  814. const pdfBlob = await PipeInputApi.handlePrint(data)
  815. if (pdfBlob) {
  816. // 创建临时 URL
  817. const pdfUrl = URL.createObjectURL(pdfBlob)
  818. // 使用 printJS 打印
  819. printJS({
  820. printable: pdfUrl,
  821. type: 'pdf',
  822. showModal: false,
  823. onPrintDialogClose: () => {
  824. // 打印对话框关闭后释放 URL
  825. URL.revokeObjectURL(pdfUrl)
  826. }
  827. })
  828. } else {
  829. ElMessage.error('获取打印文件失败')
  830. }
  831. } catch (error) {
  832. console.error('打印失败:', error)
  833. ElMessage.error('打印失败')
  834. }finally {
  835. loadingInstance.close()
  836. }
  837. }
  838. /** 修改成功处理 */
  839. const handleScheduleSuccess = () => {
  840. //通知父组件刷新数据
  841. getList()
  842. }
  843. const handleRowDblclick = (row: Record<string, any>) => {
  844. if (row.isClaim === false) {
  845. return
  846. }
  847. router.push({ name: 'PipeCheckerTaskDetail', query: { id: row.id, type: 'PipeReportPreparationList' } })
  848. }
  849. const handleClaim = (id: string) => {
  850. ElMessageBox.confirm('是否确认认领?', '提示', {
  851. confirmButtonText: '确定',
  852. cancelButtonText: '取消',
  853. type: 'warning'
  854. })
  855. .then(() => {
  856. PipeTaskOrderApi.claim({id: id}).then(() => {
  857. ElMessage.success('认领成功')
  858. getList()
  859. })
  860. })
  861. .catch(() => {
  862. })
  863. }
  864. //取消认领
  865. const handleCancelClaim = (id: string) => {
  866. ElMessageBox.confirm('是否取消认领?', '提示', {
  867. confirmButtonText: '确定',
  868. cancelButtonText: '取消',
  869. type: 'warning'
  870. })
  871. .then(() => {
  872. PipeTaskOrderApi.cancelClaim({id: id}).then(() => {
  873. ElMessage.success('取消认领成功')
  874. getList()
  875. })
  876. })
  877. .catch(() => {
  878. })
  879. }
  880. /** 处理状态筛选 */
  881. const handleStatusFilter = () => {
  882. // 设置状态筛选
  883. queryParams.isClaim = filterStatus.value
  884. // 重置页码并触发查询
  885. queryParams.pageNo = 1
  886. getList()
  887. }
  888. // 存储展开状态的响应式数据
  889. const expandedRows = ref(new Set())
  890. // 判断行是否展开
  891. const isExpanded = (row) => {
  892. return expandedRows.value.has(row.id || JSON.stringify(row))
  893. }
  894. // 切换展开状态
  895. const toggleExpand = (row) => {
  896. const rowKey = row.id || JSON.stringify(row)
  897. if (expandedRows.value.has(rowKey)) {
  898. expandedRows.value.delete(rowKey)
  899. } else {
  900. expandedRows.value.add(rowKey)
  901. }
  902. }
  903. // 人员选择弹窗
  904. const userTableRef = ref()
  905. const userInfo = computed(() => userStore.user)
  906. const fieldKey = ref('')
  907. const customUserDialogVisible = ref(false)
  908. const checkFormOptions = ref<any[]>([])
  909. interface UserListQuery {
  910. nickName: string
  911. pageNo: number
  912. pageSize: number
  913. total?: number
  914. }
  915. const userQueryData = reactive<UserListQuery>({
  916. nickName: '',
  917. pageNo: 1,
  918. pageSize: 10,
  919. total: 0
  920. })
  921. const recheckStrIdsOpts = ref<any[]>([
  922. { id: userInfo.value.id, nickName: userInfo.value?.nickname }
  923. ])
  924. const userTableList = ref<any[]>([])
  925. const userColumns = ref<any[]>([
  926. {
  927. type: 'selection',
  928. width: '50px'
  929. },
  930. {
  931. label: '工号',
  932. prop: 'employeeNo'
  933. },
  934. {
  935. label: '姓名',
  936. prop: 'nickname'
  937. },
  938. {
  939. label: '部门',
  940. prop: 'deptName'
  941. }
  942. ])
  943. const handleUserConfirm = () => {
  944. const selectRows = userTableRef.value.getTableRef().getSelectionRows()
  945. // 过滤组合合成options
  946. const currOptions = checkFormOptions.value.map((item) => item.id) || []
  947. selectRows
  948. .filter((item) => !currOptions.includes(item.id))
  949. .forEach((item) => {
  950. checkFormOptions.value.push({
  951. id: item.id,
  952. nickName: item.nickname,
  953. employeeNo: item.employeeNo
  954. })
  955. })
  956. queryParams[fieldKey.value] = [
  957. ...new Set([...queryParams[fieldKey.value], ...selectRows.map((row) => row.id)])
  958. ]
  959. customUserDialogVisible.value = false
  960. }
  961. // 打开用户选择框
  962. const handleOpenUserDialog = (options: any, key: string) => {
  963. checkFormOptions.value = options
  964. userQueryData.nickName = ''
  965. fieldKey.value = key
  966. userQueryData.pageNo = 1
  967. userQueryData.pageSize = 10
  968. handleFetchUserList()
  969. }
  970. // 获取用户信息
  971. const handleFetchUserList = async () => {
  972. const queryParams: UserListQuery = {
  973. ...userQueryData
  974. }
  975. delete queryParams.total
  976. const result = await getUserList(queryParams)
  977. userTableList.value = result.list
  978. userQueryData.total = result.total
  979. customUserDialogVisible.value = true
  980. }
  981. const onPageSizeChange = (val) => {
  982. userQueryData.pageSize = val
  983. handleFetchUserList()
  984. }
  985. const onPageNoChange = (val) => {
  986. userQueryData.pageNo = val
  987. handleFetchUserList()
  988. }
  989. watch(() => route.path, async () => {
  990. if (route.path === '/gdjy/my-task/pipe') {
  991. await getList()
  992. }
  993. })
  994. /** 初始化 **/
  995. onMounted(() => {
  996. getList()
  997. emitter.on('refresh-my-task-pipe', ()=> {
  998. getList();
  999. })
  1000. })
  1001. onUnmounted(() => {
  1002. emitter.off('refresh-my-task-pipe')
  1003. })
  1004. </script>
  1005. <style lang="scss" scoped>
  1006. .project-info {
  1007. display: flex;
  1008. flex-direction: column;
  1009. align-items: center;
  1010. }
  1011. .project-no {
  1012. width: 100%;
  1013. text-align: center;
  1014. margin-bottom: 2px;
  1015. }
  1016. .project-name-tag {
  1017. max-width: 100%;
  1018. display: inline-flex;
  1019. .project-name-text {
  1020. display: inline-block;
  1021. overflow: hidden;
  1022. text-overflow: ellipsis;
  1023. white-space: nowrap;
  1024. max-width: 180px;
  1025. }
  1026. }
  1027. .status-help-content {
  1028. padding: 16px;
  1029. min-width: 180px;
  1030. }
  1031. .help-title {
  1032. font-size: 14px;
  1033. font-weight: 600;
  1034. color: #303133;
  1035. margin-bottom: 12px;
  1036. padding-bottom: 8px;
  1037. border-bottom: 2px solid #f0f0f0;
  1038. }
  1039. .status-list {
  1040. display: flex;
  1041. flex-direction: column;
  1042. gap: 10px;
  1043. }
  1044. .status-item {
  1045. display: flex;
  1046. align-items: center;
  1047. gap: 10px;
  1048. padding: 6px 8px;
  1049. border-radius: 6px;
  1050. transition: background-color 0.2s ease;
  1051. }
  1052. .status-item:hover {
  1053. background-color: #f5f7fa;
  1054. }
  1055. .color-dot {
  1056. width: 12px;
  1057. height: 12px;
  1058. border-radius: 50%;
  1059. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  1060. flex-shrink: 0;
  1061. }
  1062. .status-label {
  1063. font-size: 13px;
  1064. color: #606266;
  1065. white-space: nowrap;
  1066. }
  1067. .report-name-list {
  1068. position: relative;
  1069. .collapsed::after {
  1070. content: '';
  1071. position: absolute;
  1072. bottom: 0;
  1073. left: 0;
  1074. right: 0;
  1075. height: 15px;
  1076. background: linear-gradient(transparent, rgba(255, 255, 255, 0.9));
  1077. pointer-events: none;
  1078. }
  1079. }
  1080. </style>