TaskOrderDetailDialog.vue 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804
  1. <template>
  2. <!-- 主内容区域 -->
  3. <div :class="{ 'app-container': inPageMode }">
  4. <!-- 页面模式下的操作按钮 -->
  5. <div v-if="inPageMode" class="mb-4">
  6. <div class="flex justify-between items-center">
  7. <div v-if="taskOrderDetail">
  8. <el-button
  9. type="primary"
  10. @click="openModifyTimeDialog"
  11. :disabled="canNotModify"
  12. >修改检验时间</el-button
  13. >
  14. <el-button
  15. type="primary"
  16. @click="handleModifyTaskOrder"
  17. :disabled="canNotModify"
  18. >修改任务单</el-button
  19. >
  20. <el-button
  21. type="danger"
  22. @click="openVoidTaskDialog"
  23. :disabled="canNotModify"
  24. >作废任务单</el-button
  25. >
  26. <el-button
  27. type="success"
  28. @click="openCheckerSelectionDialog"
  29. :disabled="isTaskCancelled || isTaskCompleted"
  30. v-if="checkRole(['Boiler Director','admin'])"
  31. >修改检验人员</el-button
  32. >
  33. <!-- <el-button v-if="props.type !== 'checker'" type="success" @click="openCheckerSelectionDialog" :disabled="isTaskCancelled">修改检验人员</el-button>-->
  34. <el-button
  35. type="success"
  36. @click="handleModifyManager"
  37. :disabled="isTaskCancelled || isTaskCompleted"
  38. v-if="checkRole(['Boiler Director','admin'])"
  39. >修改项目负责人</el-button
  40. >
  41. <el-button
  42. type="primary"
  43. plain
  44. @click="handleAddSafetyRecord"
  45. :disabled="isTaskCancelled || isTaskCompleted"
  46. >添加安全记录检查</el-button
  47. >
  48. <el-button
  49. type="primary"
  50. plain
  51. @click="() => handleServiceOrder(100)"
  52. :disabled="isTaskCancelled"
  53. >服务单/受理单</el-button
  54. >
  55. <el-button
  56. type="primary"
  57. plain
  58. @click="() => handleInspectionStatusAddReport(1000)"
  59. :disabled="isTaskCancelled"
  60. >检验情况告知</el-button
  61. >
  62. <el-button type="danger" @click="handlePushSettlementSystem"
  63. :disabled="canPushSettlementSystem">推送结算系统</el-button>
  64. </div>
  65. </div>
  66. </div>
  67. <!-- 任务单详情、异常信息、审核、设备清单 -->
  68. <div v-if="!taskOrderDetail" class="loading-text">
  69. 无法加载任务详情。
  70. </div>
  71. <div v-else>
  72. <ContentWrap class="mb-4" title="任务单详情">
  73. <div class="tip custom-block">单位信息</div>
  74. <el-descriptions :column="3" border>
  75. <el-descriptions-item label="任务单号">
  76. {{ taskOrderDetail.orderNo }}
  77. </el-descriptions-item>
  78. <el-descriptions-item label="检验类别">
  79. {{ PressureBoilerCheckTypeMap[taskOrderDetail.checkType] || '-' }}
  80. </el-descriptions-item>
  81. <el-descriptions-item label="检验设备数量">
  82. {{ taskOrderDetail.equipNum || '-' }}
  83. </el-descriptions-item>
  84. <el-descriptions-item label="申请单位名称">
  85. {{ taskOrderDetail.unitName || '-' }}
  86. </el-descriptions-item>
  87. <el-descriptions-item label="使用单位名称">
  88. {{ taskOrderDetail.useUnitName || '-' }}
  89. </el-descriptions-item>
  90. <el-descriptions-item label="检验日期">
  91. {{ Array.isArray(taskOrderDetail.checkDate) ? formatArrayDate(taskOrderDetail.checkDate) : taskOrderDetail.checkDate || '-' }}
  92. </el-descriptions-item>
  93. <el-descriptions-item label="申请单位地址">
  94. {{ taskOrderDetail.unitAddress || '-' }}
  95. </el-descriptions-item>
  96. <el-descriptions-item label="使用单位地址">
  97. {{ taskOrderDetail.useUnitAddress || '-' }}
  98. </el-descriptions-item>
  99. <el-descriptions-item label="收费性质">
  100. {{ PressureFeeNatureMap[taskOrderDetail.feeNature] || '-' }}
  101. </el-descriptions-item>
  102. <el-descriptions-item label="收费形式">
  103. {{ PressureFeeTypeMap[taskOrderDetail.feeType] || '-' }}
  104. </el-descriptions-item>
  105. <el-descriptions-item label="总金额">
  106. {{ taskOrderDetail.payAmount || 0 }}
  107. </el-descriptions-item>
  108. <el-descriptions-item label="减免比例">
  109. {{ taskOrderDetail.reductionRadio ? Big(taskOrderDetail.reductionRadio).times(100).toString() : 0}}%
  110. </el-descriptions-item>
  111. <el-descriptions-item label="实际费用">
  112. {{ taskOrderDetail.actualAmount || 0 }}
  113. </el-descriptions-item>
  114. <el-descriptions-item label="应收法定金额">
  115. {{ taskOrderDetail.shouldAmount || 0 }}
  116. </el-descriptions-item>
  117. <el-descriptions-item label="服务收费金额">
  118. {{ taskOrderDetail.serviceAmount || 0 }}
  119. </el-descriptions-item>
  120. <el-descriptions-item label="免征费用">
  121. {{ taskOrderDetail.reduceFee || 0 }}
  122. </el-descriptions-item>
  123. <el-descriptions-item label="结算状态">
  124. {{ taskOrderDetail.paymentStatus === 1?'已结算':'未结算' }}
  125. </el-descriptions-item>
  126. <el-descriptions-item label="非税状态">
  127. {{ taskOrderDetail.isPay === 1?'已缴费':'未缴费' }}
  128. </el-descriptions-item>
  129. <el-descriptions-item label="业务受理人">
  130. <el-tag v-if="taskOrderDetail.acceptUser" effect="light" :closable="false">
  131. {{
  132. taskOrderDetail.acceptUser
  133. ? `${taskOrderDetail.acceptUser.nickname} (${taskOrderDetail.acceptUser.employeeNo})`
  134. : '-'
  135. }}
  136. </el-tag>
  137. <span v-else>-</span>
  138. </el-descriptions-item>
  139. <el-descriptions-item label="项目负责人">
  140. <div v-if="taskOrderDetail.manager">
  141. <el-tag type="primary">
  142. {{ taskOrderDetail.manager ? `${taskOrderDetail.manager.nickname} (${taskOrderDetail.manager.employeeNo})` : '-' }}
  143. </el-tag>
  144. </div>
  145. <span v-else>-</span>
  146. </el-descriptions-item>
  147. <el-descriptions-item label="检验人员">
  148. <div
  149. v-if="taskOrderDetail.teamItemList && taskOrderDetail.teamItemList.length > 0">
  150. <div
  151. v-for="(team, teamIndex) in taskOrderDetail.teamItemList"
  152. :key="team.groupTeamId || 'team-' + teamIndex"
  153. style="margin-bottom: 8px">
  154. <div
  155. v-if="taskOrderDetail.teamItemList.length > 1"
  156. style="font-weight: bold; margin-bottom: 4px">
  157. 团队 {{ teamIndex + 1 }}:
  158. </div>
  159. <div
  160. style="display: flex; flex-wrap: wrap; align-items: center; gap: 6px">
  161. <template
  162. v-for="(leader, leaderIdx) in team.leaders"
  163. :key="
  164. leader.id
  165. ? 'leader-' + leader.id
  166. : 'leader-idx-' + leaderIdx + '-' + teamIndex
  167. ">
  168. <el-tag
  169. effect="light"
  170. :closable="false">
  171. <span class="leader-tag">组</span>
  172. {{ leader.nickname }}
  173. </el-tag>
  174. </template>
  175. <template
  176. v-for="(member, memberIdx) in team.members"
  177. :key="
  178. member.id
  179. ? 'member-' + member.id
  180. : 'member-idx-' + memberIdx + '-' + teamIndex
  181. ">
  182. <el-tag effect="light" :closable="false"
  183. >{{ member.nickname
  184. }}({{ member.employeeNo }})</el-tag
  185. >
  186. </template>
  187. <span
  188. v-if="
  189. (!team.leaders || team.leaders.length === 0) &&
  190. (!team.members || team.members.length === 0)
  191. "
  192. style="margin-left: 4px"
  193. >-</span
  194. >
  195. </div>
  196. </div>
  197. </div>
  198. <span v-else>-</span>
  199. </el-descriptions-item>
  200. <el-descriptions-item label="计划编制人">
  201. <el-tag v-if="taskOrderDetail.scheduleUser" effect="light" :closable="false">
  202. {{
  203. taskOrderDetail.scheduleUser
  204. ? `${taskOrderDetail.scheduleUser.nickname} (${taskOrderDetail.scheduleUser.employeeNo})`
  205. : '-'
  206. }}
  207. </el-tag>
  208. <span v-else>-</span>
  209. </el-descriptions-item>
  210. <el-descriptions-item label="中止检验">
  211. {{ taskOrderDetail.XXX || '-' }}
  212. </el-descriptions-item>
  213. <el-descriptions-item label="安全检查记录">
  214. <el-button link type="primary" @click="handleLookSecurityCheck">{{
  215. taskOrderDetail.securityCheckCount
  216. }}</el-button>
  217. </el-descriptions-item>
  218. <el-descriptions-item label="备注" :span="2">
  219. {{ taskOrderDetail.remark || '-' }}
  220. </el-descriptions-item>
  221. </el-descriptions>
  222. <div class="tip custom-block">联系人信息</div>
  223. <el-descriptions :column="3" border>
  224. <el-descriptions-item label="约检联系人">
  225. {{ taskOrderDetail.unitContact || '-' }}
  226. </el-descriptions-item>
  227. <el-descriptions-item label="约检联系人电话">
  228. {{ taskOrderDetail.unitPhone || '-' }}
  229. </el-descriptions-item>
  230. <el-descriptions-item label="约检联系人邮箱">
  231. {{ taskOrderDetail.unitEmail || '-' }}
  232. </el-descriptions-item>
  233. <el-descriptions-item label="电子报告接收人">
  234. {{ taskOrderDetail.recipient || '-' }}
  235. </el-descriptions-item>
  236. <el-descriptions-item label="报告接收人电话">
  237. {{ taskOrderDetail.recipientPhone || '-' }}
  238. </el-descriptions-item>
  239. <el-descriptions-item label="接收人邮箱">
  240. {{ taskOrderDetail.recipientEmail || '-' }}
  241. </el-descriptions-item>
  242. <el-descriptions-item label="缴费联系人">
  243. {{ taskOrderDetail.payerContactName || '-' }}
  244. </el-descriptions-item>
  245. <el-descriptions-item label="缴费人电话">
  246. {{ taskOrderDetail.payerContact || '-' }}
  247. </el-descriptions-item>
  248. <el-descriptions-item label="缴费人邮箱">
  249. {{ taskOrderDetail.payerMail || '-' }}
  250. </el-descriptions-item>
  251. </el-descriptions>
  252. </ContentWrap>
  253. <ContentWrap v-if="exceptionInfo.id" title="异常信息">
  254. <el-form
  255. v-if="exceptionInfo.id"
  256. disabled
  257. :model="exceptionInfo"
  258. ref="formRef"
  259. label-width="130px"
  260. class="p-3">
  261. <el-row
  262. v-if="exceptionInfo.id"
  263. class="form-group"
  264. :gutter="24">
  265. <el-col :span="8">
  266. <el-form-item
  267. label="有效日期调整原因"
  268. prop="effectiveDateAdjustReason">
  269. <el-input
  270. v-model="exceptionInfo.effectiveDateAdjustReason"
  271. placeholder="请输入有效日期调整原因" />
  272. </el-form-item>
  273. </el-col>
  274. <el-col :span="8">
  275. <el-form-item
  276. label="受理建议"
  277. prop="acceptSuggeston">
  278. <el-input
  279. v-model="exceptionInfo.acceptSuggeston"
  280. placeholder="请输入受理建议" />
  281. </el-form-item>
  282. </el-col>
  283. <el-col :span="8">
  284. <el-form-item
  285. label="调整有效日期"
  286. prop="adjustEffectiveDate">
  287. <el-date-picker
  288. v-model="exceptionInfo.adjustEffectiveDate"
  289. type="date"
  290. value-format="YYYY-MM-DD"
  291. placeholder="请选择调整有效日期" />
  292. </el-form-item>
  293. </el-col>
  294. <el-col :span="12">
  295. <el-form-item label="情况说明" prop="descrition">
  296. <component
  297. :is="getExceptionItem('descrition', 'descritionAttach')" />
  298. </el-form-item>
  299. </el-col>
  300. <el-col :span="12">
  301. <el-form-item label="重启表" prop="restartTable">
  302. <component
  303. :is="getExceptionItem('restartTable', 'restartTableAttach')" />
  304. </el-form-item>
  305. </el-col>
  306. <el-col :span="12">
  307. <el-form-item label="指令书" prop="instrustionBook">
  308. <component
  309. :is="getExceptionItem('instrustionBook', 'instrustionBookAttach')" />
  310. </el-form-item>
  311. </el-col>
  312. <el-col :span="12">
  313. <el-form-item label="受理回执" prop="acceptReceipt">
  314. <component
  315. :is="getExceptionItem('acceptReceipt', 'acceptReceiptAttach')" />
  316. </el-form-item>
  317. </el-col>
  318. <el-col :span="12">
  319. <el-form-item label="其他" prop="other">
  320. <component
  321. :is="getExceptionItem('other', 'otherAttach')" />
  322. </el-form-item>
  323. </el-col>
  324. <el-col :span="12">
  325. <el-form-item
  326. label="提前检验申请函"
  327. prop="earlyCheckApply">
  328. <component
  329. :is="getExceptionItem('earlyCheckApply', 'earlyCheckApplyAttach')" />
  330. </el-form-item>
  331. </el-col>
  332. </el-row>
  333. </el-form>
  334. </ContentWrap>
  335. <ContentWrap
  336. title="审核"
  337. v-if="supportingDocsAuditDataList.length > 0 && inPageMode">
  338. <SmartTable
  339. v-model:columns="supportingDocsAuditColumns"
  340. :data="supportingDocsAuditDataList"
  341. v-model:page-no="operationReportPageNo"
  342. v-model:page-size="operationReportPageSize"
  343. :total="operationReportTotal"
  344. @on-page-no-change="() => handleGetOperationReportAuditList()"
  345. @on-page-size-change="() => handleGetOperationReportAuditList()"
  346. @refresh="() => handleGetOperationReportAuditList()" />
  347. </ContentWrap>
  348. <ContentWrap title="设备清单">
  349. <div style="margin: 10px 0">
  350. <el-button
  351. type="primary"
  352. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || isTaskCancelled"
  353. @click="() => handleAddCheckerItems()"
  354. >批量添加检验项目</el-button
  355. >
  356. <el-button
  357. type="primary"
  358. :disabled="selectedEquips.length !== 1 || isTaskCancelled"
  359. @click="() => handleMainquestionAddReport(PressureReportType['MAINQUESTION'], 'add')"
  360. >添加重大问题线索</el-button
  361. >
  362. <el-button
  363. type="primary"
  364. :disabled="selectedEquips.length !== 1 || isTaskCancelled"
  365. @click="handleAddInspectionplanReport">
  366. {{'添加检验方案'}}
  367. </el-button>
  368. <el-button
  369. type="primary"
  370. @click="handleBatchConcat"
  371. :disabled="selectedEquips.length === 0 || isTaskCancelled"
  372. >批量修改约检联系人</el-button
  373. >
  374. <el-button type="danger" @click="handleAbortTask"
  375. :disabled="isTaskCompleted || selectedEquips.length === 0 || taskOrder?.taskStatus === PressureTaskOrderTaskStatus['AUDITING_CANCEL']">移除设备
  376. </el-button>
  377. </div>
  378. <el-table
  379. :data="taskOrderDetail.orderItems"
  380. ref="orderItemsTableRef"
  381. @selection-change="handleEquipSelectionChange"
  382. border
  383. stripe
  384. empty-text="暂无设备信息">
  385. <el-table-column fixed="left" type="selection" width="40" />
  386. <el-table-column
  387. label="操作"
  388. fixed="left"
  389. align="center"
  390. width="200px">
  391. <template #default="scope">
  392. <div class="operation-buttons">
  393. <el-button v-if="canAddWorkInstruction()" type="primary" link size="small" @click="() => handleAddReport(PressureReportType['WORKINSTRUCTION'], scope.row)" :disabled="isTaskCancelled">添加作业指导书</el-button>
  394. <el-button v-if="showViewMainquestionBtn(scope.row)" type="primary" @click="handleViewMainquestionReport(scope.row)" link size="small">查看重大问题线索告知表</el-button>
  395. <el-button
  396. v-if="scope.row.mainCheckerUser?.id !== taskOrderDetail.manager?.id"
  397. link
  398. type="primary"
  399. size="small"
  400. :disabled="isTaskCancelled"
  401. @click="handleSetMainChecker(scope.row)"
  402. >修改主检人</el-button
  403. >
  404. <!-- <el-button-->
  405. <!-- v-if="scope.row.taskStatus === PressureCheckerMyTaskStatus.REPORT_END"-->
  406. <!-- link-->
  407. <!-- type="primary"-->
  408. <!-- size="small"-->
  409. <!-- :disabled="isTaskCancelled"-->
  410. <!-- @click="handleEntityReport(scope.row)"-->
  411. <!-- >添加作业指导书实体报告</el-button-->
  412. <!-- >-->
  413. </div>
  414. </template>
  415. </el-table-column>
  416. <el-table-column
  417. prop="equipDistrictName"
  418. align="center"
  419. label="区域"
  420. width="120px">
  421. <template #default="scope">
  422. <div>{{ scope.row.equipDistrictName }}</div>
  423. <div class="text-gray-400 text-sm">
  424. {{ scope.row.equipStreetName }}
  425. </div>
  426. </template>
  427. </el-table-column>
  428. <el-table-column
  429. prop="checkType"
  430. label="检验性质"
  431. width="150px"
  432. align="center">
  433. <template #default>
  434. {{ PressureBoilerCheckTypeMap[taskOrderDetail.checkType] || '-' }}
  435. </template>
  436. </el-table-column>
  437. <el-table-column
  438. prop="reportRespVOList"
  439. label="检验项目"
  440. width="150px"
  441. align="center">
  442. <template #default="{ row }">
  443. <template
  444. v-if="getRowReportVOList(row).length <= 2">
  445. <el-row
  446. v-for="item in getRowReportVOList(row)"
  447. :key="item?.templateId">
  448. <el-button
  449. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem(row.taskStatus) || isTaskCancelled"
  450. link
  451. type="primary"
  452. class="!whitespace-normal"
  453. @click="() => handleAddCheckerItems(row)"
  454. >{{ item?.reportName }}</el-button
  455. >
  456. <el-button
  457. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END']"
  458. link
  459. type="primary"
  460. @click.stop.prevent="() => handleInputCalcField(row.equipId, item)"
  461. >(费用:{{ getCheckItemFeeType(item)
  462. }})</el-button
  463. >
  464. </el-row>
  465. </template>
  466. <!-- 弹窗 -->
  467. <el-popover
  468. v-else
  469. placement="top-start"
  470. :width="200"
  471. trigger="hover">
  472. <!-- 弹窗内容 -->
  473. <el-scrollbar max-height="400px">
  474. <el-row
  475. v-for="item in getRowReportVOList(row)"
  476. :key="item?.templateId">
  477. <el-button
  478. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END'] || canAddReportItem(row.taskStatus)"
  479. link
  480. type="primary"
  481. class="!whitespace-normal"
  482. @click="() => handleAddCheckerItems(row)"
  483. >{{ item?.reportName }}</el-button
  484. >
  485. <el-button
  486. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END']"
  487. link
  488. type="primary"
  489. @click.stop.prevent="() => handleInputCalcField(row.equipId, item)"
  490. >(费用:{{ getCheckItemFeeType(item)
  491. }})</el-button
  492. >
  493. </el-row>
  494. </el-scrollbar>
  495. <template #reference>
  496. <div>
  497. <el-row
  498. v-for="item in getRowReportVOList(row).slice(0, 2)"
  499. :key="item?.templateId">
  500. <el-button
  501. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END']"
  502. link
  503. class="!whitespace-normal"
  504. type="primary"
  505. @click="() => handleAddCheckerItems(row)"
  506. >{{ item?.reportName }}</el-button
  507. >
  508. <el-button
  509. :disabled="taskOrder?.taskStatus === PressureTaskOrderTaskStatus['REPORT_END']"
  510. link
  511. type="primary"
  512. @click.stop.prevent="() => handleInputCalcField(row.equipId, item)"
  513. >(费用:{{ getCheckItemFeeType(item)
  514. }})</el-button
  515. >
  516. </el-row>
  517. </div>
  518. </template>
  519. </el-popover>
  520. </template>
  521. </el-table-column>
  522. <el-table-column
  523. prop="reportRespVOList"
  524. label="操作指导书"
  525. width="120px"
  526. align="center">
  527. <template #default="{row}">
  528. <template
  529. v-if="filterReportType(row.reportRespVOList).length">
  530. <div
  531. class="w-full"
  532. v-for="(item,index) in filterReportType(row.reportRespVOList)"
  533. :key="index">
  534. {{ item?.reportName }}
  535. </div>
  536. </template>
  537. <span v-else>-</span>
  538. </template>
  539. </el-table-column>
  540. <el-table-column
  541. prop="fee"
  542. label="收费金额"
  543. width="120px"
  544. align="center" />
  545. <el-table-column
  546. prop="taskStatus"
  547. label="主报告状态"
  548. width="150px"
  549. align="center">
  550. <template #default="scope">
  551. <el-tag :type="getTypeColor(scope.row.taskStatus)">
  552. {{ PressureTaskOrderTaskStatusMap[scope.row.taskStatus] || '-' }}
  553. </el-tag>
  554. </template>
  555. </el-table-column>
  556. <el-table-column
  557. prop="equipCode"
  558. label="设备注册代码"
  559. width="200px"
  560. align="center">
  561. <template #default="scope">
  562. <el-tag
  563. type="primary"
  564. size="small"
  565. class="ml-1"
  566. >{{ scope.row.equipCode }}</el-tag
  567. >
  568. </template>
  569. </el-table-column>
  570. <el-table-column
  571. prop="useCode"
  572. label="使用证编号"
  573. width="150px"
  574. align="center" />
  575. <el-table-column
  576. prop="maxContinueEvapor"
  577. label="蒸发量"
  578. min-width="200px"
  579. align="center" />
  580. <!-- <el-table-column-->
  581. <!-- prop="tonnage"-->
  582. <!-- label="吨位"-->
  583. <!-- width="80px"-->
  584. <!-- align="center" />-->
  585. <el-table-column
  586. prop="boilerModel"
  587. label="型号"
  588. width="150px"
  589. align="center" />
  590. <el-table-column
  591. label="下次内部检验"
  592. width="120px"
  593. align="center">
  594. <template #default="scope">
  595. {{ scope.row.nextInCheckDate ? dayjs(scope.row.nextInCheckDate).format('YYYY-MM-DD') : '-' }}
  596. </template>
  597. </el-table-column>
  598. <el-table-column
  599. label="下次外部检验"
  600. width="120px"
  601. align="center">
  602. <template #default="scope">
  603. {{ scope.row.nextOutCheckDate ? dayjs(scope.row.nextOutCheckDate).format('YYYY-MM-DD') : '-' }}
  604. </template>
  605. </el-table-column>
  606. <el-table-column
  607. label="下次耐压检验"
  608. width="120px"
  609. align="center">
  610. <template #default="scope">
  611. {{ scope.row.nextPressureCheckDate ? dayjs(scope.row.nextPressureCheckDate).format('YYYY-MM-DD') : '-' }}
  612. </template>
  613. </el-table-column>
  614. <el-table-column
  615. label="约检联系人"
  616. width="160px"
  617. align="center">
  618. <template #default="scope">
  619. <div>{{ scope.row.contact || '-' }}</div>
  620. </template>
  621. </el-table-column>
  622. <el-table-column
  623. label="约检联系人电话"
  624. width="160px"
  625. align="center">
  626. <template #default="scope">
  627. <div>{{ scope.row.contactPhone || '-' }}</div>
  628. </template>
  629. </el-table-column>
  630. </el-table>
  631. </ContentWrap>
  632. </div>
  633. <!-- 页面模式下的底部操作按钮 -->
  634. <div
  635. v-if="inPageMode && taskOrderDetail"
  636. class="flex justify-center mt-4">
  637. <!-- <el-button v-if="props.type !== 'checker'" type="success" @click="handlePrintCommitment" :disabled="isTaskCancelled">打印委托书</el-button>-->
  638. <!-- <el-button v-if="props.type !== 'checker'" type="success" @click="handlePrintEquipmentRecord" :disabled="isTaskCancelled">打印设备记录</el-button>-->
  639. <el-button
  640. type="primary"
  641. @click="handleConfirm"
  642. v-if="taskStatus === PressureTaskOrderTaskStatus.WAIT_CONFIRM"
  643. :disabled="isTaskCancelled"
  644. >认领</el-button
  645. >
  646. <el-button
  647. type="primary"
  648. @click="handleCancelConfirm"
  649. v-if="taskStatus === PressureTaskOrderTaskStatus.CONFIRMED"
  650. :disabled="isTaskCancelled || isTaskCompleted"
  651. >取消认领</el-button
  652. >
  653. <el-button @click="handleClosePage">关闭</el-button>
  654. </div>
  655. </div>
  656. <!-- 内部弹窗:修改检验时间、作废任务单、检验员选择 (仅在页面模式且有权限时出现) -->
  657. <template v-if="inPageMode && taskOrderDetail">
  658. <!-- 修改检验时间对话框 -->
  659. <el-dialog
  660. v-model="modifyTimeDialogVisible"
  661. title="修改检验时间"
  662. width="500px"
  663. draggable
  664. :close-on-click-modal="false"
  665. append-to-body>
  666. <el-form
  667. ref="modifyTimeFormRef"
  668. :model="modifyTimeForm"
  669. label-width="100px">
  670. <el-form-item label="检验日期" prop="newInspectionDate" required>
  671. <el-date-picker
  672. v-model="modifyTimeForm.newInspectionDate"
  673. type="date"
  674. placeholder="选择日期"
  675. value-format="YYYY-MM-DD"
  676. class="!w-full" />
  677. </el-form-item>
  678. <el-form-item label="修改原因" prop="reason" required>
  679. <el-input
  680. v-model="modifyTimeForm.reason"
  681. type="textarea"
  682. :rows="3"
  683. placeholder="请输入修改原因" />
  684. </el-form-item>
  685. </el-form>
  686. <template #footer>
  687. <el-button @click="modifyTimeDialogVisible = false"
  688. >取消</el-button
  689. >
  690. <el-button type="primary" @click="handleSubmitModifyTime"
  691. >确定</el-button
  692. >
  693. </template>
  694. </el-dialog>
  695. <!-- 作废任务单对话框 -->
  696. <el-dialog
  697. v-model="voidTaskDialogVisible"
  698. title="作废任务单"
  699. width="500px"
  700. draggable
  701. :close-on-click-modal="false"
  702. append-to-body>
  703. <el-form
  704. ref="voidTaskFormRef"
  705. :model="voidTaskForm"
  706. :rules="{
  707. reason: [
  708. { required: true, message: '请输入作废原因', trigger: 'blur' },
  709. ],
  710. }"
  711. label-width="100px">
  712. <el-form-item label="作废原因" prop="reason">
  713. <el-input
  714. v-model="voidTaskForm.reason"
  715. type="textarea"
  716. :rows="3"
  717. placeholder="请输入作废原因" />
  718. </el-form-item>
  719. </el-form>
  720. <template #footer>
  721. <el-button @click="voidTaskDialogVisible = false"
  722. >取消</el-button
  723. >
  724. <el-button type="primary" @click="handleSubmitVoidTask"
  725. >确定</el-button
  726. >
  727. </template>
  728. </el-dialog>
  729. <!-- 检验员选择弹窗 -->
  730. <el-dialog
  731. v-model="checkerSelectVisible"
  732. title="选择检验员"
  733. append-to-body
  734. width="800px"
  735. draggable
  736. :close-on-click-modal="false">
  737. <CheckerSelect
  738. ref="checkerSelectRef"
  739. v-model="tempSelectedCheckersInDialog"
  740. :dept-id="taskOrderDetail?.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'"
  741. :disabled="false"
  742. :has-data="true"
  743. empty-text="暂无检验员数据"
  744. :multiple="true"
  745. @change="handleCheckerSelectionChangeInDialog"
  746. />
  747. <template #footer>
  748. <div class="flex justify-end">
  749. <el-button @click="checkerSelectVisible = false"
  750. >取消</el-button
  751. >
  752. <el-button
  753. type="primary"
  754. @click="confirmCheckerSelectionAndSubmit"
  755. >确定</el-button
  756. >
  757. </div>
  758. </template>
  759. </el-dialog>
  760. <UserSelectForm
  761. ref="userSelectFormRef"
  762. @confirm="handleManagerSelected"
  763. :single="true" />
  764. <!-- 出具报告对话框 -->
  765. <GenerateReportDialog
  766. v-model:visible="generateReportDialogVisible"
  767. :equip-id="currentReportEquip?.id || ''"
  768. :equip-name="currentReportEquip?.equipName"
  769. @success="handleGenerateReportSuccess" />
  770. <!-- 出具报告对话框(新版本) -->
  771. <IssueReportDialog
  772. v-model:visible="issueReportDialogVisible"
  773. :task-order-id="currentTaskOrderId"
  774. :report-type="currentReportType"
  775. :default-report-scope="200"
  776. :is-part-report="true"
  777. :default-selected-equipments="currentSelectedEquipment ? [currentSelectedEquipment] : []"
  778. @confirm="handleIssueReportConfirm" />
  779. <!-- 修改主检人对话框 -->
  780. <el-dialog
  781. v-model="mainCheckerDialogVisible"
  782. title="修改主检人"
  783. width="800px"
  784. draggable
  785. :close-on-click-modal="false"
  786. append-to-body>
  787. <div class="mb-4">
  788. <div class="text-sm text-gray-600 mb-2">
  789. 当前设备:{{ currentEquipmentRow?.equipCode }} -
  790. {{ currentEquipmentRow?.equipName }}
  791. </div>
  792. <div class="text-sm text-gray-600 mb-4">
  793. 请选择一个检验员作为主检人(单选)
  794. </div>
  795. </div>
  796. <CheckerSelect
  797. v-model="tempSelectedMainChecker"
  798. @change="handleMainCheckerSelectionChange"
  799. :max="1"/>
  800. <template #footer>
  801. <div class="flex justify-end">
  802. <el-button @click="mainCheckerDialogVisible = false"
  803. >取消</el-button
  804. >
  805. <el-button
  806. type="primary"
  807. @click="confirmMainCheckerSelection"
  808. >确定</el-button
  809. >
  810. </div>
  811. </template>
  812. </el-dialog>
  813. </template>
  814. <!-- 安全检查记录弹窗 -->
  815. <SavetyCheckRecordList
  816. v-if="savetyCheckRecordListVsible"
  817. v-model:visible="savetyCheckRecordListVsible"
  818. :checkId="savetyCheck.checkId"
  819. :orderId="savetyCheck.orderId"
  820. :editType="savetyCheck.editType"
  821. @success="handleUpdateSavetyCheckRecordList" />
  822. <CustomDialog
  823. v-if="showSavetyCheckRecordVersions"
  824. v-model="showSavetyCheckRecordVersions"
  825. title="安全检查记录列表"
  826. width="800px"
  827. :showFooter="false"
  828. :z-index="1001">
  829. <SmartTable
  830. ref="smartTableRef"
  831. v-model:pageNo="savetyRecordPageNo"
  832. v-model:pagesize="savetyRecordPageSize"
  833. v-model:total="savetyRecordTotal"
  834. v-model:columns="savetyRecordColumns"
  835. :useBorderLayout="false"
  836. :data="savetyRecordList"
  837. :buttons="[]"
  838. @on-page-no-change="() => fetchSafetyCheckRecordPage()"
  839. @on-page-size-change="() => fetchSafetyCheckRecordPage()"
  840. @refresh="() => fetchSafetyCheckRecordPage()" />
  841. </CustomDialog>
  842. <!-- 批量修改约检联系人 -->
  843. <batchEditForm ref="formRef" @success="handleScheduleSuccess" />
  844. <!-- 添加检验项目弹窗 -->
  845. <AddOrEditCheckItemForEquipment
  846. v-if="showAddCheckItemsDialog"
  847. v-model="showAddCheckItemsDialog"
  848. :orderInfo="taskOrder"
  849. :selectedIds="checkItemIds"
  850. :isBatch="isBatchAdd"
  851. :equipmentIds="selectedEquipmentIds"
  852. :orderItemIds="selectedOrderIds"
  853. :isShowItemPart="false"
  854. @refresh="() => emit('refresh')" />
  855. <!-- 添加检验方案 添加弹窗 -->
  856. <AddInspectionplan
  857. ref="addInspectionplanRef"
  858. @success="handleSuccessInspectionplan" />
  859. <!-- 添加检验方案详情 -->
  860. <AddInspectionplanDetail
  861. v-if="AddInspectionplanDetailVisible"
  862. v-model:visible="AddInspectionplanDetailVisible"
  863. :editInspectionplanParams="editInspectionplanParams"
  864. :inspectionplanDetail="inspectionplanDetail"
  865. :taskOrderDetail="taskOrderDetail"
  866. :isEdit="isEdit"
  867. @success="handleUpdateInspectionplanDetail"
  868. @refresh="handleRefreshInspectionplan"
  869. />
  870. <!-- 服务单/受理单 -->
  871. <OrderDialog
  872. v-if="orderReportVisible"
  873. v-model:visible="orderReportVisible"
  874. :orderId="props.taskOrder.id"
  875. type="boiler"
  876. />
  877. <ServiceRecordList
  878. v-if="serviceRecordListVisible"
  879. v-model:visible="serviceRecordListVisible"
  880. :serverForm="serviceOrderDialogFormData"
  881. :businessType="businessType"
  882. :orderItemId="mainOrderItemId"
  883. :reportId="mainReportId"
  884. :isAddMainquestion="isAddMainquestion"
  885. :taskOrderDetail="taskOrderDetail"
  886. @success="handleUpdateServiceRecordList"
  887. />
  888. <!-- 作业指导书 添加弹窗 -->
  889. <AddBookAndCheckScheme ref="addBookAndCheckSchemeRef" @success="handleSuccessReport" />
  890. <!-- 作业指导书 编辑弹窗 -->
  891. <EditWorkBookReport
  892. v-if="editWorkBookReportVisible"
  893. v-model:visible="editWorkBookReportVisible"
  894. :title="editOperationReportTypeTitle"
  895. :templateId="editOperationReportParams?.templateId"
  896. :reportId="editOperationReportParams?.reportId"
  897. :orderId="editOperationReportParams?.orderId"
  898. :dataJSON="editOperationReportParams?.prepareJson"
  899. :curReportTypeInfo="curReportTypeInfo"
  900. :isCustomFileUrl="false"
  901. :isEdit="isWorkBookEdit"
  902. @success="handleEditOperationReportList"
  903. />
  904. <calcCheckItemFee
  905. v-if="showCalcCheckItemFeeDialog"
  906. v-model="showCalcCheckItemFeeDialog"
  907. :equipmentId="calcEquipmentId"
  908. :templateInfo="calcTemplateInfo"
  909. @save="handleSaveCalcFee"
  910. />
  911. <Dialog title="客户拒检原因" v-model="dialogVisible" align-center>
  912. <el-form ref="abortFormRef" :model="formData" :rules="rules" label-width="100px" v-loading="formLoading">
  913. <el-form-item label="拒绝原因" prop="reasonDict">
  914. <el-select
  915. v-model="formData.reasonDict"
  916. placeholder="请选择拒绝原因"
  917. prop="reasonDict"
  918. @change=" () => { formData.reason = '' }"
  919. >
  920. <el-option
  921. v-for="dict in getStrDictOptions('refuseInspectedCategory')"
  922. :key="dict.value"
  923. :label="dict.label"
  924. :value="dict.value"
  925. />
  926. </el-select>
  927. </el-form-item>
  928. <el-form-item
  929. v-if="formData.reasonDict == '5'"
  930. label="其他"
  931. prop="reason"
  932. >
  933. <el-input
  934. v-model="formData.reason"
  935. placeholder="请输入其他原因"
  936. maxlength="150"
  937. show-word-limit
  938. :autosize="{ minRows: 5, maxRows: 20 }"
  939. type="textarea"
  940. />
  941. </el-form-item>
  942. </el-form>
  943. <template #footer>
  944. <el-button @click="submitForm" type="primary" :disabled="formLoading">上报市局</el-button>
  945. <el-button @click="submitFormNoReport" :disabled="formLoading" style="background-color: #F56C6C; border-color: #F56C6C; color: #ffffff;">无需上报</el-button>
  946. <el-button @click="dialogVisible = false">取 消</el-button>
  947. </template>
  948. </Dialog>
  949. </template>
  950. <script setup lang="tsx">
  951. import CustomDialog from '@/components/CustomDialog/index.vue'
  952. import SmartTable from '@/components/SmartTable/SmartTable'
  953. import calcCheckItemFee from './calcCheckItemFee.vue'
  954. import SavetyCheckRecordList from './SavetyCheckRecordList.vue'
  955. import AddOrEditCheckItemForEquipment from './AddOrEditCheckItemForEquipment.vue'
  956. import { ref, watch, defineProps, defineEmits, reactive, computed, nextTick } from 'vue'
  957. import { BoilerTaskOrderApi,BoilerTaskOrderItemVO } from '@/api/pressure2/boilertaskorder'
  958. import {
  959. PressureFeeTypeMap,
  960. PressureTaskOrderTaskStatus,
  961. PressureCheckerMyTaskStatus,
  962. PressureFeeNatureMap,
  963. PressureBoilerCheckTypeMap,
  964. PressureReportType,
  965. PressureReportTypeMap,
  966. PressureTaskOrderStatus,
  967. PressureTaskOrderStatusMap, PressureCheckerMyTaskStatusMap, PressureTaskOrderTaskStatusMap,
  968. PressureBoilerCheckType
  969. } from '@/utils/constants'
  970. import { formatArrayDate } from '@/utils/formatTime'
  971. import {
  972. ElMessage,
  973. FormInstance,
  974. ElMessageBox,
  975. dayjs,
  976. type ElForm,
  977. type ElTable,
  978. ElSelect, ElOption, type Action
  979. } from 'element-plus'
  980. import { useRouter, useRoute } from 'vue-router'
  981. import CheckerSelect, { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
  982. import UserSelectForm from '@/components/UserSelectForm/index.vue'
  983. import { useTagsViewStore } from '@/store/modules/tagsView'
  984. import GenerateReportDialog from './GenerateReportDialog.vue'
  985. import IssueReportDialog from './IssueReportDialog.vue'
  986. import VuePdfEmbed from 'vue-pdf-embed'
  987. import { Icon } from '@/components/Icon'
  988. import batchEditForm from '../../equipboilerscheduling/components/batchEditForm.vue'
  989. import {Message as message} from "@/layout/components/Message";
  990. import {buildFileUrl} from "@/utils";
  991. import FileUploadModal from '@/views/pressure2/boilertaskorder/components/ImportFile.vue'
  992. import {is} from "@/utils/is";
  993. import {BoilerAppointmentConfirmOrderApi} from "@/api/pressure2/appointmentconfirmorder";
  994. import { getPressureReportTemplateListNoLimit } from '@/api/pressure2/reportTemplate'
  995. import AddInspectionplan from "@/views/pressure2/boilertaskorder/components/AddInspectionplan.vue";
  996. import {useUserStore} from "@/store/modules/user";
  997. import AddInspectionplanDetail from "@/views/pressure2/boilertaskorder/components/AddInspectionplanDetail.vue";
  998. import ServiceRecordList from "@/views/pressure2/boilertaskorder/components/ServiceRecordList.vue";
  999. import AddBookAndCheckScheme from "@/views/pressure2/boilertaskorder/components/AddBookAndCheckScheme.vue";
  1000. import EditWorkBookReport from "@/views/pressure2/boilertaskorder/components/EditWorkBookReport.vue";
  1001. import {EquipBoilerApi} from "@/api/pressure2/equipboiler";
  1002. import {TaskOrderApi} from "@/api/pressure/taskorder";
  1003. import OrderDialog from "@/views/pressure2/boilertaskorder/components/OrderDialog.vue";
  1004. import {checkRole} from "@/utils/permission";
  1005. import {getStrDictOptions} from "@/utils/dict";
  1006. import Big from 'big.js';
  1007. const userStore = useUserStore()
  1008. const userInfo = computed(() => userStore.user)
  1009. const router = useRouter()
  1010. const route = useRoute()
  1011. const tagsViewStore = useTagsViewStore()
  1012. const orderReportVisible = ref(false)
  1013. const isWorkBookEdit = ref(false)
  1014. // 异常信息
  1015. const exceptionInfo = ref<Record<string, any>>({})
  1016. // 定义emit事件
  1017. const emit = defineEmits<{
  1018. refresh: []
  1019. }>()
  1020. const props = defineProps({
  1021. taskOrder: {
  1022. type: Object as () => Record<string, any>, // Assuming a generic object, replace with TaskOrderVO or a more specific interface if available
  1023. required: true
  1024. },
  1025. inPageMode: {
  1026. type: Boolean,
  1027. default: false
  1028. },
  1029. type: {
  1030. type: String,
  1031. default: 'taskorder'
  1032. }
  1033. })
  1034. const taskOrderDetail = ref<any>(null) // This will hold the reactive copy of props.taskOrder
  1035. const isTaskCancelled = computed(() => {
  1036. return taskOrderDetail.value?.taskStatus === PressureTaskOrderTaskStatus.CANCELLED;
  1037. });
  1038. const isTaskCompleted = computed(() => {
  1039. const completeStatus = [PressureTaskOrderTaskStatus.REPORT_CONFIRMATION, PressureTaskOrderTaskStatus.REPORT_END];
  1040. return completeStatus.includes(taskOrderDetail.value.taskStatus)
  1041. })
  1042. const canNotModify = computed(() => {
  1043. if (!taskOrderDetail.value) return true;
  1044. if (taskOrderDetail.value.taskStatus === PressureTaskOrderTaskStatus.CANCELLED) {
  1045. return true;
  1046. }
  1047. return taskOrderDetail.value.taskStatus !== PressureTaskOrderTaskStatus.WAIT_CONFIRM;
  1048. });
  1049. const taskStatus = computed(() => {
  1050. return taskOrderDetail.value.taskStatus;
  1051. });
  1052. const modifyTimeDialogVisible = ref(false)
  1053. const modifyTimeFormRef = ref<FormInstance>()
  1054. const modifyTimeForm = reactive({
  1055. newInspectionDate: undefined as string | undefined,
  1056. reason: ''
  1057. })
  1058. const voidTaskDialogVisible = ref(false)
  1059. const voidTaskFormRef = ref<FormInstance>()
  1060. const voidTaskForm = reactive({
  1061. reason: ''
  1062. })
  1063. const showDocPdfDialog = ref(false)
  1064. const checkRowReport = ref()
  1065. const showDesigner = ref(false)
  1066. const checkerSelectVisible = ref(false)
  1067. const currentSelectedCheckerIdsForDialog = ref<string[]>([])
  1068. const tempSelectedCheckersInDialog = ref<CheckerItem[]>([])
  1069. // 检验员组件引用
  1070. const checkerSelectRef = ref()
  1071. const userSelectFormRef = ref<InstanceType<typeof UserSelectForm> | null>(null)
  1072. // 修改主检人相关状态
  1073. const mainCheckerDialogVisible = ref(false)
  1074. const currentEquipmentRow = ref<any>(null)
  1075. const tempSelectedMainChecker = ref<string[]>([])
  1076. const tempSelectedMainCheckerInfo = ref<any[]>([])
  1077. // 出具报告对话框状态
  1078. const generateReportDialogVisible = ref(false)
  1079. const currentReportEquip = ref<any>(null)
  1080. // 出具报告对话框状态(新的IssueReportDialog)
  1081. const issueReportDialogVisible = ref(false)
  1082. const currentTaskOrderId = ref('')
  1083. const currentReportType = ref<100 | 200>(100)
  1084. const currentSelectedEquipment = ref<any>(null)
  1085. const orderItemsTableRef = ref<InstanceType<typeof ElTable>>()
  1086. /** 服务单/受理单 */
  1087. const serviceOrderDialogFormRef = ref<FormInstance>()
  1088. const serviceOrderDialogVisible = ref(false)
  1089. const serviceRecordListVisible = ref(false)
  1090. const businessType = ref<BusinessType>()
  1091. const submitting = ref(false)
  1092. const serviceOrderDialogFormData = ref<Record<string,any>>({
  1093. serviceFormReceiver: '',
  1094. serviceFormReceiverPhone: '',
  1095. confirmStatus: ''
  1096. })
  1097. const formRef = ref()
  1098. // 选中的设备
  1099. const selectedEquips = ref<BoilerTaskOrderItemVO[]>([])
  1100. watch(() => props.taskOrder, (newVal) => {
  1101. if (newVal) {
  1102. taskOrderDetail.value = JSON.parse(JSON.stringify(newVal)); // Use deep copy if modifications are made locally, otherwise direct assignment is fine
  1103. // 更新异常单信息
  1104. const orderExceptionRespVO = taskOrderDetail.value.orderExceptionRespVO
  1105. if(orderExceptionRespVO){
  1106. exceptionInfo.value = {
  1107. ...orderExceptionRespVO,
  1108. adjustEffectiveDate: orderExceptionRespVO.adjustEffectiveDate ? dayjs(orderExceptionRespVO.adjustEffectiveDate.join('-')).format('YYYY-MM-DD') : '',
  1109. }
  1110. }
  1111. } else {
  1112. taskOrderDetail.value = null;
  1113. }
  1114. }, { immediate: true, deep: true })
  1115. const openModifyTimeDialog = () => {
  1116. if (!taskOrderDetail.value) return;
  1117. const currentApptDate = taskOrderDetail.value?.checkDate;
  1118. if (currentApptDate) {
  1119. modifyTimeForm.newInspectionDate = Array.isArray(currentApptDate) ? formatArrayDate(currentApptDate) : currentApptDate
  1120. } else {
  1121. modifyTimeForm.newInspectionDate = undefined;
  1122. }
  1123. modifyTimeForm.reason = ''
  1124. if(modifyTimeFormRef.value) {
  1125. modifyTimeFormRef.value.clearValidate()
  1126. }
  1127. modifyTimeDialogVisible.value = true
  1128. }
  1129. const handleModifyTaskOrder = () => {
  1130. if (!taskOrderDetail.value?.id) {
  1131. ElMessage.error('任务单ID不存在,无法修改!');
  1132. return;
  1133. }
  1134. router.push({
  1135. name: 'BoilerTaskOrderDetail', // Ensure this route name is correct for editing
  1136. query: {
  1137. id: taskOrderDetail.value.id
  1138. }
  1139. })
  1140. }
  1141. const handleModifyManager = () => {
  1142. if (!userSelectFormRef.value) {
  1143. ElMessage.error('用户选择组件未加载!');
  1144. return;
  1145. }
  1146. if (!taskOrderDetail.value?.id) {
  1147. ElMessage.error('任务ID无效,无法修改项目负责人!');
  1148. return;
  1149. }
  1150. if (!taskOrderDetail.value?.managerId) {
  1151. ElMessage.error('请先认领再修改项目负责人!');
  1152. return;
  1153. }
  1154. userSelectFormRef.value.open(taskOrderDetail.value.id); // ID is now from taskOrderDetail
  1155. }
  1156. const handleManagerSelected = async (emittedId: string, selectedUsers: any[]) => {
  1157. //console.log(emittedId);
  1158. if (!taskOrderDetail.value?.id) {
  1159. ElMessage.error('任务ID不存在,无法修改项目负责人!');
  1160. return;
  1161. }
  1162. if (selectedUsers.length === 0) {
  1163. ElMessage.info('未选择新的项目负责人。');
  1164. return;
  1165. }
  1166. const newManager = selectedUsers[0];
  1167. try {
  1168. const payload = {
  1169. id: taskOrderDetail.value.id, // ID from taskOrderDetail
  1170. managerId: newManager.id
  1171. };
  1172. await BoilerTaskOrderApi.updateTaskOrder(payload);
  1173. ElMessage.success('项目负责人更新成功!');
  1174. // 通知父组件刷新数据
  1175. emit('refresh');
  1176. } catch (error) {
  1177. console.error("Failed to update project manager:", error);
  1178. ElMessage.error('项目负责人更新失败!');
  1179. }
  1180. }
  1181. const openVoidTaskDialog = () => {
  1182. if (!taskOrderDetail.value) return;
  1183. voidTaskForm.reason = ''
  1184. if(voidTaskFormRef.value) {
  1185. voidTaskFormRef.value.clearValidate()
  1186. }
  1187. voidTaskDialogVisible.value = true
  1188. }
  1189. const openCheckerSelectionDialog = async () => {
  1190. if (!taskOrderDetail.value) {
  1191. ElMessage.warning('无法加载任务单信息');
  1192. return;
  1193. }
  1194. checkerSelectVisible.value = true;
  1195. // 先获取检验员列表
  1196. await nextTick()
  1197. const deptId = taskOrderDetail.value.deptId?.toString() || userStore.getUser.deptId?.toString() || '1'
  1198. await checkerSelectRef.value?.getCheckerList(deptId)
  1199. // 等待数据加载完成后,再从 teamItemList 中构建检验员列表
  1200. await nextTick()
  1201. // 从 teamItemList 中构建检验员列表
  1202. const checkers: CheckerItem[] = []
  1203. if (taskOrderDetail.value.teamItemList && taskOrderDetail.value.teamItemList.length > 0) {
  1204. taskOrderDetail.value.teamItemList.forEach(team => {
  1205. // 添加组长
  1206. if (team.leaders && team.leaders.length > 0) {
  1207. team.leaders.forEach(leader => {
  1208. checkers.push({
  1209. groupTeamId: team.groupTeamId,
  1210. memberId: leader.id,
  1211. leaderId: leader.id,
  1212. member: leader,
  1213. isLeader: true
  1214. })
  1215. })
  1216. }
  1217. // 添加组员
  1218. if (team.members && team.members.length > 0) {
  1219. team.members.forEach(member => {
  1220. checkers.push({
  1221. groupTeamId: team.groupTeamId,
  1222. memberId: member.id,
  1223. leaderId: team.leaders?.[0]?.id || '',
  1224. member: member,
  1225. isLeader: false
  1226. })
  1227. })
  1228. }
  1229. })
  1230. }
  1231. tempSelectedCheckersInDialog.value = checkers
  1232. // 等待赋值完成后,触发组件内部的状态更新
  1233. await nextTick()
  1234. // 手动触发组件内部的全选状态更新
  1235. checkerSelectRef.value?.processedDeptData?.forEach((dept: any) => {
  1236. dept.teamList?.forEach((team: any) => {
  1237. team.memberList?.forEach((subTeam: any) => {
  1238. const availableMembers = subTeam.memberList || []
  1239. const allSubTeamMembers = availableMembers.map((m: any) => subTeam.id + ':' + m.memberId)
  1240. if (allSubTeamMembers.length === 0) {
  1241. subTeam.checked = false
  1242. return
  1243. }
  1244. const selectedSubTeamMembers = checkers.filter((c: CheckerItem) =>
  1245. allSubTeamMembers.includes(c.groupTeamId + ':' + c.memberId)
  1246. )
  1247. subTeam.checked = selectedSubTeamMembers.length === allSubTeamMembers.length
  1248. })
  1249. })
  1250. })
  1251. }
  1252. /** 处理检验员变化 */
  1253. const handleCheckerSelectionChangeInDialog = (checkers: CheckerItem[]) => {
  1254. tempSelectedCheckersInDialog.value = checkers;
  1255. }
  1256. const confirmCheckerSelectionAndSubmit = async () => {
  1257. if (!taskOrderDetail.value?.id) {
  1258. ElMessage.error('任务ID不存在,无法修改检验员!');
  1259. return;
  1260. }
  1261. try {
  1262. const groupedByTeam: Record<string, { leaderId: string | null; userIds: string[] }> = {};
  1263. tempSelectedCheckersInDialog.value.forEach(checker => {
  1264. if (!checker.groupTeamId) {
  1265. console.warn('Checker missing groupTeamId:', checker);
  1266. return;
  1267. }
  1268. if (!groupedByTeam[checker.groupTeamId]) {
  1269. groupedByTeam[checker.groupTeamId] = { leaderId: null, userIds: [] };
  1270. }
  1271. if (checker.isLeader) {
  1272. groupedByTeam[checker.groupTeamId].leaderId = checker.memberId;
  1273. } else {
  1274. groupedByTeam[checker.groupTeamId].userIds.push(checker.memberId);
  1275. }
  1276. });
  1277. const teamList = Object.keys(groupedByTeam).map(groupTeamId => ({
  1278. groupTeamId: groupTeamId,
  1279. leaderId: groupedByTeam[groupTeamId].leaderId,
  1280. userIds: groupedByTeam[groupTeamId].userIds
  1281. }));
  1282. if (teamList.length < 1){
  1283. ElMessage.error('请选择检验员!');
  1284. return;
  1285. }
  1286. const data = {
  1287. id: taskOrderDetail.value.id, // ID from taskOrderDetail
  1288. teamList: teamList
  1289. };
  1290. await BoilerTaskOrderApi.updateCheckers(data);
  1291. ElMessage.success('检验人员更新成功!');
  1292. checkerSelectVisible.value = false;
  1293. // 通知父组件刷新数据
  1294. emit('refresh');
  1295. } catch (error) {
  1296. console.error("Failed to update checkers:", error);
  1297. ElMessage.error('检验人员更新失败!');
  1298. }
  1299. }
  1300. const handleSubmitModifyTime = async () => {
  1301. if (!modifyTimeFormRef.value) return
  1302. if (!taskOrderDetail.value?.id) {
  1303. ElMessage.error('任务ID不存在,无法修改检验时间!')
  1304. return
  1305. }
  1306. await modifyTimeFormRef.value.validate(async (valid) => {
  1307. if (valid) {
  1308. if (!taskOrderDetail.value) {
  1309. ElMessage.error('任务详情为空,无法修改!')
  1310. return
  1311. }
  1312. const taskOrderDetailCopy = JSON.parse(JSON.stringify(taskOrderDetail.value))
  1313. taskOrderDetailCopy.checkDate = modifyTimeForm.newInspectionDate
  1314. const data = {
  1315. id: taskOrderDetail.value.id, // ID from taskOrderDetail
  1316. objId: taskOrderDetail.value.id, // objId from taskOrderDetail
  1317. checkDate: modifyTimeForm.newInspectionDate,
  1318. reason: modifyTimeForm.reason,
  1319. changeType: 100,
  1320. afterJson: JSON.stringify(taskOrderDetailCopy)
  1321. }
  1322. try {
  1323. await BoilerTaskOrderApi.createTaskOrderOperationRecord(data)
  1324. ElMessage.success('修改检验时间请求已提交!')
  1325. modifyTimeDialogVisible.value = false
  1326. // 通知父组件刷新数据
  1327. emit('refresh');
  1328. } catch (error) {
  1329. ElMessage.error('提交修改检验时间失败!')
  1330. }
  1331. }
  1332. })
  1333. }
  1334. const handleSubmitVoidTask = async () => {
  1335. if (!voidTaskFormRef.value) return
  1336. if (!taskOrderDetail.value?.id) {
  1337. ElMessage.error('任务ID不存在,无法作废!')
  1338. return
  1339. }
  1340. await voidTaskFormRef.value.validate(async (valid) => {
  1341. if (valid) {
  1342. const data = {
  1343. id: taskOrderDetail.value.id, // ID from taskOrderDetail
  1344. objId: taskOrderDetail.value.id, // objId from taskOrderDetail
  1345. reason: voidTaskForm.reason,
  1346. changeType: 300
  1347. }
  1348. try {
  1349. await BoilerTaskOrderApi.createTaskOrderOperationRecord(data)
  1350. ElMessage.success('作废任务单请求已提交!')
  1351. voidTaskDialogVisible.value = false
  1352. // 通知父组件刷新数据
  1353. emit('refresh');
  1354. } catch (error) {
  1355. ElMessage.error('提交作废任务单失败!')
  1356. }
  1357. }
  1358. })
  1359. }
  1360. const handleSetMainChecker = (row: any) => {
  1361. if (!isCanAddFlag(row)){
  1362. return
  1363. }
  1364. currentEquipmentRow.value = row
  1365. // 如果当前有主检人,预选中该主检人
  1366. if (row.mainCheckerUserId) {
  1367. tempSelectedMainChecker.value = [row.mainCheckerUserId]
  1368. } else {
  1369. tempSelectedMainChecker.value = []
  1370. }
  1371. tempSelectedMainCheckerInfo.value = []
  1372. mainCheckerDialogVisible.value = true
  1373. }
  1374. /** 处理主检人选择变化 - 单选逻辑 */
  1375. const handleMainCheckerSelectionChange = (checkers: any[]) => {
  1376. // 实现单选逻辑:如果选择了新的检验员,只保留最后选择的一个
  1377. //console.log(checkers)
  1378. if (checkers.length > 1) {
  1379. // 获取新选择的检验员(最后一个)
  1380. const newSelected = checkers[checkers.length - 1]
  1381. tempSelectedMainChecker.value = [newSelected.groupTeamId + ':' + newSelected.memberId]
  1382. tempSelectedMainCheckerInfo.value = [newSelected]
  1383. } else if (checkers.length === 1) {
  1384. tempSelectedMainChecker.value = [checkers[0].groupTeamId + ':' + checkers[0].memberId]
  1385. tempSelectedMainCheckerInfo.value = [checkers[0]]
  1386. } else {
  1387. tempSelectedMainChecker.value = []
  1388. tempSelectedMainCheckerInfo.value = []
  1389. }
  1390. }
  1391. /** 确认修改主检人 */
  1392. const confirmMainCheckerSelection = async () => {
  1393. if (tempSelectedMainChecker.value.length === 0) {
  1394. ElMessage.warning('请选择一个主检人')
  1395. return
  1396. }
  1397. if (!currentEquipmentRow.value?.id) {
  1398. ElMessage.error('设备信息无效,无法修改主检人')
  1399. return
  1400. }
  1401. try {
  1402. // 调用修改主检人的API
  1403. const data = {
  1404. id: currentEquipmentRow.value.mainID,
  1405. mainCheckerId: tempSelectedMainChecker.value[0].split(':')[1]
  1406. }
  1407. await BoilerTaskOrderApi.updateTaskOrderMainChecker(data)
  1408. ElMessage.success('主检人修改成功')
  1409. mainCheckerDialogVisible.value = false
  1410. // 通知父组件刷新数据
  1411. emit('refresh');
  1412. } catch (error) {
  1413. console.error('修改主检人失败:', error)
  1414. ElMessage.error('修改主检人失败')
  1415. }
  1416. }
  1417. /** 实体报告 */
  1418. const handleEntityReport = (row: any) => {
  1419. currentTaskOrderId.value = taskOrderDetail.value?.id || ''
  1420. currentReportType.value = 100
  1421. currentSelectedEquipment.value = row
  1422. issueReportDialogVisible.value = true
  1423. }
  1424. /** 出具报告确认 */
  1425. const handleIssueReportConfirm = (data: any) => {
  1426. console.log('出具报告数据:', data)
  1427. // 刷新数据
  1428. emit('refresh')
  1429. }
  1430. /** 出具报告成功回调 */
  1431. const handleGenerateReportSuccess = () => {
  1432. // 刷新数据或其他处理
  1433. emit('refresh')
  1434. }
  1435. const handleConfirm = async () => {
  1436. //taskOrderDetail.value.id
  1437. try {
  1438. await ElMessageBox.confirm('是否认领该任务单?', '认领提示', {
  1439. confirmButtonText: '确定',
  1440. cancelButtonText: '取消',
  1441. type: 'warning'
  1442. })
  1443. await BoilerTaskOrderApi.confirmTaskOrder({ id:taskOrderDetail.value.id, "confirm": true })
  1444. ElMessage.success('认领成功')
  1445. if (props.inPageMode) {
  1446. tagsViewStore.closeSelectedTag(route)
  1447. }
  1448. } catch (error) {
  1449. if (error !== 'cancel') {
  1450. ElMessage.error('认领失败')
  1451. console.error('Confirm error:', error)
  1452. }
  1453. }
  1454. }
  1455. // 取消认领
  1456. const handleCancelConfirm = async () => {
  1457. try {
  1458. await ElMessageBox.confirm('是否取消认领该任务单?', '取消认领提示', {
  1459. confirmButtonText: '确定',
  1460. cancelButtonText: '取消',
  1461. type: 'warning'
  1462. })
  1463. await BoilerTaskOrderApi.confirmTaskOrder({ id:taskOrderDetail.value.id, "confirm": false })
  1464. ElMessage.success('取消认领成功')
  1465. if (props.inPageMode) {
  1466. tagsViewStore.closeSelectedTag(route)
  1467. }
  1468. } catch (error) {
  1469. if (error !== 'cancel') {
  1470. ElMessage.error('取消认领失败')
  1471. console.error('Cancel confirm error:', error)
  1472. }
  1473. }
  1474. }
  1475. const handleClosePage = () => {
  1476. if (props.inPageMode) {
  1477. tagsViewStore.closeSelectedTag(route)
  1478. }
  1479. }
  1480. /**
  1481. * 安全检查记录弹窗
  1482. * @param { visible } 显示状态
  1483. * ***/
  1484. const savetyCheckRecordListVsible = ref(false)
  1485. // 安全检查记录弹窗 携带参数
  1486. const savetyCheck = reactive({
  1487. checkId: '',
  1488. orderId: '',
  1489. editType: '',
  1490. })
  1491. const handleAddSafetyRecord = async () => {
  1492. const confirmed = await ElMessageBox.confirm('是否确定添加安全检查记录?', '添加安全检查记录提示', {
  1493. confirmButtonText: '确定',
  1494. cancelButtonText: '取消',
  1495. type: 'warning'
  1496. }).catch(() => false);
  1497. if (!confirmed) {
  1498. return;
  1499. }
  1500. savetyCheckRecordListVsible.value = true
  1501. savetyCheck.orderId = taskOrderDetail.value.id
  1502. savetyCheck.editType = 'edit'
  1503. }
  1504. watch(() => savetyCheckRecordListVsible.value, (savetyCheckRecordListVsible) => {
  1505. if(savetyCheckRecordListVsible) return
  1506. savetyCheck.checkId = ''
  1507. savetyCheck.orderId = ''
  1508. savetyCheck.editType = ''
  1509. })
  1510. // 安全检查记录列表弹窗
  1511. const showSavetyCheckRecordVersions = ref(false)
  1512. const savetyRecordList = ref([])
  1513. const savetyRecordPageSize = ref(10)
  1514. const savetyRecordPageNo = ref(1)
  1515. const savetyRecordTotal = ref(0)
  1516. const savetyRecordColumns = ref([
  1517. {
  1518. label: '名称',
  1519. prop: 'name',
  1520. },
  1521. {
  1522. label: '日期',
  1523. prop: 'date',
  1524. render: (row, value) => (value ? dayjs(value).format('YYYY-MM-DD') : '-')
  1525. },
  1526. {
  1527. label: '有效期至',
  1528. prop: 'validityDate',
  1529. render: (row, value) => (value ? dayjs(value).format('YYYY-MM-DD') : '-')
  1530. },
  1531. {
  1532. label: '检查结论',
  1533. prop: 'conclusion',
  1534. },
  1535. {
  1536. label: '操作',
  1537. prop: '',
  1538. render: (row) => {
  1539. return <div>
  1540. <el-button link type="primary" onClick={() => handleModifySavetyRecord(row,'view')}>查看</el-button>
  1541. <el-button link type="primary" onClick={() => handleModifySavetyRecord(row,'edit')}>修改</el-button>
  1542. <el-button link type="danger" onClick={() => handleDeleteSavetyRecord(row)}>删除</el-button>
  1543. </div>
  1544. }
  1545. }
  1546. ])
  1547. const fetchSafetyCheckRecordPage = async () => {
  1548. const result = await BoilerTaskOrderApi.getSafetyCheckRecordPage({
  1549. pageNo: savetyRecordPageNo.value,
  1550. pageSize: savetyRecordPageSize.value,
  1551. orderId: taskOrderDetail.value.id
  1552. })
  1553. if(result) {
  1554. savetyRecordList.value = result.list
  1555. savetyRecordTotal.value = result.total
  1556. taskOrderDetail.value.securityCheckCount = result.total
  1557. }
  1558. }
  1559. const handleModifySavetyRecord = (row,editType) => {
  1560. // 修改安全检查记录
  1561. savetyCheckRecordListVsible.value = true
  1562. savetyCheck.orderId = taskOrderDetail.value.id
  1563. savetyCheck.checkId = row.id
  1564. savetyCheck.editType = editType
  1565. }
  1566. const handleDeleteSavetyRecord = (row) => {
  1567. ElMessageBox.confirm(`确定要删除【${row.name}】吗?`, '提示', {
  1568. confirmButtonText: '确定',
  1569. cancelButtonText: '取消',
  1570. type: 'warning'
  1571. }).then(async () => {
  1572. // 恢复版本
  1573. // TODO: 这里发起删除请求 --- 缺少删除接口
  1574. const delRes = await BoilerTaskOrderApi.deleteSafetyCheckRecord({ id: row.id })
  1575. if(delRes) {
  1576. ElMessage.success('删除成功')
  1577. await fetchSafetyCheckRecordPage()
  1578. }
  1579. }).catch(() => {
  1580. // 取消恢复版本
  1581. })
  1582. }
  1583. const safetyCheckRecordPdfUrl = ref('')
  1584. const savetyCheckRecordPdfLoading = ref(false)
  1585. const handleSafetyCheckRecordPdfRendered = () => {
  1586. console.log('安全检查记录PDF渲染完成')
  1587. savetyCheckRecordPdfLoading.value = false
  1588. }
  1589. // 安全检查记录回调方法
  1590. const handleUpdateSavetyCheckRecordList = () => {
  1591. fetchSafetyCheckRecordPage()
  1592. }
  1593. /** 表格选择框变化 */
  1594. const handleEquipSelectionChange = (selection: BoilerTaskOrderItemVO[]) => {
  1595. // 实现设备选择逻辑
  1596. selectedEquips.value = selection
  1597. }
  1598. /** 处理批量修改约检联系人 */
  1599. const handleBatchConcat = () => {
  1600. if (selectedEquips.value.length === 0) {
  1601. ElMessage.warning('请至少选择一条记录')
  1602. return
  1603. }
  1604. if (!isCanAddFlag()){
  1605. return
  1606. }
  1607. formRef.value.open(selectedEquips.value, 'taskOrder')
  1608. }
  1609. /** 修改成功处理 */
  1610. const handleScheduleSuccess = () => {
  1611. selectedEquips.value = []
  1612. //通知父组件刷新数据
  1613. emit('refresh');
  1614. }
  1615. /***** 重大问题线索&检验方案&作业指导书 *****/
  1616. const supportingDocsAuditDataList = ref<Recordable[]>([])
  1617. const supportingDocsAuditColumns = ref([
  1618. {
  1619. label: '设备注册代码',
  1620. prop: 'equipCode',
  1621. },
  1622. {
  1623. label: '项目名称',
  1624. prop: 'reportName'
  1625. },
  1626. {
  1627. label: '类型',
  1628. prop: 'reportType',
  1629. render: (row, reportType) => {
  1630. return PressureReportTypeMap[reportType] || '-'
  1631. }
  1632. },
  1633. {
  1634. label: '状态',
  1635. prop: 'status',
  1636. render: (row, status) => {
  1637. // 如果 reportType=600 且 tbType=900,显示 -
  1638. if ((row.reportType === 600 && row.tbType === 900) || row.reportType === 500) {
  1639. return '-'
  1640. }
  1641. return !status ? '-' : PressureTaskOrderStatusMap[status]
  1642. }
  1643. },
  1644. {
  1645. label: '当前流程',
  1646. prop: 'currentNode',
  1647. render: (row) => {
  1648. // 如果 reportType=600 且 tbType=900,显示 -
  1649. if ((row.reportType === 600 && row.tbType === 900) || row.reportType === 500) {
  1650. return '-'
  1651. }
  1652. switch(row.status) {
  1653. case PressureTaskOrderStatus['CANCELLED']:
  1654. return '-'
  1655. case PressureTaskOrderStatus['APPROVED']:
  1656. return '审核通过'
  1657. case PressureTaskOrderStatus['AUDITING']:
  1658. return <div>
  1659. <p>当前流程:{row?.currentNode || '-'}</p>
  1660. <p>状态:审核中</p>
  1661. </div>
  1662. case PressureTaskOrderStatus['REJECTED']:
  1663. return <div>
  1664. <p>当前流程:已退回</p>
  1665. <p>状态:{`${row?.currentAuditor?.nickname}(${row?.currentAuditor?.employeeNo})拒绝`}</p>
  1666. </div>
  1667. default:
  1668. return '-'
  1669. }
  1670. }
  1671. },
  1672. {
  1673. label: '退回原因',
  1674. prop: 'returnReason',
  1675. render: (row, returnReason) => {
  1676. return returnReason || '-'
  1677. }
  1678. },
  1679. {
  1680. label: '提交人',
  1681. prop: 'submitUser',
  1682. render: (row, submitUser) => {
  1683. return submitUser?.nickname || '-'
  1684. }
  1685. },
  1686. {
  1687. label: '提交时间',
  1688. prop: 'submitTime',
  1689. render: (row, submitTime) => {
  1690. return !submitTime ? '-' : dayjs(submitTime).format('YYYY-MM-DD')
  1691. }
  1692. },
  1693. {
  1694. label: '操作',
  1695. prop: '',
  1696. render: (row) => {
  1697. switch(row.status) {
  1698. case PressureTaskOrderStatus['AUDITING']:
  1699. case PressureTaskOrderStatus['APPROVED']:
  1700. return <div>
  1701. <el-button link type="primary" onClick={() => newHandleOperationReport(row, 'view')}>查看详情</el-button>
  1702. {row.reportType === PressureReportType.MAINQUESTION && (
  1703. <el-button link type="primary" onClick={() => handleCancelDocs(row)}>作废</el-button>
  1704. )}
  1705. {row.reportType == PressureReportType.WORKINSTRUCTION && row.status == PressureTaskOrderStatus['AUDITING'] && <el-button link type="primary" onClick={() => recycleReportFn(row)}>
  1706. 回收
  1707. </el-button>}
  1708. </div>
  1709. // case PressureTaskOrderStatus['APPROVED']:
  1710. // return <el-button link type="primary" onClick={() => handleAssociateEquipment(row)}>关联设备</el-button>
  1711. case PressureTaskOrderStatus['REJECTED']:
  1712. return <div>
  1713. <el-button link type="primary" onClick={() => handleResubmitDocs(row)}>重新提交</el-button>
  1714. <el-button link type="primary" onClick={() => handleCancelDocs(row)}>作废</el-button>
  1715. </div>
  1716. case 0:
  1717. return <div>
  1718. <el-button link type="primary" onClick={() => handleCancelDocs(row)}>作废</el-button>
  1719. <el-button link type="primary" onClick={() => newHandleOperationReport(row, 'edit')}>编辑</el-button>
  1720. </div>
  1721. default:
  1722. return '-'
  1723. }
  1724. }
  1725. },
  1726. ])
  1727. /***** 异常信息 start *****/
  1728. const getExceptionItem = (field: string, fieldAttr: string)=>{
  1729. const fileUrl = exceptionInfo.value[fieldAttr] && buildFileUrl(exceptionInfo.value[fieldAttr])
  1730. const fileName = exceptionInfo.value[field]
  1731. if(fileUrl) {
  1732. return (
  1733. <>
  1734. <div class="flex items-center w-full p-l-10px p-r-10px hover:bg-gray-100 rounded-6px">
  1735. {/* <el-tooltip content={fileName}> */}
  1736. <span class="flex-1 text-ellipsis overflow-hidden whitespace-nowrap">{fileName}</span>
  1737. {/* </el-tooltip> */}
  1738. <div class="ml-10px">
  1739. <el-link href={fileUrl} underline={false} download target="_blank" type="primary">下载</el-link>
  1740. </div>
  1741. {/* <div class="ml-10px">
  1742. <el-button link type="danger" onClick={()=>handleRemove(field, fieldAttr)}>删除</el-button>
  1743. </div> */}
  1744. </div>
  1745. </>
  1746. )
  1747. } else {
  1748. return (
  1749. <el-button type="primary" onClick={()=>handleOpenFileUploadModal(field, fieldAttr)}>
  1750. <Icon icon="ep:upload-filled" />
  1751. <span>附件上传</span>
  1752. </el-button>
  1753. )
  1754. }
  1755. }
  1756. const handleGetExceptionInfo = (id: string) => {
  1757. BoilerAppointmentConfirmOrderApi.getExceptionInfo(id).then((res) => {
  1758. if(res) exceptionInfo.value = {
  1759. ...res,
  1760. adjustEffectiveDate: res.adjustEffectiveDate?.join('-')
  1761. }
  1762. }).catch((error)=>{
  1763. console.log(error, '-----error--->')
  1764. ElMessage.error(error)
  1765. })
  1766. }
  1767. const fileUploadModalRef = ref<InstanceType<typeof FileUploadModal>>();
  1768. const currentUploadMap = reactive({
  1769. field: '',
  1770. fieldAttr: '',
  1771. })
  1772. const handleOpenFileUploadModal = (type: string, attach: string) => {
  1773. currentUploadMap.field = type
  1774. currentUploadMap.fieldAttr = attach
  1775. fileUploadModalRef.value?.open()
  1776. }
  1777. const handleFileUploadSuccess = (fileInfo:{fileName: string, fileUrl: string}) => {
  1778. exceptionInfo.value[currentUploadMap.field] = fileInfo.fileName
  1779. exceptionInfo.value[currentUploadMap.fieldAttr] = fileInfo.fileUrl
  1780. console.log('handleFileUploadSuccess:', exceptionInfo.value)
  1781. }
  1782. /***** 异常信息 end *****/
  1783. // 获取服务单/受理单模板 1000-检验情况告知 400-重大问题线索
  1784. type BusinessType = 100 | 1000 | 400
  1785. const handleServiceOrder = (type: BusinessType) => {
  1786. console.log(type)
  1787. if (type == 100){
  1788. orderReportVisible.value = true
  1789. return
  1790. }
  1791. businessType.value = type
  1792. serviceRecordListVisible.value = true
  1793. // isAddMainquestion.value = 'edit'
  1794. // serviceOrderDialogVisible.value = true
  1795. // const currentBusinessType = getSignFilePath(type)
  1796. // serviceOrderDialogFormData.value.confirmStatus = currentBusinessType.isSignature || '0'
  1797. // downloadSignFilePdf.value = currentBusinessType.signFilePdf
  1798. }
  1799. // 获取审核列表
  1800. const operationReportPageNo = ref(1)
  1801. const operationReportPageSize = ref(10)
  1802. const operationReportTotal = ref(0)
  1803. const handleGetOperationReportAuditList = async () => {
  1804. const auditListResult = await BoilerTaskOrderApi.getMajorIssuesAuditList({
  1805. pageNo: operationReportPageNo.value,
  1806. pageSize: operationReportPageSize.value,
  1807. orderId: route.query.id,
  1808. notShowEndPlan: 1,
  1809. // notStatusList: 200,
  1810. })
  1811. supportingDocsAuditDataList.value = auditListResult.list.filter(item => {
  1812. // if([PressureReportType.INSPECTIONPLAN, PressureReportType.WORKINSTRUCTION].includes(item.reportType)){
  1813. // return item.status !== 200
  1814. // } else {
  1815. // return item
  1816. // }
  1817. return item
  1818. })
  1819. operationReportTotal.value = auditListResult.total
  1820. }
  1821. handleGetOperationReportAuditList()
  1822. // 添加重大问题线索 & 检验方案 & 作业指导书
  1823. // reportType:500重大问题线索通知 600 检验方案 700 作业指导书
  1824. const curMainquestionEquipmentRow = ref<Recordable>({})
  1825. const isAddMainquestion = ref<'add' | 'edit' | 'view'>('view')
  1826. const mainOrderItemId = ref('')
  1827. const mainReportId = ref('')
  1828. const editOperationReportVisible = ref(false)
  1829. const editOperationReportTypeTitle = ref('')
  1830. const editOperationReportParams = ref<Record<string, any>>({
  1831. templateId: '',
  1832. reportId: '',
  1833. orderId: '',
  1834. prepareJson: ''
  1835. })
  1836. /***** 添加检验项目 *****/
  1837. const isBatchAdd = ref(false)
  1838. const showAddCheckItemsDialog = ref(false)
  1839. const selectedEquipmentIds = ref<string[]>([])
  1840. const selectedOrderIds = ref<string[]>([])
  1841. const checkItemIds = ref<string[]>([])
  1842. const canAddReportItem = (taskStatus)=>{
  1843. const {REPORT_AUDIT, REPORT_APPROVE, REPORT_END} = PressureCheckerMyTaskStatus
  1844. return [REPORT_AUDIT, REPORT_APPROVE, REPORT_END].includes(taskStatus)
  1845. }
  1846. const isCanAddFlag = (row?:any) =>{
  1847. let selectedItems = [] as any[]
  1848. if(row) {
  1849. isBatchAdd.value = false
  1850. selectedItems.push(row)
  1851. selectedEquipmentIds.value = [row?.equipId]
  1852. selectedOrderIds.value = [row?.mainID]
  1853. checkItemIds.value = (row.reportRespVOList || []).map(item => item.templateId)
  1854. } else {
  1855. isBatchAdd.value = true
  1856. selectedItems = orderItemsTableRef.value?.getSelectionRows() || []
  1857. selectedEquipmentIds.value = selectedItems.map(item => item?.equipId)
  1858. selectedOrderIds.value = selectedItems.map(item => item?.mainID)
  1859. if(selectedItems.length >= 1) {
  1860. checkItemIds.value = (selectedItems[0].reportRespVOList || []).map(item => item.templateId)
  1861. }
  1862. }
  1863. if(selectedItems.length === 0) {
  1864. ElMessage.warning('请选择设备单!')
  1865. return false
  1866. }
  1867. // 校验选中行的状态是否存在 报告审核/审核/办结
  1868. let canAddFlag = true
  1869. selectedItems.forEach(row=>{
  1870. if(canAddReportItem(row.taskStatus)) {
  1871. ElMessage.warning(`设备:${row.equipCode}的主报告状态为${PressureCheckerMyTaskStatusMap[row.taskStatus]},不能进行调整!`)
  1872. canAddFlag = false
  1873. }
  1874. })
  1875. return canAddFlag
  1876. }
  1877. const handleAddCheckerItems = (row?: any) => {
  1878. if (!isCanAddFlag(row)){
  1879. return
  1880. }
  1881. // let selectedItems = [] as any[]
  1882. // if(row) {
  1883. // isBatchAdd.value = false
  1884. // selectedItems.push(row)
  1885. // selectedEquipmentIds.value = [row?.equipId]
  1886. // selectedOrderIds.value = [row?.mainID]
  1887. // checkItemIds.value = (row.reportRespVOList || []).map(item => item.templateId)
  1888. // } else {
  1889. // isBatchAdd.value = true
  1890. // selectedItems = orderItemsTableRef.value?.getSelectionRows() || []
  1891. // selectedEquipmentIds.value = selectedItems.map(item => item?.equipId)
  1892. // selectedOrderIds.value = selectedItems.map(item => item?.mainID)
  1893. // if(selectedItems.length >= 1) {
  1894. // checkItemIds.value = (selectedItems[0].reportRespVOList || []).map(item => item.templateId)
  1895. // }
  1896. // }
  1897. // if(selectedItems.length === 0) {
  1898. // ElMessage.warning('请选择设备单!')
  1899. // return
  1900. // }
  1901. // // 校验选中行的状态是否存在 报告审核/审核/办结
  1902. // let canAddFlag = true
  1903. // selectedItems.forEach(row=>{
  1904. // if(canAddReportItem(row.taskStatus)) {
  1905. // ElMessage.warning(`设备:${row.equipCode}的主报告状态为${PressureCheckerMyTaskStatusMap[row.taskStatus]},不能添加检验项目!`)
  1906. // canAddFlag = false
  1907. // }
  1908. // })
  1909. // if(!canAddFlag) return
  1910. showAddCheckItemsDialog.value = true
  1911. }
  1912. /***** 添加检验项目 end *****/
  1913. //判断主报告状态
  1914. const checkMainStatus = (row?: any) => {
  1915. // 校验选中行的状态是否存在 报告审核/审核/办结
  1916. let canAddFlag = true
  1917. selectedItems.forEach(row=>{
  1918. if(canAddReportItem(row.taskStatus)) {
  1919. ElMessage.warning(`设备:${row.equipCode}的主报告状态为${PressureCheckerMyTaskStatusMap[row.taskStatus]},不能添加检验项目!`)
  1920. canAddFlag = false
  1921. }
  1922. })
  1923. return canAddFlag;
  1924. }
  1925. const getRowReportVOList = (row)=>{
  1926. return (row.reportRespVOList || []).filter(item=>item.reportType !== PressureReportType['WORKINSTRUCTION'])
  1927. }
  1928. const filterReportType = (list: any[])=>{
  1929. return (list || []).filter(item=>item.reportType === PressureReportType['WORKINSTRUCTION'])
  1930. }
  1931. // 添加检验方案/查看检验方案按钮
  1932. const initEditOperationReportParams = JSON.parse(JSON.stringify(editOperationReportParams.value))
  1933. const addInspectionplanRef = ref<InstanceType<typeof AddInspectionplan>>()
  1934. const isEdit = ref<'add' | 'edit' | 'view'>('view')
  1935. const editInspectionplanParams = ref<Recordable>({
  1936. ...initEditOperationReportParams.value,
  1937. })
  1938. const AddInspectionplanDetailVisible = ref(false)
  1939. const inspectionplanDetail = ref({})
  1940. const handleUpdateInspectionplanDetail = (info) => {
  1941. console.log('handleUpdateInspectionplanDetail-info:', info )
  1942. editInspectionplanParams.value = {
  1943. ...editInspectionplanParams.value,
  1944. ...info
  1945. }
  1946. }
  1947. const handleRefreshInspectionplan= ()=>{
  1948. // 重新获取审核列表数据
  1949. operationReportPageNo.value = 1
  1950. handleGetOperationReportAuditList()
  1951. }
  1952. const handleAddInspectionplanReport = async () => {
  1953. try {
  1954. if (!isCanAddFlag()){
  1955. return
  1956. }
  1957. // 查询检验方案模板数据
  1958. // const options = ref<any[]>([])
  1959. // const params = { type: '6',reportType : 600 }
  1960. // const response = await getPressureReportTemplateListNoLimit({...params, pageNo: 1, pageSize: 100, status: 200})
  1961. // options.value = response?.data?.list || response?.list || response || []
  1962. //
  1963. // const equipType = taskOrderDetail.value.orderItems[0]?.typeName;
  1964. // const checkType = PressureBoilerCheckTypeMap[taskOrderDetail.value?.checkType] || '-'
  1965. //
  1966. // const newParams = {
  1967. // options: options.value.map(item => ({
  1968. // ...item,
  1969. // label: item.tbName,
  1970. // reportName: equipType + checkType + "-" + item.tbName,
  1971. // value: item.id
  1972. // })),
  1973. // formData: {
  1974. // orderId: taskOrderDetail.value.id,
  1975. // },
  1976. // equipCount: unref(selectedEquips).length
  1977. // }
  1978. const newParams = {
  1979. selectedEquips : selectedEquips.value,
  1980. taskOrderDetail : taskOrderDetail.value,
  1981. }
  1982. // 添加检验方案逻辑
  1983. addInspectionplanRef.value?.open(newParams, '检验方案类型')
  1984. } catch (error) {
  1985. // 处理接口错误
  1986. ElMessage({
  1987. type: 'error',
  1988. message: 'Failed to load options'
  1989. });
  1990. console.error('API error:', error);
  1991. }
  1992. }
  1993. const getCheckItemFeeType = computed(() => {
  1994. return ({isAutoAmount, fee}) => {
  1995. if(is(fee, 'Number')) return fee
  1996. else if(is(fee, 'Null') && isAutoAmount === '1') return '录入计算'
  1997. else return '无'
  1998. }
  1999. })
  2000. const newHandleOperationReport = async (row, type: 'add' | 'edit' | 'view' | '' = '') => {
  2001. if(row.reportType === PressureReportType.MAINQUESTION){
  2002. return handleMainquestionAddReport(row.reportType, type, row)
  2003. }
  2004. // 如果是检验方案走检验方案的逻辑
  2005. if(row.reportType === PressureReportType['INSPECTIONPLAN']) {
  2006. // 检验方案
  2007. editInspectionplanParams.value = {
  2008. ...editInspectionplanParams.value,
  2009. reportId: row.id,
  2010. templateId: row.templateId,
  2011. orderId: taskOrderDetail.value.id,
  2012. isSelfType: row.tbType === 500 && row.pjType === 5,
  2013. }
  2014. inspectionplanDetail.value = row
  2015. if(!row.status){
  2016. // const templateInitJSON = await getPressureReportTemplateMockJSON( {taskOrderNo: props.taskOrder.orderNo,
  2017. // templateId: row.templateId})
  2018. // editInspectionplanParams.value.prepareJson = templateInitJSON
  2019. }
  2020. isEdit.value = type ? type : !row.status ? 'add' : 'edit'
  2021. AddInspectionplanDetailVisible.value = true
  2022. return
  2023. }
  2024. //作业指导书 选择的是模板,则直接通过葡萄城进行查看预览
  2025. if(row.reportType === PressureReportType['WORKINSTRUCTION']) {
  2026. return handleWorkBookDetail(row,type !== 'view')
  2027. }
  2028. // 查看文件详情的pdf
  2029. showDocPdfDialog.value = true
  2030. checkRowReport.value = row
  2031. showDesigner.value = !!row.templateId
  2032. }
  2033. // 作业指导书查看详情/编辑
  2034. const handleWorkBookDetail = (row, isEdit = false)=>{
  2035. //isCustomFileUrl.value = !row.templateId
  2036. editOperationReportTypeTitle.value = PressureReportTypeMap[row.reportType]
  2037. editOperationReportParams.value = {
  2038. ...editOperationReportParams.value,
  2039. reportId: row.id,
  2040. templateId: row.templateId,
  2041. orderId: taskOrderDetail.value.id,
  2042. prepareJson: row.prepareJson
  2043. }
  2044. isWorkBookEdit.value = isEdit
  2045. editWorkBookReportVisible.value = true
  2046. }
  2047. /***** 费用计算 *****/
  2048. const calcEquipmentId = ref('')
  2049. const calcTemplateInfo = ref({})
  2050. const showCalcCheckItemFeeDialog = ref(false)
  2051. const handleInputCalcField = async (equipId, item) => {
  2052. try {
  2053. calcTemplateInfo.value = item
  2054. calcEquipmentId.value = equipId
  2055. showCalcCheckItemFeeDialog.value = true
  2056. } catch (error) {
  2057. ElMessage.error('录入费用出错啦!')
  2058. console.error('录入费用出错啦!', error)
  2059. }
  2060. }
  2061. const handleSaveCalcFee = async (templateInfo) => {
  2062. // 更新检验项目的费用
  2063. const updateRes = await BoilerTaskOrderApi.updateCheckItemFee({id: templateInfo.id, fee: templateInfo.fee, feeCalculateJson: templateInfo.feeCalculateJson })
  2064. if(updateRes) {
  2065. emit('refresh')
  2066. ElMessage.success('费用已更新')
  2067. }
  2068. }
  2069. /***** 费用计算 end *****/
  2070. /*
  2071. * 添加重大问题线索
  2072. * */
  2073. const handleMainquestionAddReport = async (reportType, type: 'add' | 'edit' | 'view', row?: Recordable) => {
  2074. if (!reportType) return ElMessage.error('未知的报告类型')
  2075. if (!row && unref(selectedEquips).length !== 1) return ElMessage.error('请选择一台设备')
  2076. if (type !== 'view' && !isCanAddFlag(row)){
  2077. return
  2078. }
  2079. isAddMainquestion.value = type
  2080. console.log('isAddMainquestion:log', isAddMainquestion.value)
  2081. mainReportId.value = row ? row.id : ''
  2082. mainOrderItemId.value = row ? row.orderItemId : unref(selectedEquips)[0].mainID
  2083. curMainquestionEquipmentRow.value = row ? {...row} : unref(selectedEquips)[0]
  2084. // 校验审核列表是否已经存在
  2085. const existingAudit = supportingDocsAuditDataList.value.find(item => item.reportType === reportType && item.orderItemId === curMainquestionEquipmentRow.value.mainID)
  2086. if (existingAudit) {
  2087. ElMessage.error('该设备已存在该类型的报告')
  2088. return
  2089. }
  2090. if (type == 'add'){
  2091. const confirmed = await ElMessageBox.confirm('是否确定添加重大问题线索?', '添加重大问题线索提示', {
  2092. confirmButtonText: '确定',
  2093. cancelButtonText: '取消',
  2094. type: 'warning'
  2095. }).catch(() => false);
  2096. if (!confirmed) {
  2097. return;
  2098. }
  2099. }
  2100. handleServiceOrder(400)
  2101. }
  2102. /*
  2103. * 添加检验情况告知单
  2104. * */
  2105. const handleInspectionStatusAddReport = async (reportType, type: 'add' | 'edit' | 'view') => {
  2106. if (!reportType) return ElMessage.error('未知的报告类型')
  2107. if (taskOrderDetail.value.notificationformReport != null){
  2108. isAddMainquestion.value = 'view'
  2109. mainReportId.value = taskOrderDetail.value.notificationformReport.id
  2110. }else{
  2111. isAddMainquestion.value = 'add'
  2112. }
  2113. // mainOrderItemId.value = row ? row.orderItemId : unref(selectedEquips)[0].mainID
  2114. // 校验审核列表是否已经存在
  2115. // const existingAudit = supportingDocsAuditDataList.value.find(item => item.reportType === reportType && item.orderItemId === curMainquestionEquipmentRow.value.mainID)
  2116. // if (existingAudit) {
  2117. // ElMessage.error('该设备已存在该类型的报告')
  2118. // return
  2119. // }
  2120. if (isAddMainquestion.value == 'add'){
  2121. const confirmed = await ElMessageBox.confirm('是否确定添加检验情况告知单?', '添加检验情况告知单提示', {
  2122. confirmButtonText: '确定',
  2123. cancelButtonText: '取消',
  2124. type: 'warning'
  2125. }).catch(() => false);
  2126. if (!confirmed) {
  2127. return;
  2128. }
  2129. }
  2130. handleServiceOrder(1000)
  2131. }
  2132. const handleSuccessInspectionplan = async (info) => {
  2133. const firstOrderItem = unref(taskOrderDetail).orderItems[0] || {}
  2134. const params: Recordable = {
  2135. taskOrderNo: props.taskOrder.orderNo,
  2136. templateId: info.templateId,
  2137. }
  2138. if (firstOrderItem.equipCode) {
  2139. params.equipCode = firstOrderItem.equipCode
  2140. }
  2141. try {
  2142. // 1.获取选中模板配置信息
  2143. //const templateInitJSON = await getPressureReportTemplateMockJSON(params)
  2144. const templateInitJSON = null;
  2145. const defaultUser: Record<string, any> = {
  2146. prepareName: unref(userInfo)?.nickname,
  2147. prepareDate: dayjs().format('YYYY年MM月DD')
  2148. }
  2149. const prepareJson = templateInitJSON ? {...JSON.parse(templateInitJSON), ...defaultUser} : defaultUser
  2150. // 2.组装参数, 生成新的检验方案记录,
  2151. const addParams = {
  2152. orderId: taskOrderDetail.value.id,
  2153. templateId: info.templateId,
  2154. prepareJson: JSON.stringify(prepareJson),
  2155. prepareId: unref(userInfo)?.id,
  2156. prepareName: unref(userInfo)?.nickname,
  2157. orderItemIds: selectedEquips.value.map(item => item.mainID),
  2158. reportName: info.reportName,
  2159. }
  2160. const newReportId = await BoilerTaskOrderApi.addMajorIssues(addParams)
  2161. editInspectionplanParams.value = {
  2162. reportId: newReportId,
  2163. templateId: info.templateId,
  2164. orderId: taskOrderDetail.value.id,
  2165. // prepareJson: templateInitJSON ? JSON.parse(templateInitJSON) : ''
  2166. prepareJson: JSON.stringify(prepareJson),
  2167. isSelfType: info.isSelfType,
  2168. }
  2169. isEdit.value = 'add'
  2170. AddInspectionplanDetailVisible.value = true
  2171. } catch (error) {
  2172. ElMessage.error('获取模板失败')
  2173. }
  2174. }
  2175. const handleUpdateServiceRecordList = ()=>{
  2176. isAddMainquestion.value = 'view'
  2177. emit('refresh');
  2178. }
  2179. const showViewMainquestionBtn = (row: Recordable)=>{
  2180. return supportingDocsAuditDataList.value.some(item => item.reportType === PressureReportType.MAINQUESTION && item.orderItemId === row.mainID)
  2181. }
  2182. const canAddWorkInstruction = ()=>{
  2183. return taskOrderDetail.value?.checkType !== PressureBoilerCheckType.OUT
  2184. }
  2185. const handleViewMainquestionReport = (row: Recordable)=>{
  2186. if(!showViewMainquestionBtn(row)) return ElMessage.error('该设备不存在该类型的报告')
  2187. const checkAuditRow = unref(supportingDocsAuditDataList).find(item => item.reportType === PressureReportType.MAINQUESTION && item.orderItemId === row.mainID)
  2188. newHandleOperationReport(checkAuditRow, 'view')
  2189. }
  2190. const handleLookSecurityCheck = async () => {
  2191. showSavetyCheckRecordVersions.value = true
  2192. await fetchSafetyCheckRecordPage()
  2193. }
  2194. //添加作业指导书
  2195. // 记录当前的报告类型相关信息
  2196. const addBookAndCheckSchemeRef = ref<InstanceType<typeof AddBookAndCheckScheme>>()
  2197. const curReportType = ref()
  2198. const editWorkBookReportVisible = ref(false)
  2199. const curReportTypeInfo = reactive({
  2200. reportType: '',
  2201. data: {}
  2202. })
  2203. const handleAddReport = async (reportType, row?: Recordable) => {
  2204. if (!isCanAddFlag(row)){
  2205. return
  2206. }
  2207. // 更新记录操作行信息
  2208. curReportTypeInfo.reportType = reportType
  2209. curReportTypeInfo.data = {...row}
  2210. // 创建一个带ElSelect组件的弹窗
  2211. const dialogSelectedValue = ref<string | number>('')
  2212. const createElSelectFormDialog = (options, label) => {
  2213. return defineComponent({
  2214. setup() {
  2215. return () => h('div', [
  2216. h('p', { style: 'margin-bottom: 6px' }, label),
  2217. h(ElSelect, {
  2218. modelValue: dialogSelectedValue.value,
  2219. 'onUpdate:modelValue': (value: string) => {
  2220. dialogSelectedValue.value = value;
  2221. },
  2222. placeholder: '请选择' + label,
  2223. style: 'width: 100%'
  2224. }, options.map(option =>
  2225. h(ElOption, {
  2226. key: option.id,
  2227. label: option.name,
  2228. value: option.id
  2229. })
  2230. ))
  2231. ]);
  2232. }
  2233. });
  2234. }
  2235. try {
  2236. if(!reportType) {
  2237. ElMessage.error('未知的报告类型')
  2238. return
  2239. }
  2240. // 获取下拉选择框的options数据
  2241. const options = ref<any[]>([])
  2242. const params = {}
  2243. switch (reportType) {
  2244. // case PressureReportType['MAINQUESTION']:
  2245. // params['classId'] = 'd799cf8309fa17df5bb87766fc10e00b'
  2246. // break
  2247. // case PressureReportType['INSPECTIONPLAN']:
  2248. // // 检验方案
  2249. // params['type'] = '6'
  2250. // break
  2251. case PressureReportType['WORKINSTRUCTION']:
  2252. // 作业指导书
  2253. params['reportType'] = '700'
  2254. break
  2255. default:
  2256. return
  2257. }
  2258. // 获取指定项目类型的报告
  2259. const response = await getPressureReportTemplateListNoLimit({...params, pageNo: 1, pageSize: 100, status: 200})
  2260. options.value = response?.data?.list || response?.list || response || []
  2261. if([PressureReportType['INSPECTIONPLAN'], PressureReportType['WORKINSTRUCTION']].includes(reportType)) {
  2262. curReportType.value = reportType
  2263. // 检验方案 & 作业指导书 调整修改逻辑其他的保持不变
  2264. const newParams = {
  2265. title: PressureReportTypeMap[reportType],
  2266. options: options.value.map(item => ({
  2267. ...item,
  2268. label: item.tbName,
  2269. value: item.id
  2270. })),
  2271. formData: {
  2272. ...row,
  2273. orderId: taskOrderDetail.value.id,
  2274. // templateId: dialogSelectedValue.value,
  2275. }
  2276. }
  2277. // 添加检验方案逻辑
  2278. // if(reportType === PressureReportType['INSPECTIONPLAN']) {
  2279. // addInspectionplanRef.value?.open(newParams, '添加检验方案')
  2280. // return
  2281. // }
  2282. addBookAndCheckSchemeRef.value?.open(newParams, reportType)
  2283. return
  2284. }
  2285. // 4. 显示自定义弹窗
  2286. ElMessageBox({
  2287. title: '关联项目模板',
  2288. message: h(createElSelectFormDialog(options.value, '项目模板')),
  2289. confirmButtonText: '确定',
  2290. cancelButtonText: '取消',
  2291. showCancelButton: true,
  2292. customClass: 'customPromptStyle',
  2293. beforeClose: (action: Action, instance, done) => {
  2294. if((dialogSelectedValue.value && action === 'confirm') || action === 'cancel') {
  2295. done()
  2296. } else {
  2297. ElMessage.error('请选择项目模板')
  2298. }
  2299. }
  2300. }).then(async () => {
  2301. if(dialogSelectedValue.value) {
  2302. if (params['type'] == '700') {
  2303. // 这里去打开模板
  2304. editOperationReportVisible.value = true
  2305. editOperationReportTypeTitle.value = PressureReportTypeMap[reportType]
  2306. editOperationReportParams.value = {
  2307. ...editOperationReportParams.value,
  2308. templateId: dialogSelectedValue.value,
  2309. orderId: taskOrderDetail.value.id,
  2310. }
  2311. dialogSelectedValue.value = ''
  2312. }
  2313. }
  2314. }).catch((error) => {
  2315. dialogSelectedValue.value = ''
  2316. });
  2317. } catch (error) {
  2318. // 处理接口错误
  2319. ElMessage({
  2320. type: 'error',
  2321. message: 'Failed to load options'
  2322. });
  2323. console.error('API error:', error);
  2324. }
  2325. }
  2326. // 添加作业指导书
  2327. const handleSuccessReport = async (info) => {
  2328. const reportList = filterReportType(info.reportRespVOList);
  2329. const templateIds = (reportList || []).filter(item=>item.templateId === info.templateId)
  2330. if (templateIds.length > 0){
  2331. ElMessage.error('该设备已存在该作业指导书')
  2332. return
  2333. }
  2334. if(!info) return handleEditOperationReportList()
  2335. // 如果选择的是模板,则还是走之前的逻辑,打开葡萄城进行编辑提交
  2336. if(info?.addType === '2' && info.id){
  2337. // 这里去打开模板
  2338. editOperationReportTypeTitle.value = PressureReportTypeMap[unref(curReportType)]
  2339. editOperationReportParams.value = {
  2340. ...editOperationReportParams.value,
  2341. templateId: info.templateId,
  2342. orderId: taskOrderDetail.value.id,
  2343. orderItemId: info.mainID,
  2344. // 操作指导书,初始化编制人和编制时间
  2345. // prepareJson: JSON.stringify({
  2346. // prepareName: unref(userInfo)?.nickname,
  2347. // prepareDate: dayjs().format('YYYY年MM月DD'),
  2348. // })
  2349. }
  2350. isWorkBookEdit.value = true
  2351. //添加操作指导书
  2352. if (!editOperationReportParams.value.reportId) {
  2353. // 初次编辑模板 需要添加报告
  2354. // newReportId 返回的是reportId
  2355. const params: Recordable = {
  2356. orderId: editOperationReportParams.value.orderId,
  2357. templateId: editOperationReportParams.value.templateId,
  2358. prepareId: unref(userInfo)?.id,
  2359. prepareName: unref(userInfo)?.nickname,
  2360. orderItemId: editOperationReportParams.value.orderItemId
  2361. }
  2362. editOperationReportParams.value.reportId = await BoilerTaskOrderApi.addMajorIssues(params)
  2363. }
  2364. editWorkBookReportVisible.value = true
  2365. }
  2366. }
  2367. const handleEditOperationReportList = () => {
  2368. // 重新获取列表数据
  2369. // operationReportPageNo.value = 1
  2370. // handleGetOperationReportAuditList()
  2371. // editOperationReportParams.value = initEditOperationReportParams.value
  2372. emit('refresh');
  2373. }
  2374. const getTypeColor = (status: string | number) => {
  2375. const statusMap = {
  2376. [PressureTaskOrderTaskStatus.WAIT_CONFIRM]: 'primary',
  2377. [PressureTaskOrderTaskStatus.CANCELLED]: 'info',
  2378. [PressureTaskOrderTaskStatus.AUDITING_EDIT]: 'warning',
  2379. [PressureTaskOrderTaskStatus.AUDITING_CANCEL]: 'warning',
  2380. [PressureTaskOrderTaskStatus.AUDITING_TIME]: 'warning',
  2381. [PressureTaskOrderTaskStatus.CONFIRMED]: 'success',
  2382. [PressureTaskOrderTaskStatus.RECORD_INPUT]: 'warning',
  2383. [PressureTaskOrderTaskStatus.RECORD_CHECK]: 'warning',
  2384. [PressureTaskOrderTaskStatus.REPORT_INPUT]: 'warning',
  2385. [PressureTaskOrderTaskStatus.REPORT_AUDIT]: 'warning',
  2386. [PressureTaskOrderTaskStatus.REPORT_APPROVE]: 'warning',
  2387. [PressureTaskOrderTaskStatus.REPORT_END]: 'primary'
  2388. };
  2389. return statusMap[status] || 'info';
  2390. }
  2391. const isCustomFileUrl = ref(false)
  2392. const handleResubmitDocs = async (row) => {
  2393. if(row.reportType === PressureReportType.MAINQUESTION){
  2394. return handleMainquestionAddReport(row.reportType, 'edit', row)
  2395. }
  2396. // 如果是检验方案走检验方案的逻辑
  2397. if(row.reportType === PressureReportType['INSPECTIONPLAN']) {
  2398. // 检验方案
  2399. editInspectionplanParams.value = {
  2400. reportId: row.id,
  2401. templateId: row.templateId,
  2402. orderId: taskOrderDetail.value.id,
  2403. prepareJson: row.prepareJson || '',
  2404. isSelfType: row.tbType === 500 && row.pjType === 5,
  2405. }
  2406. inspectionplanDetail.value = row
  2407. isEdit.value = 'edit'
  2408. AddInspectionplanDetailVisible.value = true
  2409. return
  2410. }
  2411. isCustomFileUrl.value = !row.templateId
  2412. // 重新提交
  2413. editOperationReportTypeTitle.value = PressureReportTypeMap[row.reportType]
  2414. editOperationReportParams.value = {
  2415. ...editOperationReportParams.value,
  2416. reportId: row.id,
  2417. templateId: row.templateId,
  2418. orderId: taskOrderDetail.value.id,
  2419. prepareJson: row.prepareJson
  2420. }
  2421. // 作业指导书 重新提交审批
  2422. if(row.reportType === PressureReportType['WORKINSTRUCTION']) {
  2423. return handleWorkBookDetail(row, true)
  2424. }
  2425. editOperationReportVisible.value = true
  2426. }
  2427. const handleCancelDocs = async (item) => {
  2428. // 作废项目
  2429. try {
  2430. const { value: voidReason } = await ElMessageBox.prompt(
  2431. `确定要作废项目 ${item.reportName} 吗?`,
  2432. '作废项目',
  2433. {
  2434. confirmButtonText: '确认作废',
  2435. cancelButtonText: '取消',
  2436. inputPlaceholder: '请输入作废原因',
  2437. inputType: 'textarea',
  2438. inputValidator: (value: string) => {
  2439. if (!value || !value.trim()) {
  2440. return '作废原因不能为空'
  2441. }
  2442. if (value.trim().length < 5) {
  2443. return '作废原因至少需要5个字符'
  2444. }
  2445. if (value.trim().length > 200) {
  2446. return '作废原因不能超过200个字符'
  2447. }
  2448. return true
  2449. },
  2450. inputErrorMessage: '请输入有效的作废原因'
  2451. }
  2452. )
  2453. if (voidReason && voidReason.trim()) {
  2454. const params: Recordable = {
  2455. id: item.id,
  2456. reportType: item.reportType,
  2457. reason: voidReason.trim()
  2458. }
  2459. // 如果类型是检验方案/操作指导书作废,多传递一个isDelete字段
  2460. if([PressureReportType['INSPECTIONPLAN'], PressureReportType['WORKINSTRUCTION'], PressureReportType.MAINQUESTION].includes(item.reportType)) {
  2461. params.isDelete = true
  2462. }
  2463. await BoilerTaskOrderApi.cancelReport(params)
  2464. ElMessage.success(`成功作废项目 ${item.reportName}`)
  2465. handleGetOperationReportAuditList()
  2466. }
  2467. } catch (error: any) {
  2468. if (error !== 'cancel') {
  2469. console.error('作废项目失败:', error)
  2470. ElMessage.error('作废项目失败,请稍后重试')
  2471. }
  2472. }
  2473. }
  2474. // 推送结算系统
  2475. const handlePushSettlementSystem = () => {
  2476. ElMessageBox.confirm('确认推送结算系统吗?', '提示', {
  2477. confirmButtonText: '确定',
  2478. cancelButtonText: '取消',
  2479. type: 'warning'
  2480. }).then(() => {
  2481. BoilerTaskOrderApi.pushSettlementSystem({}, {
  2482. id: props.taskOrder.id
  2483. }).then(() => {
  2484. ElMessage.success('推送结算系统成功')
  2485. }).catch(()=>{
  2486. ElMessage.error('推送结算系统失败')
  2487. })
  2488. })
  2489. }
  2490. const canPushSettlementSystem = computed(() => {
  2491. // 超级管理员角色 | 项目负责人 才能推送结算系统
  2492. return !(taskOrderDetail.value.managerId == unref(userInfo)?.id || userStore.getRoles.includes('super_admin'))
  2493. })
  2494. const recycleReportFn = async (item) => {
  2495. ElMessageBox.confirm(`确定要回收项目 ${item.reportName} 吗?`, '提示', {
  2496. confirmButtonText: '确认回收',
  2497. cancelButtonText: '取 消'
  2498. })
  2499. .then(async () => {
  2500. const res = await BoilerTaskOrderApi.majorIssuesRecovery({
  2501. businessType: '0',
  2502. reportId: item.id
  2503. })
  2504. if (res) {
  2505. ElMessage.success('回收成功')
  2506. refreshDetail()
  2507. }
  2508. })
  2509. .catch(() => console.info('操作取消'))
  2510. }
  2511. const refreshDetail = () => {
  2512. console.log('刷新详情')
  2513. emit('refresh')
  2514. }
  2515. /** 处理中止检验 */
  2516. const dialogVisible = ref(false) // 弹窗的是否展示
  2517. const abortFormRef = ref<InstanceType<typeof ElForm>>()
  2518. const formLoading = ref(false)
  2519. const formData = ref<Record<string, any>>({
  2520. reasonDict: '',
  2521. reason: ''
  2522. })
  2523. const rules = reactive({
  2524. reasonDict: [{ required: true, message: '请选择拒绝原因', trigger: 'change' }],
  2525. reason: [{ required: true, message: '请输入其他原因', trigger: 'blur' }]
  2526. })
  2527. const submitForm = async () => {
  2528. abortFormRef.value &&
  2529. abortFormRef.value.validate().then(() => {
  2530. const params: any = {
  2531. ...unref(formData),
  2532. orderItemIds: selectedEquips.value.map((item) => item.mainID),
  2533. flag: 1
  2534. }
  2535. if (params.reasonDict != 5) {
  2536. params.reason = ''
  2537. }
  2538. formLoading.value = true
  2539. BoilerTaskOrderApi.abortTask(params)
  2540. .then(() => {
  2541. // 刷新数据
  2542. ElMessage.success('检验任务已中止')
  2543. emit('refresh')
  2544. })
  2545. .finally(() => {
  2546. formLoading.value = false
  2547. })
  2548. })
  2549. }
  2550. const submitFormNoReport = async () => {
  2551. const params: any = {
  2552. ...unref(formData),
  2553. orderItemIds: selectedEquips.value.map((item) => item.mainID),
  2554. flag: 0
  2555. }
  2556. if (params.reasonDict != 5) {
  2557. params.reason = ''
  2558. }
  2559. formLoading.value = true
  2560. BoilerTaskOrderApi.abortTask(params)
  2561. .then(() => {
  2562. // 刷新数据
  2563. ElMessage.success('无需上报操作成功')
  2564. emit('refresh')
  2565. })
  2566. .finally(() => {
  2567. formLoading.value = false
  2568. })
  2569. }
  2570. const handleAbortTask = () => {
  2571. if (selectedEquips.value.length === 0) {
  2572. ElMessage.warning('请至少选择一条记录')
  2573. return
  2574. }
  2575. // 主报告状态,为报告办结的不能中止
  2576. const hasReportEnd = selectedEquips.value.some((row) => row.taskStatus === 800)
  2577. if (hasReportEnd) {
  2578. ElMessage.warning('主报告状态为报告办结的不能进行客户拒检')
  2579. return
  2580. }
  2581. abortFormRef.value && abortFormRef.value.resetFields()
  2582. dialogVisible.value = true
  2583. }
  2584. </script>
  2585. <style lang="scss" scoped>
  2586. .loading-text {
  2587. text-align: center;
  2588. padding: 20px;
  2589. color: #909399;
  2590. }
  2591. :deep(.el-descriptions__label) {
  2592. width: 10%;
  2593. }
  2594. :deep(.el-descriptions__content) {
  2595. width: 20%;
  2596. }
  2597. .leader-tag {
  2598. display: inline-block;
  2599. width: 16px;
  2600. height: 16px;
  2601. line-height: 14px;
  2602. text-align: center;
  2603. border: 1px solid #4475d6;
  2604. font-size: 12px;
  2605. margin-right: 4px;
  2606. color: #4475d6;
  2607. }
  2608. .app-container { // Ensure this class is defined if not globally available
  2609. padding: 20px; // Example padding
  2610. }
  2611. // 操作按钮对齐样式
  2612. .operation-buttons {
  2613. display: flex;
  2614. justify-content: center;
  2615. align-items: center;
  2616. gap: 8px;
  2617. flex-wrap: wrap;
  2618. }
  2619. .custom-block.tip {
  2620. padding: 0 6px;
  2621. background-color: var(--block-warning-bg-color);
  2622. border-left: 5px solid var(--el-color-primary);
  2623. margin: 15px 0;
  2624. }
  2625. .el-row {
  2626. margin: 1px;
  2627. }
  2628. </style>