StatusOperationPanel.vue 83 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680
  1. <template>
  2. <div class="container-panel">
  3. <el-row class="info-panel">
  4. <div class="info-item">
  5. <span class="label">报告编号:</span>
  6. <span class="value">{{ selectedItem?.reportNo || '-' }}</span>
  7. </div>
  8. <div class="info-item" style="margin: 0 auto;" v-if="isShowRecordOrReportBtn">
  9. <!-- <el-switch-->
  10. <!-- v-model="isShowReportPdf"-->
  11. <!-- active-text="报告"-->
  12. <!-- inactive-text="记录"-->
  13. <!-- @change="handleChangeShowReportPdf"-->
  14. <!-- />-->
  15. <!-- <el-radio-group v-model="showReportPdfType" @change="handleChangeShowReportPdf">-->
  16. <!-- <el-radio-button label="record">记录</el-radio-button>-->
  17. <!-- <el-radio-button label="report">报告</el-radio-button>-->
  18. <!-- <el-radio-button label="result" v-if="selectedItem?.reportType === 100">结论报告</el-radio-button>-->
  19. <!-- </el-radio-group>-->
  20. <div class="capsule-tabs">
  21. <div
  22. class="tab-item"
  23. :class="{ active: showReportPdfType === 'record' }"
  24. @click="handleChangeShowReportPdf('record')"
  25. v-if="hasRecord"
  26. >
  27. <span>记录</span>
  28. </div>
  29. <div
  30. class="tab-item"
  31. :class="{ active: showReportPdfType === 'report' }"
  32. @click="handleChangeShowReportPdf('report')"
  33. >
  34. <span>报告</span>
  35. </div>
  36. </div>
  37. </div>
  38. <div class="info-item" style="margin: 0 auto;">
  39. <span class="label">检验项目:</span>
  40. <span class="value" :title="selectedItem?.reportName || '-'">{{
  41. selectedItem?.reportName || '-'
  42. }}</span>
  43. </div>
  44. <div v-if="selectedItem?.reportType === 300">
  45. <span>{{ selectedItem.instructionId ? '已' : '未'}}关联操作指导书</span>
  46. <el-button
  47. type="primary"
  48. size="small"
  49. link
  50. class="edit-checker-btn"
  51. @click="handleShowAssociationOperationManual"
  52. >
  53. <Icon icon="ep:edit" />
  54. </el-button>
  55. </div>
  56. <div class="info-item" style="flex-basis: 300px; text-align: end;">
  57. <span class="label">{{ selectedItem?.reportType === 100 ? '主检人' : '检验员' }}:</span>
  58. <span
  59. class="value"
  60. :title="
  61. selectedItem?.reportType === 100
  62. ? taskOrderItem?.mainCheckerUser?.nickname || '-'
  63. : getCheckersName()
  64. "
  65. >{{
  66. selectedItem?.reportType === 100
  67. ? taskOrderItem?.mainCheckerUser?.nickname || '-'
  68. : getCheckersName()
  69. }}</span
  70. >
  71. <el-button
  72. v-if="!isAuditMode"
  73. type="primary"
  74. size="small"
  75. link
  76. class="edit-checker-btn"
  77. @click="
  78. () =>
  79. selectedItem?.reportType === 100 ? handleModifyMainChecker() : handleModifyChecker()
  80. "
  81. :disabled="(selectedItem?.reportType === 100 && taskOrderItem?.mainCheckerUser?.id !== userStore?.user?.id)
  82. || (selectedItem?.checkUsers?.length > 0 && selectedItem?.checkUsers?.[0]?.id !== userStore?.user?.id && taskOrderItem?.mainCheckerUser?.id !== userStore?.user?.id)
  83. || isCompleteInput"
  84. >
  85. <!-- 主报告:登录用户为主检人的时,才可以修改主检人 -->
  86. <!-- 子报告:登录用户为检验员或主检人的时候,才可以修改检验员 -->
  87. <Icon icon="ep:edit" />
  88. </el-button>
  89. </div>
  90. </el-row>
  91. <el-row class="status-operation-panel">
  92. <!-- 未选择任何项目时的提示 -->
  93. <div v-if="!selectedItem" class="no-selection">
  94. <el-empty description="请选择一个检验项目查看详情" :image-size="100" />
  95. </div>
  96. <!-- 选择单个项目时显示详情操作 -->
  97. <div v-else class="single-item-panel">
  98. <!--
  99. 1、重大问题线索告知表
  100. 2、作业指导书
  101. 3、检验方案
  102. 以上报告类型不显示做进度栏目
  103. -->
  104. <InspectionItemProgress
  105. v-if="!onlyShowPdf"
  106. :selected-item="selectedItem"
  107. :task-info="taskInfo"
  108. :is-audit-mode="isAuditMode"
  109. @modify-checker="handleModifyChecker"
  110. />
  111. <!-- <div class="pdf-panel" :style="{ maxWidth: !onlyShowPdf ? '1200px' : 'unset' }"> -->
  112. <div ref="pdfPanelRef" class="pdf-panel" >
  113. <!-- PDF预览区域 -->
  114. <div class="!h-full" :style="{ width: pdfContentWidth + 'px'}">
  115. <SpreadViewer :initData="initData" ref="spreadRef" isFullscreen @saveSuccess="saveSuccess"/>
  116. </div>
  117. </div>
  118. <!--
  119. 1、重大问题线索告知表
  120. 2、作业指导书
  121. 3、检验方案
  122. 以上报告类型不显示右侧栏目
  123. -->
  124. <template v-if="showCheckBook && getReportStatusEnd">
  125. <div class="right-panel-container">
  126. <!-- 收缩展开按钮 -->
  127. <div class="toggle-btn" @click="togglePanel" :class="{ 'collapsed': !isExpanded }">
  128. <el-icon>
  129. <Back v-if="!isExpanded" />
  130. <Right v-else />
  131. </el-icon>
  132. </div>
  133. <div class="operation-panel" :class="{ 'expanded': isExpanded, 'collapsed': !isExpanded }">
  134. <div class="operation-inner custom-inner">
  135. <template v-if="checkBookDetail.rectificationStatus === 2">
  136. <div class="operation-item">
  137. <div class="item-header"> 回退原因 </div>
  138. <div class="item-content">
  139. <el-form
  140. ref="returnFormRef"
  141. :model="returnForm"
  142. :rules="returnFormRules"
  143. label-position="right"
  144. label-width="80px"
  145. >
  146. <el-form-item label="回退原因" prop="rejectionReason">
  147. <el-input
  148. v-model="returnForm.rejectionReason"
  149. type="textarea"
  150. :rows="5"
  151. maxlength="100"
  152. placeholder="请输入回退原因"
  153. />
  154. </el-form-item>
  155. </el-form>
  156. </div>
  157. </div>
  158. </template>
  159. <div class="operation-item1">
  160. <div class="item-header"> 处理人信息 </div>
  161. <div class="item-content">
  162. <div class="item-content-item">
  163. <span class="item-content-item-label">联系人姓名:</span>
  164. <span class="item-content-item-value">{{ checkBookDetail?.recipient || '-' }}</span>
  165. </div>
  166. <div class="item-content-item">
  167. <span class="item-content-item-label">联系人电话:</span>
  168. <span class="item-content-item-value">{{ checkBookDetail?.recipientPhone || '-'}}</span>
  169. </div>
  170. <div class="item-content-item">
  171. <span class="item-content-item-label">当前状态:</span>
  172. <span class="item-content-item-value">{{
  173. rectificationStatusMap[checkBookDetail?.rectificationStatus] || '-'
  174. }}</span>
  175. </div>
  176. </div>
  177. </div>
  178. <div class="operation-item1 videoAndImg">
  179. <div class="item-header"> 整改材料 </div>
  180. <div class="item-content1">
  181. <div class="item-content1-item">图片:</div>
  182. <div class="item-content1-img">
  183. <template
  184. v-for="(path, index) in checkBookDetail.rectificationImage?.split(',') || []"
  185. :key="index"
  186. >
  187. <div class="item-content1-img-item">
  188. <img class="img-item" :src="buildFileUrl(path)" alt="" @click="handlePreview(buildFileUrl(path), 'image')" />
  189. <div class="list-item-tool">
  190. <el-icon class="icon" @click="() => handlePreview(buildFileUrl(path), 'image')"><View /></el-icon>
  191. </div>
  192. </div>
  193. </template>
  194. </div>
  195. </div>
  196. <div class="item-content1">
  197. <div class="item-content1-item">视频:</div>
  198. <div class="item-content1-img">
  199. <template
  200. v-for="(path, index) in checkBookDetail.rectificationVideo?.split(',') || []"
  201. :key="index"
  202. >
  203. <div class="item-content1-img-item">
  204. <video class="img-item" :src="buildFileUrl(path)" alt="" @click="handlePreview(buildFileUrl(path), 'video')"></video>
  205. <!-- 视频播放按钮 -->
  206. <div class="list-item-tool">
  207. <el-icon class="icon" @click="() => handlePreview(buildFileUrl(path), 'video')"><View /></el-icon>
  208. </div>
  209. </div>
  210. </template>
  211. </div>
  212. </div>
  213. </div>
  214. </div>
  215. </div>
  216. </div>
  217. </template>
  218. <template v-else>
  219. <div class="right-panel-container">
  220. <!-- 收缩展开按钮 -->
  221. <div class="toggle-btn" @click="togglePanel" :class="{ 'collapsed': !isExpanded }" v-if="!onlyShowPdf">
  222. <el-icon>
  223. <Back v-if="!isExpanded" />
  224. <Right v-else />
  225. </el-icon>
  226. </div>
  227. <div class="operation-panel" :class="{ 'expanded': isExpanded, 'collapsed': !isExpanded }" v-if="!onlyShowPdf">
  228. <div class="operation-inner">
  229. <!-- 流转记录 -->
  230. <div class="operation-item">
  231. <div class="item-header"> 流转记录 </div>
  232. <div class="item-content">
  233. <el-empty
  234. v-if="!recordList.length"
  235. description="暂无流转记录"
  236. :image-size="120"
  237. />
  238. <div class="record-item" v-for="record in recordList" :key="record.id">
  239. <div class="record-item-title">{{ PressureReportType['SUGGUESTION'] === props.selectedItem?.reportType ? record.processName : PressureCheckerMyTaskStatusMap[record.process]
  240. }}</div>
  241. <div class="record-item-inner">
  242. <div class="content">
  243. <span>{{ record.createUser.nickname }}</span>
  244. <el-button
  245. :type="
  246. record.result === 100
  247. ? 'success'
  248. : record.result === 200
  249. ? 'danger'
  250. : 'default'
  251. "
  252. round
  253. size="small"
  254. >{{
  255. record.result === 100
  256. ? '通过'
  257. : record.result === 200
  258. ? '拒绝'
  259. : record.result || '-'
  260. }}</el-button
  261. >
  262. <span class="time">{{
  263. !record.createTime
  264. ? '-'
  265. : dayjs(record.createTime).format('YYYY-MM-DD HH:mm:ss')
  266. }}</span>
  267. </div>
  268. <p class="desc">
  269. <span>描述</span>
  270. {{ record.remark && record.remark.trim() !== '' ? record.remark : '-' }}
  271. </p>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. <!-- 智能纠错 -->
  277. <div class="operation-item">
  278. <div class="item-header"> 智能纠错 </div>
  279. <div class="item-content">
  280. <el-empty
  281. v-if="!checkInputList.length"
  282. description="暂无纠错内容"
  283. :image-size="120"
  284. />
  285. <div class="error-item" v-for="input in checkInputList" :key="input.code">
  286. <el-icon color="#E0534E" :size="20"><InfoFilled /></el-icon>
  287. {{ input.code }}:{{ input.name }}
  288. </div>
  289. </div>
  290. </div>
  291. <!-- 历史版本 -->
  292. <div class="operation-item">
  293. <div class="item-header"> 历史版本 </div>
  294. <div class="item-content" v-if="historyList.length">
  295. <!-- <template> -->
  296. <div class="history-item" v-for="item in historyList" :key="item.id">
  297. <div class="history-title">{{ item.versionNoStr || '-' }}号版本</div>
  298. <p
  299. >修改原因:<span>{{ item.modifiedReason || '人工修改' }}</span></p
  300. >
  301. <div class="history-footer">
  302. <span class="name">{{ item.creatorName || '-' }}</span>
  303. <span class="time"
  304. >修改于{{
  305. dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss') || '-'
  306. }}</span
  307. >
  308. </div>
  309. <div class="my-2">
  310. <el-button type="primary" link @click="handleShowVersionInfo(item)"
  311. >查看详情</el-button
  312. >
  313. <el-button v-if="!checkerIsLoginUser" type="primary" link @click="restoreVersion(item)"
  314. >恢复版本</el-button
  315. >
  316. </div>
  317. </div>
  318. <!-- </template> -->
  319. </div>
  320. <template v-else>
  321. <el-empty description="暂无历史版本" :image-size="120" />
  322. </template>
  323. </div>
  324. </div>
  325. </div>
  326. </div>
  327. </template>
  328. </div>
  329. <!-- 审批人选择对话框 -->
  330. <AuditUserDialog
  331. v-if="isShowApprovalDialog"
  332. v-model="isShowApprovalDialog"
  333. :apiFn="getRecheckUserList"
  334. title="请选择审批人"
  335. selectedAlertText="已选择审批人"
  336. width="700px"
  337. :columns="[
  338. {
  339. type: 'selection',
  340. fieldProps: {
  341. reserveSelection: true
  342. }
  343. },
  344. {
  345. label: '姓名',
  346. prop: 'nickname',
  347. search: {
  348. type: 'input',
  349. span: 12,
  350. prop: 'nickName'
  351. }
  352. },
  353. {
  354. label: '部门',
  355. prop: 'deptName',
  356. search: {
  357. type: 'input',
  358. span: 12
  359. }
  360. }
  361. ]"
  362. @confirm="handleApprovalSelectConfirm"
  363. />
  364. <Dialog
  365. v-model="isShowAuditDialog"
  366. width="400"
  367. :title="schemaFlag == 'proofread' ? '请选择校核人' : '请选择审核人'"
  368. >
  369. <CustomLargeListSelect
  370. v-model="form.recheckUser"
  371. :fetchFunc="getRecheckUserList"
  372. label-key="nickname"
  373. value-key="id"
  374. searchKeyProp="nickName"
  375. @change="handleChangeEntrustUnit"
  376. />
  377. <template #footer>
  378. <el-button type="primary" @click="handleAuditSelectConfirm" :loading="submitting">保 存</el-button>
  379. <el-button @click="isShowAuditDialog = false">取 消</el-button>
  380. </template>
  381. </Dialog>
  382. <!-- 批量提交校核 -->
  383. <Dialog
  384. v-model="showBatchSubmitToRecheckDialog"
  385. width="400"
  386. title="批量提交校核"
  387. >
  388. <el-form ref="batchRecheckFormRef" :model="batchRecheckForm" :rules="batchRecheckFormRules" label-width="80px">
  389. <el-form-item label="提交记录" prop="reportIds">
  390. <el-select
  391. v-model="batchRecheckForm.reportIds"
  392. multiple
  393. clearable
  394. placeholder="请选择报告"
  395. >
  396. <el-option
  397. v-for="item in getCanSubmitRecheckReport"
  398. :key="item.id"
  399. :value="item.id"
  400. :label="item.reportName"
  401. />
  402. </el-select>
  403. </el-form-item>
  404. <el-form-item label="校核人" prop="recheckUser">
  405. <CustomLargeListSelect
  406. v-model="batchRecheckForm.recheckUser"
  407. :fetchFunc="getRecheckUserList"
  408. label-key="nickname"
  409. value-key="id"
  410. searchKeyProp="nickName"
  411. @change="handleChangeEntrustUnit"
  412. placeholder="请选择校核人"
  413. />
  414. </el-form-item>
  415. <el-form-item label="">
  416. <span style="font-size: 13px; white-space: nowrap; margin-top: -16px; color: #999;">
  417. 您已完成{{getCanSubmitRecheckReport.length}}份记录录入,可以进行批量提交校核
  418. </span>
  419. </el-form-item>
  420. </el-form>
  421. <template #footer>
  422. <el-button type="primary" @click="handleBatchSubmitToRecheck">提 交</el-button>
  423. <el-button @click="showBatchSubmitToRecheckDialog = false">取 消</el-button>
  424. </template>
  425. </Dialog>
  426. <!-- 校核人选择对话框 暂时作废
  427. -->
  428. <!-- <AuditUserDialog
  429. v-if="isShowAuditDialog"
  430. v-model="isShowAuditDialog"
  431. :apiFn="getRecheckUserList"
  432. title="请选择校核人"
  433. selectedAlertText="已选择校核人"
  434. width="700px"
  435. :pageType="0"
  436. :columns="[
  437. {
  438. type: 'selection',
  439. fieldProps: {
  440. reserveSelection: true
  441. }
  442. },
  443. {
  444. label: '姓名',
  445. prop: 'nickname',
  446. search: {
  447. type: 'input',
  448. span: 12,
  449. prop: 'nickName'
  450. }
  451. },
  452. {
  453. label: '部门',
  454. prop: 'deptName',
  455. search: {
  456. type: 'input',
  457. span: 12
  458. }
  459. }
  460. ]"
  461. @confirm="handleAuditSelectConfirm"
  462. /> -->
  463. <!-- 报告审核人选择对话框 -->
  464. <AuditUserDialog
  465. v-if="isShowReportAuditDialog"
  466. v-model="isShowReportAuditDialog"
  467. :apiFn="getRecheckUserList"
  468. title="请选择审核人"
  469. selectedAlertText="已选择审核人"
  470. width="700px"
  471. :columns="[
  472. {
  473. type: 'selection',
  474. fieldProps: {
  475. reserveSelection: true
  476. }
  477. },
  478. {
  479. label: '姓名',
  480. prop: 'nickname',
  481. search: {
  482. type: 'input',
  483. span: 12,
  484. prop: 'nickName'
  485. }
  486. },
  487. {
  488. label: '部门',
  489. prop: 'deptName',
  490. search: {
  491. type: 'input',
  492. span: 12
  493. }
  494. }
  495. ]"
  496. @confirm="handleReportAuditSelectConfirm"
  497. />
  498. </el-row>
  499. <!-- 检验结果录入-葡萄城模板 -->
  500. <InlineInspectionResultInput
  501. v-if="showInlineInspectionResultInput"
  502. v-model:visible="showInlineInspectionResultInput"
  503. :template-params="inspectionResultTemplateParams"
  504. @confirm="handleInspectionResultConfirm"
  505. @cancel="handleReturnToNormalMode"
  506. />
  507. <!-- 检验录入-模板 -->
  508. <!-- <InlineEditCheckRecord-->
  509. <!-- v-if="showInlineEditCheckRecord"-->
  510. <!-- :templateId="templateId"-->
  511. <!-- v-model:visible="showInlineEditCheckRecord"-->
  512. <!-- :report-list="reportList"-->
  513. <!-- :task-order-item="taskOrderItem"-->
  514. <!-- :template-params="templateParams"-->
  515. <!-- @confirm="handleTemplateConfirm"-->
  516. <!-- @cancel="handleRefresh"-->
  517. <!-- />-->
  518. <!-- 检验录入-模板 -->
  519. <CustomDialog v-model="showInlineEditCheckRecord" :show-footer="false" fullscreen :show-close="false">
  520. <SpreadViewer :initData="editData" ref="editSpreadRecordRef" @saveSuccess="saveSuccessRecord" @close="handleClose">
  521. <template #title>
  522. <div style="font-size: 20px; ">检验录入</div>
  523. </template>
  524. </SpreadViewer>
  525. </CustomDialog>
  526. <!-- 报告编制 - 模板 -->
  527. <!-- <InlineReportEdit-->
  528. <!-- v-if="showInlineReportEdit"-->
  529. <!-- v-model:visible="showInlineReportEdit"-->
  530. <!-- :template-params="templateParams"-->
  531. <!-- :report-list="reportList || []"-->
  532. <!-- :report-type="showReportPdfType"-->
  533. <!-- @confirm="handleTemplateConfirm"-->
  534. <!-- @cancel="handleRefresh"-->
  535. <!-- @refresh="()=>{refreshPdf = !refreshPdf}"-->
  536. <!-- />-->
  537. <!-- 报告编制 - 模板 -->
  538. <CustomDialog v-model="showInlineReportEdit" :show-footer="false" fullscreen :show-close="false">
  539. <SpreadViewer :initData="editData" ref="editSpreadReportRef" @saveSuccess="saveSuccessReport" @close="handleClose">
  540. <template #title>
  541. <div style="font-size: 20px; ">报告编制</div>
  542. </template>
  543. </SpreadViewer>
  544. </CustomDialog>
  545. <!-- 修改主检人弹窗 -->
  546. <UserSelectForm ref="userSelectFormRef" @confirm="handleUserSelect" :single="true" />
  547. <CustomDialog v-model="showReportDialog" :show-footer="false" width="1000px">
  548. <!-- <VuePdfEmbed
  549. v-loading="pdfLoading"
  550. :height="500"
  551. :width="968"
  552. :source="reportSource"
  553. @rendered="handlePdfRendered"
  554. />-->
  555. <SpreadViewer :initData="reportInitData" ref="reportSpreadRef" />
  556. </CustomDialog>
  557. <!-- 查看版本详情的弹窗 -->
  558. <CustomDialog v-model="showVersionDetail" title="查看详情" :show-footer="false" width="1000px">
  559. <SmartTable
  560. v-model:columns="versionColumns"
  561. :buttons="versionDetailButtons"
  562. :data="versionDataCompareList"
  563. :is-pagination="false"
  564. :show-refresh="false"
  565. />
  566. </CustomDialog>
  567. <!-- 图片预览对话框 -->
  568. <el-dialog
  569. v-model="previewVisible"
  570. class="preview-dialog"
  571. title="Warning"
  572. width="500"
  573. :show-footer="false"
  574. :show-close="false"
  575. align-center
  576. >
  577. <div class="preview-container">
  578. <video class="preview-video" v-if="previewType === 'video'" :src="previewUrl" auto-play controls></video>
  579. <img class="preview-image" v-else :src="previewUrl" />
  580. </div>
  581. </el-dialog>
  582. <dialog ref="previewDialogRef"></dialog >
  583. <ReportListUploadModal
  584. ref="reportListUploadModalRef"
  585. :selectedItem="selectedItem"
  586. :reportList="reportList"
  587. @confirm="handleRefresh"
  588. />
  589. </div>
  590. <!-- 新加 -->
  591. <Teleport v-if="teleportBtnRef" to=".teleport-btn">
  592. <div class="operation-btns">
  593. <!-- 报告办结后,这部分按钮不再显示 -->
  594. <template v-if="!getReportStatusEnd && selectedItem">
  595. <!-- 根据报告类型和配置显示相应按钮 -->
  596. <template
  597. v-if="
  598. selectedItem.reportType === PressureReportType.SINGLE &&
  599. 'PipeCheckerTaskDetail' === routeName
  600. "
  601. >
  602. <!-- 独审报告根据配置显示按钮 -->
  603. <el-button
  604. v-if="currentReportConfig?.isApproval && isCanSubmitToAudit"
  605. type="danger"
  606. @click="handleSubmitAudit"
  607. :disabled="checkerIsLoginUser"
  608. size="small"
  609. >
  610. 提交报告审核
  611. </el-button>
  612. <!-- 没有审核只有审批 -->
  613. <el-button
  614. v-if="
  615. currentReportConfig?.isRatify &&
  616. !currentReportConfig?.isApproval &&
  617. isCanSubmitToAudit
  618. "
  619. type="danger"
  620. @click="handleApprovalSelectConfirm"
  621. :disabled="checkerIsLoginUser"
  622. size="small"
  623. >
  624. 提交报告审批
  625. </el-button>
  626. </template>
  627. <!-- 非独审报告默认显示审核按钮 -->
  628. <el-button
  629. v-if="
  630. selectedItem.reportType !== PressureReportType.SUB &&
  631. selectedItem.reportType !== PressureReportType.SINGLE &&
  632. isCanSubmitToAudit &&
  633. 'BoilerCheckerTaskDetail' === routeName
  634. "
  635. type="danger"
  636. @click="handleSubmitAudit"
  637. :disabled="checkerIsLoginUser"
  638. size="small"
  639. >
  640. {{ selectedItem.reportType === PressureReportType['SUGGUESTION'] ? '提交审核' : '提交报告审核' }}
  641. </el-button>
  642. <el-button
  643. v-if="selectedItem.reportType === PressureReportType.SUB && selectedItem.taskStatus == PressureCheckerMyTaskStatus.REPORT_INPUT "
  644. type="danger"
  645. @click="handleCompletion"
  646. :disabled="checkerIsLoginUser"
  647. size="small"
  648. >
  649. 报告办结
  650. </el-button>
  651. <el-button type="primary" size="small" plain v-if="isCanEditReport" @click="handleEditRreport" :disabled="checkerIsLoginUser"
  652. >编制报告</el-button>
  653. <el-button v-if="isCanSubmitRecheck" type="primary" @click="handleSelectVerfiyer" :disabled="checkerIsLoginUser" size="small"
  654. >提交校核</el-button>
  655. <el-button
  656. type="primary"
  657. v-if="isCanEditTestRecord"
  658. plain
  659. @click="handleEditSpreadRecord"
  660. :disabled="checkerIsLoginUser"
  661. size="small"
  662. >{{ selectedItem.reportType === PressureReportType['SUGGUESTION'] ? '编制意见书' : '填写记录' }}</el-button>
  663. </template>
  664. </div>
  665. </Teleport>
  666. <AssociationOperationManual
  667. v-if="showAssociationOperationManual"
  668. :selectedItem="selectedItem"
  669. :reportList="reportList"
  670. :equipCode="props.taskOrderItem?.equipCode"
  671. @close="()=>{
  672. showAssociationOperationManual = false
  673. handleRefresh()
  674. }"
  675. />
  676. </template>
  677. <script setup lang="tsx">
  678. import SmartTable from '@/components/SmartTable/SmartTable'
  679. import { computed, ref, watch } from 'vue'
  680. import { useRouter, useRoute } from 'vue-router'
  681. import { InfoFilled, View, Back, Right, WarningFilled } from '@element-plus/icons-vue'
  682. import { dayjs, ElMessage, ElMessageBox } from 'element-plus'
  683. const CustomDialog = defineAsyncComponent(() => import('@/components/CustomDialog/index.vue'))
  684. import VuePdfEmbed from 'vue-pdf-embed'
  685. import { getReportAllowedApplyModify, getReportCheckPdf } from '@/api/laboratory/functional/report'
  686. import * as UserApi from '@/api/system/user'
  687. import {
  688. PressureCheckerMyTaskStatusMap,
  689. PressureCheckerMyTaskStatus,
  690. PressureReportType,
  691. PressureTaskOrderTaskStatus,
  692. } from '@/utils/constants'
  693. import type {
  694. ReportItemVO,
  695. BoilerTaskOrderDetailVO,
  696. BoilerTaskOrderOrderItemVO
  697. } from '@/api/pressure2/boilertaskorder'
  698. import InspectionItemProgress from './InspectionItemProgress.vue'
  699. import InlineEditCheckRecord from './InlineEditCheckRecord.vue'
  700. import InlinePdfViewer from './InlinePdfViewer.vue'
  701. import InlineInspectionResultInput from './InlineInspectionResultInput.vue'
  702. import InlineReportEdit from './InlineReportEdit.vue'
  703. import { BoilerTaskOrderApi } from '@/api/pressure2/boilertaskorder'
  704. import { defineAsyncComponent } from 'vue'
  705. import UserSelectForm from '@/components/UserSelectForm/index.vue'
  706. import { reportInfoApi } from '@/api/reportInfoService'
  707. import { buildFileUrl } from '@/utils'
  708. import { useUserStore } from '@/store/modules/user'
  709. const AuditUserDialog = defineAsyncComponent(
  710. () => import('@/views/Functional/components/AuditUserDialog.vue')
  711. )
  712. import { is } from '@/utils/is'
  713. import _ from 'lodash'
  714. import { uploadFile } from '@/api/common/index'
  715. import ReportListUploadModal from './reportListUploadModal.vue'
  716. import AssociationOperationManual from './AssociationOperationManual.vue'
  717. import {DynamicTbInsApi} from "@/api/pressure2/dynamictbins";
  718. import {SpreadViewer} from "@/components/DynamicReport";
  719. import {InitParams} from "@/components/DynamicReport/SpreadInterface";
  720. import { cloneDeep, debounce } from 'lodash-es'
  721. import {PipeTaskOrderApi} from "@/api/pressure2/pipetaskorder";
  722. interface Props {
  723. selectedItem: ReportItemVO | null
  724. taskInfo: BoilerTaskOrderDetailVO | null
  725. taskOrderItem: BoilerTaskOrderOrderItemVO
  726. isAuditMode?: boolean
  727. reportId?: string | null
  728. reportList?: ReportItemVO[]
  729. taskId: string
  730. teleportBtnRef: Ref<HTMLDivElement | null>
  731. }
  732. interface Emits {
  733. (e: 'refresh'): void
  734. (e: 'template-confirm', templateUrl?: string): void
  735. (e: 'modify-checker', item: ReportItemVO): void
  736. (e: 'submit-approval'): void
  737. (e: 'reject'): void
  738. (e: 'cancel'): void
  739. (e: 'submit-ratify'): void
  740. (e: 'update:selected-item', item: ReportItemVO): void
  741. }
  742. const props = defineProps<Props>()
  743. const emit = defineEmits<Emits>()
  744. const route = useRoute()
  745. const userStore = useUserStore()
  746. const schemaFlag = ref<string | null>(null) //等于proofread = 校核 audit=审核
  747. // 获取当前的路由Name
  748. const routeName = computed(() => route.name)
  749. const form = ref<Record<string, any>>({
  750. recheckUser: {}
  751. })
  752. const refreshPdf = ref(true)
  753. // 视图模式状态管理
  754. const viewMode = ref<'normal' | 'inspection-result'>('normal')
  755. // 批量提交的表单
  756. const batchRecheckForm = ref({
  757. reportIds: [],
  758. recheckUser: {}
  759. })
  760. const batchRecheckFormRules = {
  761. reportIds: [{required: true, message: '请选择提交记录', trigger: 'change'}],
  762. recheckUser: [{required: true, message: '请选择校核人', trigger: 'change'}]
  763. }
  764. const batchRecheckFormRef = ref()
  765. // const isShowReportPdf = ref([PressureCheckerMyTaskStatus.REPORT_INPUT,PressureCheckerMyTaskStatus.REPORT_AUDIT,PressureCheckerMyTaskStatus.REPORT_APPROVE,PressureCheckerMyTaskStatus.REPORT_END].includes(props.selectedItem.taskStatus)
  766. // && ![400,500,600,700].includes(props.selectedItem.reportType))
  767. const showReportPdfType = ref('record')
  768. const refreshPdfFlag = ref(true)
  769. // const pdfPanelRef = ref<HTMLElement | null>(null)
  770. const hasRecord = ref(true)
  771. const hasReport = ref(true)
  772. // 格式化记录结果状态显示
  773. const formatRecordResult = (record) => {
  774. const resultMap = {
  775. 100: '通过',
  776. 200: '拒绝',
  777. 300: '已阅',
  778. 400: '同意',
  779. 500: '不同意'
  780. }
  781. return resultMap[record.result] || record.result || '-'
  782. }
  783. // 获取记录结果的按钮类型
  784. const getRecordResultButtonType = (record) => {
  785. if ([100, 300, 400].includes(record.result)) {
  786. return 'success'
  787. } else if ([200, 500].includes(record.result)) {
  788. return 'danger'
  789. } else {
  790. return 'default'
  791. }
  792. }
  793. const reportSpreadRef=ref();
  794. const spreadRef=ref();
  795. const initData=ref<InitParams>(
  796. {
  797. templateId: '',
  798. refId: '',
  799. refName:'',
  800. insId:'',
  801. opType: 0, // 0:excel,1: pdf
  802. manualUrl: '',
  803. });
  804. const editSpreadRecordRef=ref();
  805. const editSpreadReportRef=ref();
  806. const editData=ref<InitParams>(
  807. {
  808. templateId: '',
  809. refId: '',
  810. refName:'',
  811. insId:'',
  812. opType: 0, // 0:excel,1: pdf
  813. manualUrl: '',
  814. });
  815. const reportInitData=ref<InitParams>(
  816. {
  817. templateId: '',
  818. refId: '',
  819. refName:'',
  820. insId:'',
  821. opType: 1, // 0:excel,1: pdf
  822. });
  823. // 获取可以批量提交的报告
  824. const getCanSubmitRecheckReport = computed(() => {
  825. if(!props.reportList || !props.reportList.length) return []
  826. return props.reportList.filter((report: any) => {
  827. // 主报告、子报告、独审报告才有记录校核
  828. const reportTypes = [PressureReportType['SUB'], PressureReportType['SINGLE']]
  829. const status = PressureTaskOrderTaskStatus['RECORD_INPUT'] // 记录录入状态
  830. // report.reportUrl 已经录入数据
  831. // if(report.taskStatus !== status || !report.reportUrl) return false
  832. if(report.taskStatus !== status) return false
  833. else if(report.reportType === PressureReportType['MAIN'] && userStore.user.id === props.taskOrderItem?.mainCheckerUser?.id) return true
  834. else
  835. return reportTypes.includes(report.reportType) && (report.checkUsers?.[0]?.id === userStore.user.id || !report.checkUsers || !report.checkUsers.length)
  836. // 过滤掉主报告存在未办结检验意见通知书时
  837. }).filter((report: any) => {
  838. if(report.reportType !== PressureReportType['MAIN']){
  839. return true
  840. }
  841. const sugguestionReport = props.reportList?.find(x => x.reportType === PressureReportType['SUGGUESTION'])
  842. // 不存在检验意见通知书返回true
  843. if(!sugguestionReport) return true
  844. // 检验意见通知书已办结,返回true
  845. return sugguestionReport.taskStatus === PressureCheckerMyTaskStatus['REPORT_END'];
  846. })
  847. })
  848. // 当意见通知书未办结时,主报告不能流转到后续流程(提交校核)
  849. const canSubmitMainReportType = (tipsText: string)=>{
  850. // 不是主报告,直接返回true
  851. if(PressureReportType.MAIN !== props?.selectedItem?.reportType) return true
  852. // 判断检验意见通知书的状态
  853. const report = props.reportList?.find(x => x.reportType === PressureReportType['SUGGUESTION'])
  854. console.log('检验意见通知书', report)
  855. // 不存在检验意见通知书返回true
  856. if(!report) return true
  857. // 检验意见通知书已办结,返回true
  858. if(report.taskStatus === PressureCheckerMyTaskStatus['REPORT_END']) return true
  859. ElMessageBox.alert(tipsText, '提示', {
  860. showCancelButton: false,
  861. confirmButtonText: '确定',
  862. type: 'warning'
  863. })
  864. return false
  865. }
  866. // 校核人选择对话框状态
  867. const showBatchSubmitToRecheckDialog = ref(false)
  868. const isShowAuditDialog = ref(false)
  869. const handleSelectVerfiyer = async () => {
  870. const canSubmit = canSubmitMainReportType('该报告存在未办结检验意见通知书,无法提交校核')
  871. if(!canSubmit) return
  872. // 获取审核人\校核人配置信息
  873. let res = await UserApi.getApprovalDetail({})
  874. // 如果存在多份待提交校核的报告,执行批量校核弹窗
  875. if(getCanSubmitRecheckReport.value.length > 1) {
  876. if(res && res.recheckUser) {
  877. batchRecheckForm.value.recheckUser = res.recheckUser
  878. }
  879. batchRecheckForm.value.reportIds = getCanSubmitRecheckReport.value.map(x => x?.id)
  880. showBatchSubmitToRecheckDialog.value = true
  881. return
  882. }
  883. // 只有一份待提交校核的报告,执行以下逻辑
  884. if(res && res.recheckUser) {
  885. form.value.recheckUser = res.recheckUser
  886. }
  887. schemaFlag.value = 'proofread'
  888. isShowAuditDialog.value = true
  889. }
  890. // const handleAuditSelectConfirm = async (res: any) => {
  891. // console.log('handleAuditSelectConfirm', res)
  892. // if (!props.selectedItem || !res[0]) {
  893. // return
  894. // }
  895. // const saveResult = await BoilerTaskOrderApi.submitTaskReportTemplate({
  896. // id: props.selectedItem.id,
  897. // recheckId: res[0]
  898. // })
  899. // if (saveResult) {
  900. // ElMessage.success('提交校核成功!')
  901. // // 这里可以做页面刷新
  902. // emit('template-confirm')
  903. // }
  904. // }
  905. // 批量提交
  906. const handleBatchSubmitToRecheck = async () => {
  907. try {
  908. await batchRecheckFormRef.value.validate()
  909. } catch (err) {
  910. ElMessage.error('请完善表单数据!')
  911. return
  912. }
  913. // 待提交的数据
  914. const params = {
  915. reportList: getCanSubmitRecheckReport.value.filter((x: any) => batchRecheckForm.value.reportIds.includes(x?.id)).map((x: any) => ({
  916. id: x.id,
  917. reportUrl: x.reportUrl,
  918. dataJson: x?.prepareJson
  919. })),
  920. recheckId: batchRecheckForm.value.recheckUser?.id
  921. }
  922. const submitResult = await BoilerTaskOrderApi.batchSubmitToRecheck(params)
  923. if (submitResult) {
  924. ElMessage.success('提交校核成功!')
  925. showBatchSubmitToRecheckDialog.value = false
  926. selectNextItem(getCanSubmitRecheckReport.value.filter((x: any) => batchRecheckForm.value.reportIds.includes(x?.id)))
  927. // 这里可以做页面刷新
  928. emit('template-confirm')
  929. }
  930. }
  931. const submitting = ref(false)
  932. const handleAuditSelectConfirm = async () => {
  933. if (_.isEmpty(form.value.recheckUser)) {
  934. return ElMessage.error(schemaFlag.value == 'proofread' ? '请选择校核人' : '请选择审核人')
  935. }
  936. // 审核
  937. if (schemaFlag.value === 'audit') {
  938. submitting.value = true
  939. const submitResult = await BoilerTaskOrderApi.submitReportAudit({
  940. id: templateParams.value?.id,
  941. approveId: form.value?.recheckUser?.id
  942. })
  943. submitting.value = false
  944. if (submitResult) {
  945. ElMessage.success('提交审核成功!')
  946. isShowAuditDialog.value = false
  947. selectNextItem([props.selectedItem])
  948. // 这里可以做页面刷新
  949. emit('template-confirm')
  950. }
  951. } else if (schemaFlag.value === 'proofread') {
  952. // 校核
  953. const saveResult = await BoilerTaskOrderApi.submitTaskReportTemplate({
  954. id: props?.selectedItem?.id,
  955. recheckId: form.value?.recheckUser?.id
  956. })
  957. if (saveResult) {
  958. ElMessage.success('提交校核成功!')
  959. isShowAuditDialog.value = false
  960. selectNextItem([props.selectedItem])
  961. // 这里可以做页面刷新
  962. emit('template-confirm')
  963. }
  964. }
  965. }
  966. /**
  967. * 项目切换
  968. */
  969. const selectNextItem = (items:ReportItemVO[]) => {
  970. // 找到其他在记录录入或者报告编制状态的第一项目
  971. const ids = items.map(item => item.id)
  972. const inputReportList= props.reportList.filter(
  973. item => {
  974. return !ids.includes(item.id)
  975. }
  976. ).filter(item =>{
  977. return item.taskStatus === PressureTaskOrderTaskStatus['RECORD_INPUT'] || item.taskStatus === PressureTaskOrderTaskStatus['REPORT_INPUT']
  978. })
  979. console.log(inputReportList)
  980. if (inputReportList.length > 0){
  981. emit('item-select', inputReportList[0])
  982. }
  983. }
  984. // 审批人选择对话框状态
  985. const isShowApprovalDialog = ref(false)
  986. // 监听项目切换,自动重置视图模式
  987. watch(
  988. () => props.selectedItem,
  989. (newItem, oldItem) => {
  990. if (newItem) {
  991. showReportPdfType.value = [PressureCheckerMyTaskStatus.REPORT_INPUT,PressureCheckerMyTaskStatus.REPORT_AUDIT,PressureCheckerMyTaskStatus.REPORT_APPROVE,PressureCheckerMyTaskStatus.REPORT_END].includes(props.selectedItem.taskStatus)
  992. && ![400,500,600,700].includes(props.selectedItem.reportType) ? 'report':'record'
  993. handleRefreshData()
  994. props.taskId && getReportAuditInfo()
  995. hasRecord.value = props.selectedItem.templateId != null
  996. if (props.selectedItem?.reportTemplateId == null){
  997. showReportPdfType.value = 'record'
  998. }
  999. if (props.selectedItem?.templateId == null){
  1000. showReportPdfType.value = 'report'
  1001. }
  1002. }
  1003. // 当切换到不同的项目时,重置视图模式为normal
  1004. if (newItem?.id !== oldItem?.id) {
  1005. viewMode.value = 'normal'
  1006. }
  1007. },
  1008. { immediate: false }
  1009. )
  1010. const previewUrl = ref('')
  1011. const previewVisible = ref(false)
  1012. const previewType = ref('')
  1013. const handlePreview = (path: string, type: 'video' | 'image') => {
  1014. previewUrl.value = path;
  1015. previewType.value = type;
  1016. previewVisible.value = true;
  1017. }
  1018. /**
  1019. * 如果是"已经审核完的检验意见通知书,则查询相关的检验意见通知信息,显示在最右侧
  1020. */
  1021. const checkBookDetail = ref<Record<string, any>>({})
  1022. const showCheckBook = computed(() => {
  1023. const { reportType, taskStatus } = props.selectedItem || {}
  1024. // console.log(taskStatus, 'taskStatus', reportType)
  1025. // taskStatus: 800
  1026. return reportType === PressureReportType['SUGGUESTION']
  1027. })
  1028. const rectificationStatusMap = reactive({
  1029. 0: '待确认',
  1030. 1: '待整改',
  1031. 2: '已递交',
  1032. 3: '材料有误',
  1033. 4: '整改通过',
  1034. 5: '整改不通过'
  1035. })
  1036. const getReportAuditInfo = async () => {
  1037. if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION']) {
  1038. const res = await reportInfoApi.exportCheckBookDetail({
  1039. id: props.taskId
  1040. })
  1041. console.log(res, '查询检验意见通知书详细信息')
  1042. if (res) {
  1043. checkBookDetail.value = res
  1044. }
  1045. }
  1046. }
  1047. const returnForm = ref({
  1048. rejectionReason: ''
  1049. })
  1050. const returnFormRules = ref({
  1051. rejectionReason: [{ required: true, message: '请输入回退原因', trigger: 'blur' }]
  1052. })
  1053. const returnFormRef = ref()
  1054. const isCompleteInput = computed(() => {
  1055. return props.selectedItem?.taskStatus >= PressureCheckerMyTaskStatus.RECORD_CHECK
  1056. })
  1057. const isShowRecordOrReportBtn = computed(() => {
  1058. return [PressureReportType.MAIN,PressureReportType.SUB,PressureReportType.SINGLE].includes(props.selectedItem?.reportType)
  1059. })
  1060. // 通过 退回
  1061. const handlePass = async (type) => {
  1062. const params: Record<string, any> = {
  1063. reportId: props.selectedItem?.id,
  1064. approvalType: type
  1065. }
  1066. if (type === 1) {
  1067. const valid = await returnFormRef.value.validate()
  1068. if (!valid) return
  1069. params.rejectionReason = returnForm.value.rejectionReason
  1070. }
  1071. const tipText = type === 1 ? '退回' : type === 2 ? '整改不通过' : '整改通过'
  1072. ElMessageBox.confirm(`确定${tipText}吗?`, '提示', {
  1073. confirmButtonText: '确定',
  1074. cancelButtonText: '取消',
  1075. type: 'warning'
  1076. }).then(() => {
  1077. BoilerTaskOrderApi.inspectionApproval(params).then((res) => {
  1078. props.taskId && getReportAuditInfo()
  1079. emit('refresh')
  1080. }).catch(() => {
  1081. ElMessage.error('操作失败')
  1082. })
  1083. })
  1084. }
  1085. // 获取检验员名称
  1086. const getCheckersName = (): string => {
  1087. if (!props.selectedItem?.checkUsers || props.selectedItem.checkUsers.length === 0) {
  1088. return '未分配'
  1089. }
  1090. return props.selectedItem.checkUsers.map((user) => user.nickname).join('、')
  1091. }
  1092. // 切换主检人
  1093. const handleUserSelect = async (id, userList) => {
  1094. const result = await BoilerTaskOrderApi.updateReportMainChecker({
  1095. id: props.taskOrderItem?.id,
  1096. mainChecker: userList[0]?.id
  1097. })
  1098. if (result) {
  1099. ElMessage.success('修改主检人成功!')
  1100. emit('refresh')
  1101. }
  1102. }
  1103. const userSelectFormRef = ref()
  1104. const handleModifyMainChecker = () => {
  1105. userSelectFormRef.value.open(props.taskOrderItem?.mainCheckerUser?.id)
  1106. }
  1107. // 判断当前检验员或主检人是否为登录用户,如果不是,则功能按钮disabled
  1108. const checkerIsLoginUser = computed(() => {
  1109. const checkerUserIds = props.selectedItem?.checkUsers.map(checker => checker?.id)
  1110. return !(checkerUserIds?.includes(userStore?.user?.id) || props.taskOrderItem?.mainCheckerUser?.id === userStore?.user?.id)
  1111. })
  1112. // 判断当前项目是否已经到报告办结阶段
  1113. const getReportStatusEnd = computed(
  1114. () =>{
  1115. return props.selectedItem && props.selectedItem.taskStatus >= PressureCheckerMyTaskStatus['REPORT_CONFIRMATION']
  1116. }
  1117. )
  1118. // 判断“提交校核”按钮是否显示
  1119. const isCanSubmitRecheck = computed(() => {
  1120. if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION'])
  1121. return props.selectedItem?.isRecheck || false
  1122. else if (props.selectedItem?.reportType === PressureReportType['MAINQUESTION']) return false
  1123. else
  1124. return (
  1125. props.selectedItem &&
  1126. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT']
  1127. // && props.selectedItem.reportUrl
  1128. )
  1129. })
  1130. // 判断“提交审核&提交审批”按钮是否显示
  1131. const isCanSubmitToAudit = computed(() => {
  1132. const { selectedItem } = props
  1133. if (selectedItem && selectedItem?.reportType === PressureReportType['SUBCONTRACT']){
  1134. return selectedItem.taskStatus === PressureCheckerMyTaskStatus['CONFIRMED']
  1135. }
  1136. if (props.selectedItem && props.selectedItem?.reportType === PressureReportType['SUGGUESTION'])
  1137. return (
  1138. props.selectedItem?.isApproval &&
  1139. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT']
  1140. )
  1141. else if (
  1142. props.selectedItem &&
  1143. props.selectedItem?.reportType === PressureReportType['MAINQUESTION']
  1144. )
  1145. return (
  1146. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT'] &&
  1147. props.selectedItem?.reportUrl
  1148. )
  1149. else
  1150. return (
  1151. props.selectedItem &&
  1152. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['REPORT_INPUT']
  1153. )
  1154. })
  1155. // 判断“填写记录”按钮是否显示
  1156. const isCanEditTestRecord = computed(
  1157. () =>
  1158. props.selectedItem &&
  1159. (props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT'] ||
  1160. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['CONFIRMED']) && props.selectedItem.reportType !== PressureReportType['SUBCONTRACT']
  1161. )
  1162. // 判断“编制报告”按钮是否显示
  1163. const isCanEditReport = computed(
  1164. () =>
  1165. props.selectedItem &&
  1166. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['REPORT_INPUT']
  1167. )
  1168. // 判断“填写结果”按钮是否显示
  1169. const isCanEditRecordResult = computed(() => {
  1170. // 非我的任务详情页面,不显示
  1171. if ('BoilerCheckerTaskDetail' !== routeName.value) return false
  1172. if (!props.selectedItem?.isAutoAmount || props.selectedItem?.isAutoAmount === '0') return false
  1173. if (
  1174. (props.selectedItem?.reportType === 100 || props.selectedItem?.reportType === 300) &&
  1175. props.selectedItem.taskStatus !== PressureCheckerMyTaskStatus['REPORT_END']
  1176. ) {
  1177. // 独审报告&主报告--“填写结果”:报告办结之前都可以填写
  1178. return true
  1179. }
  1180. // 查找主报告
  1181. const mainReport = props.reportList?.find((item) => item.reportType === 100) || {
  1182. taskStatus: null
  1183. }
  1184. if (
  1185. props.selectedItem?.reportType !== 100 &&
  1186. props.selectedItem?.reportType !== 300 &&
  1187. mainReport?.taskStatus !== PressureCheckerMyTaskStatus['REPORT_END']
  1188. ) {
  1189. // 非主报告 & 非独审报告 -- “填写结果”:主报告办结之前都可以填写
  1190. return true
  1191. }
  1192. return false
  1193. })
  1194. // 1、重大问题线索告知表 2、作业指导书 3、检验方案 只显示pdf
  1195. const onlyShowPdf = computed(() => {
  1196. const reportTypes = [
  1197. PressureReportType.MAINQUESTION,
  1198. PressureReportType.INSPECTIONPLAN,
  1199. PressureReportType.WORKINSTRUCTION
  1200. ]
  1201. return !props.selectedItem?.reportType
  1202. ? false
  1203. : reportTypes.includes(props.selectedItem?.reportType)
  1204. })
  1205. // 模板参数
  1206. const templateParams = computed(() => {
  1207. if (!props.selectedItem) return {}
  1208. return {
  1209. ...props.selectedItem,
  1210. equipCode: props.taskOrderItem?.equipCode || '',
  1211. equipId: props.taskOrderItem?.id || ''
  1212. }
  1213. })
  1214. // 判断是否为独审报告且不需要审批
  1215. const isApprovalWithoutRatify = computed(() => {
  1216. if (!props.selectedItem) return false
  1217. const reportType = (props.selectedItem as any).reportType
  1218. const isApproval = (props.selectedItem as any).isApproval
  1219. const isRatify = (props.selectedItem as any).isRatify
  1220. return (
  1221. reportType === PressureReportType.SINGLE &&
  1222. isApproval === true &&
  1223. isRatify === false &&
  1224. props.reportId === props.selectedItem.id
  1225. )
  1226. })
  1227. /**** 葡萄城:记录录入的显示和隐藏 ****/
  1228. const showInlineEditCheckRecord = ref(false)
  1229. const templateId = ref('')
  1230. const handleEditSpreadRecord = () => {
  1231. // console.log('templateParams', templateParams.value)
  1232. // DynamicTbInsApi.getOrCreatePreviewData('dc8fbb6078b2a2f0eadc0f6aedbeafa0').then(res => {
  1233. // showInlineEditCheckRecord.value = true
  1234. // templateId.value = res.id
  1235. // })
  1236. editPreview('record')
  1237. showInlineEditCheckRecord.value = true
  1238. }
  1239. const handleTemplateConfirm = (templateUrl: string) => {
  1240. console.log('templateUrl', templateUrl)
  1241. emit('template-confirm', templateUrl)
  1242. }
  1243. const handleRefresh = () => {
  1244. emit('refresh')
  1245. }
  1246. /**** 葡萄城:记录录入的显示和隐藏 end****/
  1247. /**** 葡萄城:检验结果录入的显示和隐藏 ****/
  1248. const showInlineInspectionResultInput = ref(false)
  1249. const inspectionResultTemplateParams = ref({})
  1250. // 检验结果录入模板参数
  1251. const handleInputCheckConclusion = () => {
  1252. showInlineInspectionResultInput.value = true
  1253. if (!props.selectedItem) return {}
  1254. inspectionResultTemplateParams.value = {
  1255. ...props.selectedItem,
  1256. equipCode: props.taskOrderItem?.equipCode || ''
  1257. }
  1258. }
  1259. const handleInspectionResultConfirm = (resultUrl: string) => {
  1260. emit('template-confirm', resultUrl)
  1261. viewMode.value = 'normal'
  1262. }
  1263. const handleReturnToNormalMode = () => {
  1264. viewMode.value = 'normal'
  1265. }
  1266. /**** 葡萄城:检验结果录入的显示和隐藏 end ****/
  1267. /**** 葡萄城:报告编制的显示和隐藏 ****/
  1268. const showInlineReportEdit = ref(false)
  1269. const handleEditRreport = () => {
  1270. if (showReportPdfType.value !== 'report' && showReportPdfType.value !== 'result'){
  1271. ElMessage.warning('请切换报告后再进行报告编制!')
  1272. return
  1273. }
  1274. editPreview('report')
  1275. showInlineReportEdit.value = true
  1276. }
  1277. // 获取当前报告的配置信息
  1278. const currentReportConfig = computed(() => {
  1279. if (
  1280. !props.selectedItem ||
  1281. props.selectedItem.reportType !== PressureReportType.SINGLE ||
  1282. !props.reportList
  1283. ) {
  1284. return null
  1285. }
  1286. // 从reportList中找到当前报告的配置
  1287. const currentReport = props.reportList.find((report) => report.id === templateParams.value?.id)
  1288. return currentReport
  1289. ? {
  1290. isApproval: (currentReport as any).isApproval,
  1291. isRatify: (currentReport as any).isRatify
  1292. }
  1293. : null
  1294. })
  1295. // 选择报告审核人弹窗的显示和隐藏
  1296. const isShowReportAuditDialog = ref(false)
  1297. // 提交报告审核
  1298. const handleSubmitAudit = async () => {
  1299. if([PressureReportType.SUGGUESTION, PressureReportType.MAINQUESTION].includes(props?.selectedItem?.reportType) && !props?.selectedItem?.reportUrl) {
  1300. // 【重大问题线索告知表,检验意见通知书】必须先填写记录,才能提交审核
  1301. ElMessage.warning('请先“填写记录”!再提交审核!')
  1302. return
  1303. }
  1304. if(PressureReportType.SINGLE === props?.selectedItem?.reportType && !props?.selectedItem?.prepareUrl) {
  1305. // 独审报告:用户可以不走报告编制环节直接提交审核,需要调用handleUploadAPIReportPreviewBlob将reportPreview接口的文件流拿来提交一遍
  1306. return handleUploadAPIReportPreviewBlob(handleSubmitAudit)
  1307. }
  1308. // 检查检验意见通知书是否“报告完结”
  1309. const canSubmit = canSubmitMainReportType('该报告存在未办结检验意见通知书,无法提交审核、审批')
  1310. if(!canSubmit) return
  1311. // 检查其他报告状态
  1312. const checkResult = checkOtherReportsFinished()
  1313. if (!checkResult.canSubmit) {
  1314. try {
  1315. await ElMessageBox.alert(
  1316. checkResult.message || '请先办结其他报告再提交主报告审核',
  1317. '无法提交审核'
  1318. )
  1319. } catch (error) {
  1320. // 用户关闭对话框,不需要处理
  1321. }
  1322. return
  1323. }
  1324. // if(PressureReportType.MAIN === props?.selectedItem?.reportType && !props?.selectedItem?.prepareUrl) {
  1325. // // 主报告:用户可以不走报告编制环节直接提交审核,需要调用handleUploadAPIReportPreviewBlob将reportPreview接口的文件流拿来提交一遍
  1326. // return handleUploadAPIReportPreviewBlob(handleSubmitAudit)
  1327. // }
  1328. // 检验意见通知书 && 重大问题线索通知 不需要选择审核人
  1329. if (
  1330. [PressureReportType['SUGGUESTION'], PressureReportType['MAINQUESTION']].includes(
  1331. templateParams.value?.reportType
  1332. )
  1333. ) {
  1334. ElMessageBox.confirm(`确定提交【${templateParams.value?.reportName}】`, '提示', {
  1335. confirmButtonText: '确定',
  1336. cancelButtonText: '取消'
  1337. })
  1338. .then(async () => {
  1339. const submitResult = await BoilerTaskOrderApi.submitOpinionNoticeApproval({
  1340. id: templateParams.value?.id
  1341. })
  1342. if (submitResult) {
  1343. // 这里可以做页面刷新
  1344. emit('template-confirm')
  1345. }
  1346. })
  1347. .catch(() => {
  1348. console.log('用户取消提交审核')
  1349. })
  1350. } else {
  1351. let res = await UserApi.getApprovalDetail({}) // 判断是否有审批信息
  1352. if (res && res.approveUser) {
  1353. form.value.recheckUser = res.approveUser
  1354. }
  1355. schemaFlag.value = 'audit'
  1356. isShowAuditDialog.value = true
  1357. // isShowReportAuditDialog.value = true
  1358. }
  1359. }
  1360. const handleCompletion = async () => {
  1361. await BoilerTaskOrderApi.handleCompletion(props.selectedItem.id)
  1362. handleRefresh()
  1363. ElMessage.success('报告已办结')
  1364. }
  1365. const getRecheckUserList = async (params) => {
  1366. params.orderId = props.taskInfo.id
  1367. return await BoilerTaskOrderApi.getRecheckUserList(params)
  1368. }
  1369. // 上传主报告文件流
  1370. const handleUploadAPIReportPreviewBlob = async (submitApprovalFn) => {
  1371. if(!props.selectedItem || props.selectedItem.taskStatus !== PressureTaskOrderTaskStatus.REPORT_INPUT) return
  1372. // 获取文件流
  1373. const blob = await BoilerTaskOrderApi.getReportPreview({
  1374. reportId: props.selectedItem?.id,
  1375. type: 300, // 报告模板
  1376. fileType: 100 // xlsx
  1377. })
  1378. if(blob) {
  1379. // 上传文件流
  1380. const formData = new FormData()
  1381. formData.append('file', blob)
  1382. const response = await uploadFile(formData)
  1383. // 保存报告编制的url
  1384. const saveResult = await BoilerTaskOrderApi.saveReportPrepare({
  1385. id: props.selectedItem.id,
  1386. prepareUrl: response,
  1387. })
  1388. if(saveResult) {
  1389. await emit('update:selected-item', {...props.selectedItem, prepareUrl: response})
  1390. // 提交审核
  1391. await submitApprovalFn()
  1392. }
  1393. }
  1394. }
  1395. const handleChangeEntrustUnit = (unit: Record<string, any>) => {
  1396. form.value.recheckUser = unit
  1397. }
  1398. // 检查其他报告是否已办结
  1399. const checkOtherReportsFinished = (): { canSubmit: boolean; message?: string } => {
  1400. if (!props.selectedItem) return { canSubmit: false }
  1401. // 如果不是主报告,直接允许提交
  1402. if (props.selectedItem.reportType !== PressureReportType.MAIN) {
  1403. return { canSubmit: true }
  1404. }
  1405. // 主报告需要检查其他报告状态
  1406. const unfinishedReports = !props.reportList
  1407. ? []
  1408. : props.reportList.filter((report) => {
  1409. // 排除当前报告
  1410. if (report.id === templateParams.value?.id) {
  1411. return false
  1412. }
  1413. // 检查子报告和独审报告是否已办结
  1414. const isSubReport = report.reportType === PressureReportType.SUB
  1415. const isSingleReport = report.reportType === PressureReportType.SINGLE
  1416. const isSUGGUESTIONReport = report.reportType === PressureReportType.SUGGUESTION
  1417. if (isSubReport || isSingleReport || isSUGGUESTIONReport) {
  1418. return report.taskStatus !== PressureCheckerMyTaskStatus.REPORT_END
  1419. }
  1420. return false
  1421. })
  1422. if (unfinishedReports.length > 0) {
  1423. const unfinishedNames = unfinishedReports.map((report) => report.reportName).join('、')
  1424. return {
  1425. canSubmit: false,
  1426. message: `请先办结其他报告再提交主报告审核。未办结的报告:${unfinishedNames}`
  1427. }
  1428. }
  1429. // 检查是否确认费用
  1430. // const reportsWithoutConfirmFee: any[] = []
  1431. // 检查当前报告中是否存在应确认费用,但未确认的报错
  1432. const reportsWithoutConfirmFee: any[] = !props.reportList
  1433. ? []
  1434. : props.reportList.filter(
  1435. (report: any) => report.isAutoAmount === '1' && report.feeConfirm === false
  1436. )
  1437. // if (currentReport) {
  1438. // reportsWithoutConfirmFee.push(currentReport)
  1439. // }
  1440. // 检查子报告是否都已录入结果
  1441. // const subReports = !props.reportList ? [] : props.reportList.filter(report => {
  1442. // return report.id !== templateParams.value?.id &&
  1443. // report.reportType === PressureReportType.SUB
  1444. // })
  1445. // subReports.forEach(report => {
  1446. // if (!report.formulaJson) {
  1447. // reportsWithoutConfirmFee.push(report)
  1448. // }
  1449. // })
  1450. if (reportsWithoutConfirmFee.length > 0) {
  1451. const reportNames = reportsWithoutConfirmFee.map((report) => report.reportName).join('、')
  1452. return {
  1453. canSubmit: false,
  1454. message: `请先确认费用再提交主报告审核。未确认费用的报告:${reportNames}`
  1455. }
  1456. }
  1457. return { canSubmit: true }
  1458. }
  1459. // 报告审核人选择确认
  1460. const handleReportAuditSelectConfirm = async (res: any) => {
  1461. const approveId = res[0]
  1462. const submitResult = await BoilerTaskOrderApi.submitReportAudit({
  1463. id: templateParams.value?.id,
  1464. approveId
  1465. })
  1466. if (submitResult) {
  1467. // 这里可以做页面刷新
  1468. emit('template-confirm')
  1469. }
  1470. isShowReportAuditDialog.value = false
  1471. }
  1472. /**** 葡萄城:报告编制的显示和隐藏 end ****/
  1473. const handleModifyChecker = () => {
  1474. if (props.selectedItem) {
  1475. emit('modify-checker', props.selectedItem)
  1476. }
  1477. }
  1478. // 审批人选择确认
  1479. const handleApprovalSelectConfirm = async (res: any) => {
  1480. if (!props.selectedItem || !res || res.length === 0) {
  1481. ElMessage.warning('请选择审批人')
  1482. return
  1483. }
  1484. const ratifyId = res[0] // 获取选中的审批人ID
  1485. try {
  1486. await BoilerTaskOrderApi.submitReportApprove({
  1487. id: props.selectedItem.id,
  1488. ratifyId: ratifyId
  1489. })
  1490. ElMessage.success('提交审批成功')
  1491. isShowApprovalDialog.value = false
  1492. emit('submit-approval')
  1493. } catch (error: any) {
  1494. console.error('提交审批失败:', error)
  1495. ElMessage.error('提交审批失败,请稍后重试')
  1496. isShowApprovalDialog.value = false
  1497. }
  1498. }
  1499. // 加载流转记录列表
  1500. const recordList = ref<any[]>([])
  1501. const recordListLoading = ref(false)
  1502. const loadRecordList = async () => {
  1503. if (!props.selectedItem) return
  1504. try {
  1505. let response = null
  1506. // 检验意见通知书&重大问题线索
  1507. switch (props.selectedItem.reportType) {
  1508. case PressureReportType['SUGGUESTION']:
  1509. case PressureReportType['MAINQUESTION']:
  1510. response = await BoilerTaskOrderApi.getOpinionNoticeApprovalRecordList({
  1511. id: props.selectedItem.id
  1512. })
  1513. break
  1514. default:
  1515. // 其他
  1516. response = await BoilerTaskOrderApi.getTaskOrderItemReportRecordPage({
  1517. pageSize: 10,
  1518. pageNo: 1,
  1519. reportId: props.selectedItem.id
  1520. })
  1521. }
  1522. // 根据实际接口返回的数据结构获取数据
  1523. recordList.value = response?.data?.list || response?.list || response || []
  1524. } catch (error: any) {
  1525. console.error('获取流转记录失败:', error)
  1526. ElMessage.error('获取流转记录失败,请稍后重试')
  1527. recordList.value = []
  1528. } finally {
  1529. recordListLoading.value = false
  1530. }
  1531. }
  1532. // 获取报告字段纠错列表
  1533. const checkInputList = ref<any[]>([])
  1534. const handleGetCheckKeyInputs = async () => {
  1535. checkInputList.value = []
  1536. //if (!dataJson) return
  1537. if (!props.selectedItem?.id) return ElMessage.warning('字段纠错传参有误')
  1538. let reportId = props.selectedItem?.id
  1539. // const templateId = isShowReportPdf.value? props.selectedItem?.reportTemplateId : props.selectedItem?.templateId;
  1540. // if (isShowReportPdf.value){
  1541. // reportId = "report_" + reportId;
  1542. // }
  1543. let templateId = showReportPdfType.value === 'report' ? props.selectedItem?.reportTemplateId :
  1544. showReportPdfType.value === 'result' ? props.selectedItem?.resultTemplateId : props.selectedItem?.templateId;
  1545. if (showReportPdfType.value === 'report'){
  1546. reportId = "report_" + reportId;
  1547. }else if (showReportPdfType.value === 'result'){
  1548. reportId = "result_" + reportId;
  1549. }
  1550. const response = await BoilerTaskOrderApi.getCheckKeyIsInput(
  1551. { id: templateId,reportId: reportId },
  1552. JSON.parse("{}")
  1553. )
  1554. //console.log(JSON.parse(dataJson))
  1555. if (response) checkInputList.value = formatCheckInputList(response)
  1556. }
  1557. function formatCheckInputList(response, checkInputList = [] as any[]) {
  1558. if (!response) return []
  1559. for (let checkItem of response) {
  1560. if (!checkItem.child) {
  1561. checkInputList.push({ code: checkItem.code, name: checkItem.name })
  1562. }
  1563. if (is(checkItem.child, 'Array') && checkItem.type === 'object') {
  1564. formatCheckInputList(checkItem.child, checkInputList)
  1565. }
  1566. if (is(checkItem.child, 'Array') && checkItem.type === 'array') {
  1567. const childMapper = checkItem.child.map((item, i) => {
  1568. return {
  1569. code: `${checkItem.code}: ${item.code}`,
  1570. name: item.name
  1571. }
  1572. })
  1573. formatCheckInputList(childMapper, checkInputList)
  1574. }
  1575. }
  1576. return checkInputList
  1577. }
  1578. // 获取版本记录列表
  1579. const showVersionDetail = ref(false)
  1580. const historyList = ref<any[]>([])
  1581. async function getOrderHistoryVersion(id: string) {
  1582. try {
  1583. const response = await BoilerTaskOrderApi.getSafetyCheckRecordVersionPage({
  1584. pageNo: 1,
  1585. pageSize: 100,
  1586. businessType: 0,
  1587. orderItemReportId: id
  1588. })
  1589. historyList.value = response.list || []
  1590. } catch (error) {
  1591. console.error('获取历史版本失败:', error)
  1592. ElMessage.error('获取历史版本失败')
  1593. }
  1594. }
  1595. const versionDataCompareList = ref([])
  1596. const versionColumns = ref([
  1597. {
  1598. label: '字段名',
  1599. prop: 'displayName'
  1600. },
  1601. {
  1602. label: '修改前',
  1603. prop: 'oldValue',
  1604. render: (row, value) => (
  1605. <el-text link type="default">
  1606. {value || '-'}
  1607. </el-text>
  1608. )
  1609. },
  1610. {
  1611. label: '修改后',
  1612. prop: 'newValue',
  1613. render: (row, value) => <el-text type="primary">{value || '-'}</el-text>
  1614. }
  1615. ])
  1616. const versionDetailButtons = ref([
  1617. {
  1618. render: () => (
  1619. <el-button type="success" onClick={() => handleShowReportPdf()}>
  1620. 查看原文件PDF
  1621. </el-button>
  1622. )
  1623. }
  1624. ])
  1625. const showReportDialog = ref(false)
  1626. const currentUrl = ref('')
  1627. const reportSource = ref<any | null>(null)
  1628. const pdfLoading = ref(false)
  1629. // 恢复版本
  1630. const restoreVersion = (item: any) => {
  1631. ElMessageBox.confirm('是否确定恢复到该版本?', '提示', {
  1632. confirmButtonText: '确定',
  1633. cancelButtonText: '取消',
  1634. type: 'info',
  1635. center: true
  1636. })
  1637. .then(async () => {
  1638. const result = await BoilerTaskOrderApi.saveTaskReportTemplate({
  1639. id: props.selectedItem?.id,
  1640. reportUrl: item.oldReportUrl,
  1641. prepareJson: item.oldPrepareJson,
  1642. reportType: showReportPdfType.value,
  1643. modifiedReason: '恢复版本'
  1644. })
  1645. console.log('restoreVersion', result)
  1646. if (result) {
  1647. ElMessage({
  1648. type: 'success',
  1649. message: '操作成功'
  1650. })
  1651. handleRefresh()
  1652. } else {
  1653. ElMessage.warning('操作失败,请联系管理员!')
  1654. }
  1655. })
  1656. .catch(() => {})
  1657. }
  1658. // 查看版本详情的pdf
  1659. const handleShowReportPdf = async () => {
  1660. if (currentUrl.value) {
  1661. const reportId = props.selectedItem?.id;
  1662. reportInitData.value.refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1663. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1664. reportInitData.value.templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1665. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1666. reportInitData.value.dataSource = currentUrl.value.oldPrepareJson ? JSON.parse(currentUrl.value.oldPrepareJson) : {}
  1667. console.log(currentUrl)
  1668. showReportDialog.value = true
  1669. setTimeout(()=> {
  1670. reportSpreadRef.value?.reloadView();
  1671. })
  1672. pdfLoading.value = false
  1673. } else {
  1674. ElMessage.warning('报告缺失,请联系管理员!')
  1675. }
  1676. }
  1677. const handlePdfRendered = () => {
  1678. pdfLoading.value = false
  1679. currentUrl.value = ''
  1680. }
  1681. // 查看详情
  1682. const handleShowVersionInfo = (item) => {
  1683. showVersionDetail.value = true
  1684. currentUrl.value = item
  1685. versionDataCompareList.value = JSON.parse(item.modifiedObject)
  1686. }
  1687. // 检验项目添加上传附件功能
  1688. const reportListUploadModalRef = ref<InstanceType<typeof ReportListUploadModal>>()
  1689. const handleUploadItem = () => {
  1690. reportListUploadModalRef.value?.openModal(route.query.type === 'BoilerMyTask')
  1691. }
  1692. //切换记录和报告的显示
  1693. const handleChangeShowReportPdf = (showType: string) => {
  1694. if (showType === 'report' || showType === 'result'){
  1695. if (![PressureCheckerMyTaskStatus.REPORT_INPUT,PressureCheckerMyTaskStatus.REPORT_AUDIT,PressureCheckerMyTaskStatus.REPORT_APPROVE,PressureCheckerMyTaskStatus.REPORT_END].includes(props.selectedItem.taskStatus)){
  1696. ElMessage.error('该检验项目暂未生成报告!')
  1697. showReportPdfType.value = 'record';
  1698. return;
  1699. }
  1700. }
  1701. if (showType === 'result'){
  1702. if (!props.selectedItem?.resultTemplateId){
  1703. ElMessage.error('该检验项目没有结论报告!')
  1704. showReportPdfType.value = 'record';
  1705. return;
  1706. }
  1707. }
  1708. refreshPdfFlag.value = false;
  1709. showReportPdfType.value = showType;
  1710. handleRefreshData()
  1711. }
  1712. const isCanSyncReportData = computed(() => {
  1713. return true
  1714. //return [PressureCheckerMyTaskStatus.CONFIRMED,PressureCheckerMyTaskStatus.RECORD_INPUT].includes(props.selectedItem.taskStatus)
  1715. })
  1716. const handleSyncReportData = async () => {
  1717. try {
  1718. const response = await BoilerTaskOrderApi.syncReportData({
  1719. refId: props.selectedItem.id,
  1720. reportType : showReportPdfType.value
  1721. })
  1722. if (response){
  1723. ElMessage.success('同步数据成功')
  1724. handleRefresh()
  1725. }else{
  1726. ElMessage.error('同步数据失败,请稍后重试')
  1727. }
  1728. } catch (error: any) {
  1729. console.error('同步数据失败:', error)
  1730. ElMessage.error('同步数据失败,请稍后重试')
  1731. }
  1732. }
  1733. const showAssociationOperationManual = ref(false)
  1734. const handleShowAssociationOperationManual = () => {
  1735. showAssociationOperationManual.value = true
  1736. }
  1737. onMounted(() => {
  1738. console.log(props)
  1739. //initPreview()
  1740. })
  1741. const initPreview=()=>{
  1742. const reportId = props.selectedItem?.id;
  1743. const refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1744. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1745. const templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1746. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1747. initData.value.templateId = templateId;
  1748. initData.value.refId = refId;
  1749. initData.value.opType = (props.selectedItem.taskStatus == 510 || props.selectedItem.taskStatus >= 600 || (showReportPdfType.value === 'record' && props.selectedItem.taskStatus > 500) || props?.selectedItem?.checkUsers?.[0]?.id != userStore?.user?.id) ? 1 : 0;
  1750. if (props.selectedItem.reportType === PressureReportType['INSPECTIONPLAN'] && props.selectedItem.manualUrl){
  1751. initData.value.manualUrl = props.selectedItem.manualUrl;
  1752. }else{
  1753. initData.value.manualUrl = '';
  1754. }
  1755. setTimeout(()=>{
  1756. spreadRef.value?.reloadView();
  1757. },50)
  1758. console.log('initPreview', initData.value)
  1759. }
  1760. const editPreview=(reportType: string)=>{
  1761. const reportId = props.selectedItem?.id;
  1762. const refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1763. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1764. const templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1765. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1766. editData.value.templateId = templateId;
  1767. editData.value.refId = refId;
  1768. editData.value.opType = 0;
  1769. setTimeout(()=>{
  1770. if (reportType === 'record'){
  1771. editSpreadRecordRef.value?.reloadView();
  1772. }else if(reportType === 'report'){
  1773. editSpreadReportRef.value?.reloadView();
  1774. }
  1775. },50)
  1776. console.log('editDataPreview', editData.value)
  1777. }
  1778. const saveSuccess = async (data)=>{
  1779. if (props.selectedItem.taskStatus >= PressureCheckerMyTaskStatus.REPORT_INPUT){
  1780. saveSuccessReport(data)
  1781. }else {
  1782. saveSuccessRecord(data)
  1783. }
  1784. }
  1785. const saveSuccessRecord = async (data)=>{
  1786. const dataJson = !data.dataSource ? '' : JSON.stringify(data.dataSource)
  1787. const params = {
  1788. id: props.selectedItem?.id,
  1789. reportUrl: props.selectedItem?.id,
  1790. prepareJson: dataJson
  1791. }
  1792. const saveResult = await BoilerTaskOrderApi.saveTaskReportTemplate(params)
  1793. if (saveResult) {
  1794. showInlineEditCheckRecord.value = false
  1795. handleRefresh()
  1796. }
  1797. }
  1798. const handleClose = () => {
  1799. ElMessageBox.confirm('是否关闭?', {
  1800. confirmButtonText: '确认',
  1801. cancelButtonText: '取消',
  1802. type: 'warning',
  1803. }).then(() => {
  1804. showInlineEditCheckRecord.value = false
  1805. showInlineReportEdit.value = false
  1806. handleRefresh()
  1807. })
  1808. }
  1809. const saveSuccessReport = async (data)=>{
  1810. const dataJson = !data.dataSource ? '' : JSON.stringify(data.dataSource)
  1811. const saveResult = BoilerTaskOrderApi.saveReportPrepare({
  1812. id: props.selectedItem?.id,
  1813. prepareJson: dataJson,
  1814. })
  1815. if(saveResult) {
  1816. showInlineReportEdit.value = false
  1817. handleRefresh()
  1818. }
  1819. }
  1820. const handleRefreshData = () => {
  1821. loadRecordList()
  1822. initPreview()
  1823. handleGetCheckKeyInputs()
  1824. getOrderHistoryVersion(props.selectedItem?.id)
  1825. }
  1826. defineExpose({
  1827. handleShowAssociationOperationManual
  1828. })
  1829. //新加
  1830. // 添加控制展开/收缩状态的变量
  1831. const isExpanded = ref(false);
  1832. // 添加切换面板展开/收缩的方法
  1833. const togglePanel = () => {
  1834. isExpanded.value = !isExpanded.value;
  1835. setTimeout((() => {
  1836. nextTick(handleWindowResize)
  1837. }), 300);
  1838. };
  1839. // 获取PDF宽度
  1840. const pdfContentWidth = ref<number>(980)
  1841. const pdfPanelRef = ref<HTMLDivElement>()
  1842. const handleWindowResize = debounce(() => {
  1843. if(!pdfPanelRef.value) return
  1844. const width = pdfPanelRef.value?.clientWidth - 20
  1845. pdfContentWidth.value = width > 980 ? 980 : width
  1846. //重新加载适应宽度
  1847. spreadRef.value?.reloadView();
  1848. }, 100)
  1849. onMounted(() => {
  1850. handleWindowResize()
  1851. window.addEventListener('resize', handleWindowResize)
  1852. })
  1853. onUnmounted(() => {
  1854. window.removeEventListener('resize', handleWindowResize)
  1855. })
  1856. </script>
  1857. <style lang="scss" scoped>
  1858. .capsule-tabs {
  1859. display: inline-flex;
  1860. align-items: center;
  1861. gap: 2px;
  1862. padding: 2px;
  1863. border-radius: 20px;
  1864. margin-right: 12px;
  1865. flex-shrink: 0;
  1866. .tab-item {
  1867. display: inline-flex;
  1868. align-items: center;
  1869. justify-content: center;
  1870. padding: 4px 12px;
  1871. font-size: 12px;
  1872. background: white;
  1873. border-radius: 16px;
  1874. cursor: pointer;
  1875. transition: all 0.3s ease;
  1876. color: #606266;
  1877. font-weight: 500;
  1878. border: 1px solid transparent;
  1879. user-select: none;
  1880. white-space: nowrap;
  1881. min-width: 50px;
  1882. span {
  1883. font-size: 12px !important;
  1884. }
  1885. &:hover {
  1886. color: #409eff;
  1887. border-color: #409eff;
  1888. }
  1889. &.active {
  1890. background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
  1891. color: white;
  1892. border-color: #409eff;
  1893. box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
  1894. }
  1895. }
  1896. }
  1897. .container-panel {
  1898. height: 100%;
  1899. border: 1px solid var(--el-border-color);
  1900. .info-panel {
  1901. display: flex;
  1902. height: 32px;
  1903. padding: 0 8px 0 22px;
  1904. font-size: 14px;
  1905. color: #41475c;
  1906. background-color: #effaff;
  1907. justify-content: space-between;
  1908. align-items: center;
  1909. }
  1910. .status-operation-panel {
  1911. height: calc(100% - 32px);
  1912. .single-item-panel {
  1913. display: flex;
  1914. align-items: stretch;
  1915. justify-content: space-between;
  1916. width: 100%;
  1917. height: 100%;
  1918. }
  1919. .pdf-panel {
  1920. height: 100%;
  1921. padding: 10px;
  1922. flex: 1;
  1923. overflow: hidden;
  1924. }
  1925. .right-panel-container {
  1926. display: flex;
  1927. position: relative;
  1928. // 收缩展开按钮样式
  1929. .toggle-btn {
  1930. position: absolute;
  1931. left: -30px;
  1932. top: 50%;
  1933. transform: translateY(-50%);
  1934. width: 30px;
  1935. height: 60px;
  1936. background-color: #fff;
  1937. border: 1px solid var(--el-border-color);
  1938. border-radius: 10px 0 0 10px;
  1939. display: flex;
  1940. align-items: center;
  1941. justify-content: center;
  1942. cursor: pointer;
  1943. z-index: 100;
  1944. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  1945. transition: all 0.3s ease;
  1946. &:hover {
  1947. background-color: #f5f5f5;
  1948. }
  1949. &.collapsed {
  1950. left: -18px;
  1951. // border-radius: 0 10px 10px 0;
  1952. }
  1953. }
  1954. }
  1955. .operation-panel {
  1956. flex-basis: 300px;
  1957. padding: 10px 10px 10px 0;
  1958. box-sizing: border-box;
  1959. transition: all 0.3s ease;
  1960. // 展开状态样式
  1961. &.expanded {
  1962. width: 300px;
  1963. }
  1964. // 收缩状态样式
  1965. &.collapsed {
  1966. width: 0;
  1967. padding: 0;
  1968. border: none;
  1969. .default-toolbar,
  1970. .operation-inner {
  1971. display: none;
  1972. }
  1973. }
  1974. .operation-btns {
  1975. display: flex;
  1976. flex-wrap: wrap;
  1977. gap: 12px;
  1978. .el-button {
  1979. margin-bottom: 10px;
  1980. margin-left: 0;
  1981. }
  1982. }
  1983. }
  1984. .operation-inner {
  1985. height: 100%;
  1986. padding: 7px 10px 20px;
  1987. background-color: #fff;
  1988. border: 1px solid var(--el-border-color);
  1989. box-sizing: border-box;
  1990. }
  1991. .custom-inner{
  1992. display: flex;
  1993. flex-direction: column;
  1994. overflow: hidden;
  1995. height: 100%;
  1996. padding: 7px 10px 20px;
  1997. background-color: #fff;
  1998. border: 1px solid var(--el-border-color);
  1999. box-sizing: border-box;
  2000. .operation-item1 {
  2001. position: relative;
  2002. margin-bottom: 10px;
  2003. overflow-y: auto;
  2004. .item-header {
  2005. position: sticky;
  2006. top: 0;
  2007. left: 0;
  2008. z-index: 1000;
  2009. width: 100%;
  2010. height: 28px;
  2011. padding-left: 20px;
  2012. font-size: 16px;
  2013. line-height: 28px;
  2014. color: #fff;
  2015. background: #fff url('@/assets/imgs/pressure/my-task-detail-operation-bg.png') no-repeat
  2016. left top;
  2017. background-size: 100% 28px;
  2018. }
  2019. .item-content1 {
  2020. display: flex;
  2021. margin-top: 10px;
  2022. &-item {
  2023. font-size: 14px;
  2024. }
  2025. &-img {
  2026. flex: 1;
  2027. display: grid;
  2028. grid-template-columns: repeat(3, 1fr);
  2029. grid-gap: 10px;
  2030. .item-content1-img-item{
  2031. width: 100px;
  2032. height: 100px;
  2033. position: relative;
  2034. .list-item-tool {
  2035. position: absolute;
  2036. top: 0;
  2037. left: 0;
  2038. width: 100%;
  2039. height: 100%;
  2040. z-index: 99;
  2041. border-radius: 8px;
  2042. transition: all 0.5s ease;
  2043. cursor: pointer;
  2044. display: flex;
  2045. justify-content: center;
  2046. align-items: center;
  2047. gap: 5px;
  2048. &:hover {
  2049. backdrop-filter: blur(2px);
  2050. background-color: #00000076;
  2051. z-index: 1;
  2052. .icon {
  2053. display: inline-block;
  2054. opacity: 1;
  2055. &:hover {
  2056. color: #ffffff;
  2057. transition: all 0.5s ease;
  2058. }
  2059. }
  2060. }
  2061. .icon {
  2062. color: #ffffff99;
  2063. opacity: 0;
  2064. transition: all 0.5s ease;
  2065. font-size: 16px;
  2066. }
  2067. }
  2068. }
  2069. .img-item {
  2070. width: 100px;
  2071. height: 100px;
  2072. }
  2073. }
  2074. }
  2075. .record-item {
  2076. margin-bottom: 10px;
  2077. background-color: #f5f5fa;
  2078. border-radius: 2px;
  2079. }
  2080. .item-content {
  2081. padding: 10px 0;
  2082. font-size: 14px;
  2083. .el-empty {
  2084. width: 100%;
  2085. height: 150px;
  2086. padding: 0;
  2087. box-sizing: border-box;
  2088. }
  2089. &-item {
  2090. height: 32px;
  2091. display: flex;
  2092. align-items: center;
  2093. gap: 8px;
  2094. }
  2095. }
  2096. .record-item-title {
  2097. height: 31px;
  2098. padding: 0 13px;
  2099. line-height: 31px;
  2100. background: linear-gradient(270deg, rgb(128 176 251 / 20%) 0%, rgb(73 120 246 / 20%) 100%);
  2101. border-radius: 2px;
  2102. }
  2103. .record-item-inner {
  2104. padding: 11px 13px 8px;
  2105. .content {
  2106. display: flex;
  2107. align-items: center;
  2108. .el-button {
  2109. margin-left: 8px;
  2110. }
  2111. :deep(.el-button--small.is-round) {
  2112. height: auto;
  2113. padding: 3px 11px;
  2114. }
  2115. .time {
  2116. color: rgb(31 31 31 / 88%);
  2117. text-align: right;
  2118. opacity: 0.5;
  2119. flex: 1;
  2120. }
  2121. }
  2122. .desc {
  2123. margin-top: 7px;
  2124. color: #41475c;
  2125. opacity: 0.8;
  2126. span {
  2127. opacity: 0.5;
  2128. }
  2129. }
  2130. }
  2131. .error-item {
  2132. display: flex;
  2133. padding: 7px 10px;
  2134. color: #41475c;
  2135. background-color: #f5f5fa;
  2136. border: 1px solid var(--el-border-color);
  2137. border-width: 1px 0;
  2138. align-items: center;
  2139. .el-icon {
  2140. margin-right: 6px;
  2141. }
  2142. &:nth-child(n + 1) {
  2143. margin-top: -1px;
  2144. }
  2145. &:nth-child(even) {
  2146. background-color: #fff;
  2147. }
  2148. }
  2149. .history-item {
  2150. padding: 7px 10px 10px;
  2151. margin-bottom: 13px;
  2152. color: #41475c;
  2153. background-color: #f5f5fa;
  2154. border-radius: 2px;
  2155. .history-title {
  2156. display: flex;
  2157. align-items: center;
  2158. margin-left: -10px;
  2159. font-weight: 600;
  2160. line-height: 20px;
  2161. &::before {
  2162. display: block;
  2163. width: 4px;
  2164. height: 15px;
  2165. margin-right: 7px;
  2166. background: #4978f6;
  2167. content: '';
  2168. }
  2169. }
  2170. p {
  2171. margin: 10px 0;
  2172. line-height: 20px;
  2173. }
  2174. .history-footer {
  2175. display: flex;
  2176. // align-items: center;
  2177. font-size: 12px;
  2178. .name {
  2179. color: #4978f6;
  2180. }
  2181. .time {
  2182. margin-left: 2px;
  2183. color: rgb(65 71 92 / 50%);
  2184. }
  2185. div {
  2186. flex: 1;
  2187. display: flex;
  2188. justify-content: flex-end;
  2189. .el-button span {
  2190. font-size: 12px;
  2191. }
  2192. }
  2193. }
  2194. }
  2195. }
  2196. .videoAndImg {
  2197. flex: 1;
  2198. width: 100%;
  2199. overflow-y: auto;
  2200. }
  2201. }
  2202. .operation-item {
  2203. position: relative;
  2204. max-height: calc(100% / 3 - 10px);
  2205. margin-bottom: 10px;
  2206. overflow-y: auto;
  2207. .item-header {
  2208. position: sticky;
  2209. top: 0;
  2210. left: 0;
  2211. z-index: 1000;
  2212. width: 100%;
  2213. height: 28px;
  2214. padding-left: 20px;
  2215. font-size: 16px;
  2216. line-height: 28px;
  2217. color: #fff;
  2218. background: #fff url('@/assets/imgs/pressure/my-task-detail-operation-bg.png') no-repeat
  2219. left top;
  2220. background-size: 100% 28px;
  2221. }
  2222. .item-content1 {
  2223. display: flex;
  2224. margin-top: 10px;
  2225. &-item {
  2226. font-size: 14px;
  2227. }
  2228. &-img {
  2229. flex: 1;
  2230. display: grid;
  2231. grid-template-columns: repeat(3, 1fr);
  2232. grid-gap: 10px;
  2233. .item-content1-img-item{
  2234. width: 100px;
  2235. height: 100px;
  2236. position: relative;
  2237. .list-item-tool {
  2238. position: absolute;
  2239. top: 0;
  2240. left: 0;
  2241. width: 100%;
  2242. height: 100%;
  2243. z-index: 99;
  2244. border-radius: 8px;
  2245. transition: all 0.5s ease;
  2246. cursor: pointer;
  2247. display: flex;
  2248. justify-content: center;
  2249. align-items: center;
  2250. gap: 5px;
  2251. &:hover {
  2252. backdrop-filter: blur(2px);
  2253. background-color: #00000076;
  2254. z-index: 1;
  2255. .icon {
  2256. display: inline-block;
  2257. opacity: 1;
  2258. &:hover {
  2259. color: #ffffff;
  2260. transition: all 0.5s ease;
  2261. }
  2262. }
  2263. }
  2264. .icon {
  2265. color: #ffffff99;
  2266. opacity: 0;
  2267. transition: all 0.5s ease;
  2268. font-size: 16px;
  2269. }
  2270. }
  2271. }
  2272. .img-item {
  2273. width: 100px;
  2274. height: 100px;
  2275. }
  2276. }
  2277. }
  2278. .record-item {
  2279. margin-bottom: 10px;
  2280. background-color: #f5f5fa;
  2281. border-radius: 2px;
  2282. }
  2283. .item-content {
  2284. padding: 10px 0;
  2285. font-size: 14px;
  2286. .el-empty {
  2287. width: 100%;
  2288. height: 150px;
  2289. padding: 0;
  2290. box-sizing: border-box;
  2291. }
  2292. &-item {
  2293. height: 32px;
  2294. display: flex;
  2295. align-items: center;
  2296. gap: 8px;
  2297. }
  2298. }
  2299. .record-item-title {
  2300. height: 31px;
  2301. padding: 0 13px;
  2302. line-height: 31px;
  2303. background: linear-gradient(270deg, rgb(128 176 251 / 20%) 0%, rgb(73 120 246 / 20%) 100%);
  2304. border-radius: 2px;
  2305. }
  2306. .record-item-inner {
  2307. padding: 11px 13px 8px;
  2308. .content {
  2309. display: flex;
  2310. align-items: center;
  2311. .el-button {
  2312. margin-left: 8px;
  2313. }
  2314. :deep(.el-button--small.is-round) {
  2315. height: auto;
  2316. padding: 3px 11px;
  2317. }
  2318. .time {
  2319. color: rgb(31 31 31 / 88%);
  2320. text-align: right;
  2321. opacity: 0.5;
  2322. flex: 1;
  2323. }
  2324. }
  2325. .desc {
  2326. margin-top: 7px;
  2327. color: #41475c;
  2328. opacity: 0.8;
  2329. span {
  2330. opacity: 0.5;
  2331. }
  2332. }
  2333. }
  2334. .error-item {
  2335. display: flex;
  2336. padding: 7px 10px;
  2337. color: #41475c;
  2338. background-color: #f5f5fa;
  2339. border: 1px solid var(--el-border-color);
  2340. border-width: 1px 0;
  2341. align-items: center;
  2342. .el-icon {
  2343. margin-right: 6px;
  2344. }
  2345. &:nth-child(n + 1) {
  2346. margin-top: -1px;
  2347. }
  2348. &:nth-child(even) {
  2349. background-color: #fff;
  2350. }
  2351. }
  2352. .history-item {
  2353. padding: 7px 10px 10px;
  2354. margin-bottom: 13px;
  2355. color: #41475c;
  2356. background-color: #f5f5fa;
  2357. border-radius: 2px;
  2358. .history-title {
  2359. display: flex;
  2360. align-items: center;
  2361. margin-left: -10px;
  2362. font-weight: 600;
  2363. line-height: 20px;
  2364. &::before {
  2365. display: block;
  2366. width: 4px;
  2367. height: 15px;
  2368. margin-right: 7px;
  2369. background: #4978f6;
  2370. content: '';
  2371. }
  2372. }
  2373. p {
  2374. margin: 10px 0;
  2375. line-height: 20px;
  2376. }
  2377. .history-footer {
  2378. display: flex;
  2379. // align-items: center;
  2380. font-size: 12px;
  2381. .name {
  2382. color: #4978f6;
  2383. }
  2384. .time {
  2385. margin-left: 2px;
  2386. color: rgb(65 71 92 / 50%);
  2387. }
  2388. div {
  2389. flex: 1;
  2390. display: flex;
  2391. justify-content: flex-end;
  2392. .el-button span {
  2393. font-size: 12px;
  2394. }
  2395. }
  2396. }
  2397. }
  2398. }
  2399. }
  2400. }
  2401. .default-toolbar {
  2402. display: flex;
  2403. justify-content: flex-end;
  2404. gap: 16px;
  2405. margin-bottom: 20px;
  2406. white-space: nowrap;
  2407. ::v-deep .el-button {
  2408. margin-left: 0;
  2409. }
  2410. }
  2411. // 退回对话框样式
  2412. .reject-dialog-content {
  2413. .form-item {
  2414. margin-bottom: 20px;
  2415. &:last-child {
  2416. margin-bottom: 0;
  2417. }
  2418. .form-label {
  2419. display: block;
  2420. margin-bottom: 8px;
  2421. font-size: 14px;
  2422. font-weight: 500;
  2423. color: #606266;
  2424. }
  2425. }
  2426. }
  2427. :deep(.preview-dialog) {
  2428. background-color: transparent !important;
  2429. width: auto !important;
  2430. padding: 0 !important;
  2431. .el-dialog__header {
  2432. display: none;
  2433. }
  2434. .el-dialog__body{
  2435. padding: 0;
  2436. .preview-container{
  2437. padding: 0;
  2438. position: relative;
  2439. }
  2440. .preview-image,.preview-video {
  2441. height: 65vh;
  2442. max-width: 100vw;
  2443. // object-fit: cover;
  2444. }
  2445. }
  2446. }
  2447. </style>