StatusOperationPanel.vue 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703
  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. try {
  871. await spreadRef.value?.handleSave()
  872. } catch (error) {
  873. console.error('保存数据失败:', error)
  874. ElMessage.error('保存数据失败,请重试')
  875. return
  876. }
  877. const canSubmit = canSubmitMainReportType('该报告存在未办结检验意见通知书,无法提交校核')
  878. if(!canSubmit) return
  879. // 获取审核人\校核人配置信息
  880. let res = await UserApi.getApprovalDetail({})
  881. // 如果存在多份待提交校核的报告,执行批量校核弹窗
  882. if(getCanSubmitRecheckReport.value.length > 1) {
  883. if(res && res.recheckUser) {
  884. batchRecheckForm.value.recheckUser = res.recheckUser
  885. }
  886. batchRecheckForm.value.reportIds = getCanSubmitRecheckReport.value.map(x => x?.id)
  887. showBatchSubmitToRecheckDialog.value = true
  888. return
  889. }
  890. // 只有一份待提交校核的报告,执行以下逻辑
  891. if(res && res.recheckUser) {
  892. form.value.recheckUser = res.recheckUser
  893. }
  894. schemaFlag.value = 'proofread'
  895. isShowAuditDialog.value = true
  896. }
  897. // const handleAuditSelectConfirm = async (res: any) => {
  898. // console.log('handleAuditSelectConfirm', res)
  899. // if (!props.selectedItem || !res[0]) {
  900. // return
  901. // }
  902. // const saveResult = await BoilerTaskOrderApi.submitTaskReportTemplate({
  903. // id: props.selectedItem.id,
  904. // recheckId: res[0]
  905. // })
  906. // if (saveResult) {
  907. // ElMessage.success('提交校核成功!')
  908. // // 这里可以做页面刷新
  909. // emit('template-confirm')
  910. // }
  911. // }
  912. // 批量提交
  913. const handleBatchSubmitToRecheck = async () => {
  914. try {
  915. await batchRecheckFormRef.value.validate()
  916. } catch (err) {
  917. ElMessage.error('请完善表单数据!')
  918. return
  919. }
  920. if (_.isEmpty(batchRecheckForm.value.recheckUser)) {
  921. return ElMessage.error('请选择校核人')
  922. }
  923. // 待提交的数据
  924. const params = {
  925. reportList: getCanSubmitRecheckReport.value.filter((x: any) => batchRecheckForm.value.reportIds.includes(x?.id)).map((x: any) => ({
  926. id: x.id,
  927. reportUrl: x.reportUrl,
  928. dataJson: x?.prepareJson
  929. })),
  930. recheckId: batchRecheckForm.value.recheckUser?.id
  931. }
  932. const submitResult = await BoilerTaskOrderApi.batchSubmitToRecheck(params)
  933. if (submitResult) {
  934. ElMessage.success('提交校核成功!')
  935. showBatchSubmitToRecheckDialog.value = false
  936. selectNextItem(getCanSubmitRecheckReport.value.filter((x: any) => batchRecheckForm.value.reportIds.includes(x?.id)))
  937. // 这里可以做页面刷新
  938. emit('template-confirm')
  939. }
  940. }
  941. const submitting = ref(false)
  942. const handleAuditSelectConfirm = async () => {
  943. if (_.isEmpty(form.value.recheckUser)) {
  944. return ElMessage.error(schemaFlag.value == 'proofread' ? '请选择校核人' : '请选择审核人')
  945. }
  946. // 审核
  947. if (schemaFlag.value === 'audit') {
  948. submitting.value = true
  949. const submitResult = await BoilerTaskOrderApi.submitReportAudit({
  950. id: templateParams.value?.id,
  951. approveId: form.value?.recheckUser?.id
  952. })
  953. submitting.value = false
  954. if (submitResult) {
  955. ElMessage.success('提交审核成功!')
  956. isShowAuditDialog.value = false
  957. selectNextItem([props.selectedItem])
  958. // 这里可以做页面刷新
  959. emit('template-confirm')
  960. }
  961. } else if (schemaFlag.value === 'proofread') {
  962. // 校核
  963. const saveResult = await BoilerTaskOrderApi.submitTaskReportTemplate({
  964. id: props?.selectedItem?.id,
  965. recheckId: form.value?.recheckUser?.id
  966. })
  967. if (saveResult) {
  968. ElMessage.success('提交校核成功!')
  969. isShowAuditDialog.value = false
  970. selectNextItem([props.selectedItem])
  971. // 这里可以做页面刷新
  972. emit('template-confirm')
  973. }
  974. }
  975. }
  976. /**
  977. * 项目切换
  978. */
  979. const selectNextItem = (items:ReportItemVO[]) => {
  980. // 找到其他在记录录入或者报告编制状态的第一项目
  981. const ids = items.map(item => item.id)
  982. const inputReportList= props.reportList.filter(
  983. item => {
  984. return !ids.includes(item.id)
  985. }
  986. ).filter(item =>{
  987. return item.taskStatus === PressureTaskOrderTaskStatus['RECORD_INPUT'] || item.taskStatus === PressureTaskOrderTaskStatus['REPORT_INPUT']
  988. })
  989. console.log(inputReportList)
  990. if (inputReportList.length > 0){
  991. emit('item-select', inputReportList[0])
  992. }
  993. }
  994. // 审批人选择对话框状态
  995. const isShowApprovalDialog = ref(false)
  996. // 监听项目切换,自动重置视图模式
  997. watch(
  998. () => props.selectedItem,
  999. (newItem, oldItem) => {
  1000. if (newItem) {
  1001. showReportPdfType.value = [PressureCheckerMyTaskStatus.REPORT_INPUT,PressureCheckerMyTaskStatus.REPORT_AUDIT,PressureCheckerMyTaskStatus.REPORT_APPROVE,PressureCheckerMyTaskStatus.REPORT_END].includes(props.selectedItem.taskStatus)
  1002. && ![400,500,600,700].includes(props.selectedItem.reportType) ? 'report':'record'
  1003. handleRefreshData()
  1004. props.taskId && getReportAuditInfo()
  1005. hasRecord.value = props.selectedItem.templateId != null
  1006. if (props.selectedItem?.reportTemplateId == null){
  1007. showReportPdfType.value = 'record'
  1008. }
  1009. if (props.selectedItem?.templateId == null){
  1010. showReportPdfType.value = 'report'
  1011. }
  1012. }
  1013. // 当切换到不同的项目时,重置视图模式为normal
  1014. if (newItem?.id !== oldItem?.id) {
  1015. viewMode.value = 'normal'
  1016. }
  1017. },
  1018. { immediate: false }
  1019. )
  1020. const previewUrl = ref('')
  1021. const previewVisible = ref(false)
  1022. const previewType = ref('')
  1023. const handlePreview = (path: string, type: 'video' | 'image') => {
  1024. previewUrl.value = path;
  1025. previewType.value = type;
  1026. previewVisible.value = true;
  1027. }
  1028. /**
  1029. * 如果是"已经审核完的检验意见通知书,则查询相关的检验意见通知信息,显示在最右侧
  1030. */
  1031. const checkBookDetail = ref<Record<string, any>>({})
  1032. const showCheckBook = computed(() => {
  1033. const { reportType, taskStatus } = props.selectedItem || {}
  1034. // console.log(taskStatus, 'taskStatus', reportType)
  1035. // taskStatus: 800
  1036. return reportType === PressureReportType['SUGGUESTION']
  1037. })
  1038. const rectificationStatusMap = reactive({
  1039. 0: '待确认',
  1040. 1: '待整改',
  1041. 2: '已递交',
  1042. 3: '材料有误',
  1043. 4: '整改通过',
  1044. 5: '整改不通过'
  1045. })
  1046. const getReportAuditInfo = async () => {
  1047. if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION']) {
  1048. const res = await reportInfoApi.exportCheckBookDetail({
  1049. id: props.taskId
  1050. })
  1051. console.log(res, '查询检验意见通知书详细信息')
  1052. if (res) {
  1053. checkBookDetail.value = res
  1054. }
  1055. }
  1056. }
  1057. const returnForm = ref({
  1058. rejectionReason: ''
  1059. })
  1060. const returnFormRules = ref({
  1061. rejectionReason: [{ required: true, message: '请输入回退原因', trigger: 'blur' }]
  1062. })
  1063. const returnFormRef = ref()
  1064. const isCompleteInput = computed(() => {
  1065. return props.selectedItem?.taskStatus >= PressureCheckerMyTaskStatus.RECORD_CHECK
  1066. })
  1067. const isShowRecordOrReportBtn = computed(() => {
  1068. return [PressureReportType.MAIN,PressureReportType.SUB,PressureReportType.SINGLE].includes(props.selectedItem?.reportType)
  1069. })
  1070. // 通过 退回
  1071. const handlePass = async (type) => {
  1072. const params: Record<string, any> = {
  1073. reportId: props.selectedItem?.id,
  1074. approvalType: type
  1075. }
  1076. if (type === 1) {
  1077. const valid = await returnFormRef.value.validate()
  1078. if (!valid) return
  1079. params.rejectionReason = returnForm.value.rejectionReason
  1080. }
  1081. const tipText = type === 1 ? '退回' : type === 2 ? '整改不通过' : '整改通过'
  1082. ElMessageBox.confirm(`确定${tipText}吗?`, '提示', {
  1083. confirmButtonText: '确定',
  1084. cancelButtonText: '取消',
  1085. type: 'warning'
  1086. }).then(() => {
  1087. BoilerTaskOrderApi.inspectionApproval(params).then((res) => {
  1088. props.taskId && getReportAuditInfo()
  1089. emit('refresh')
  1090. }).catch(() => {
  1091. ElMessage.error('操作失败')
  1092. })
  1093. })
  1094. }
  1095. // 获取检验员名称
  1096. const getCheckersName = (): string => {
  1097. if (!props.selectedItem?.checkUsers || props.selectedItem.checkUsers.length === 0) {
  1098. return '未分配'
  1099. }
  1100. return props.selectedItem.checkUsers.map((user) => user.nickname).join('、')
  1101. }
  1102. // 切换主检人
  1103. const handleUserSelect = async (id, userList) => {
  1104. const result = await BoilerTaskOrderApi.updateReportMainChecker({
  1105. id: props.taskOrderItem?.id,
  1106. mainChecker: userList[0]?.id
  1107. })
  1108. if (result) {
  1109. ElMessage.success('修改主检人成功!')
  1110. emit('refresh')
  1111. }
  1112. }
  1113. const userSelectFormRef = ref()
  1114. const handleModifyMainChecker = () => {
  1115. userSelectFormRef.value.open(props.taskOrderItem?.mainCheckerUser?.id)
  1116. }
  1117. // 判断当前检验员或主检人是否为登录用户,如果不是,则功能按钮disabled
  1118. const checkerIsLoginUser = computed(() => {
  1119. const checkerUserIds = props.selectedItem?.checkUsers.map(checker => checker?.id)
  1120. return !(checkerUserIds?.includes(userStore?.user?.id) || props.taskOrderItem?.mainCheckerUser?.id === userStore?.user?.id)
  1121. })
  1122. // 判断当前项目是否已经到报告办结阶段
  1123. const getReportStatusEnd = computed(
  1124. () =>{
  1125. return props.selectedItem && props.selectedItem.taskStatus >= PressureCheckerMyTaskStatus['REPORT_CONFIRMATION']
  1126. }
  1127. )
  1128. // 判断“提交校核”按钮是否显示
  1129. const isCanSubmitRecheck = computed(() => {
  1130. if (props.selectedItem?.reportType === PressureReportType['SUGGUESTION'])
  1131. return props.selectedItem?.isRecheck || false
  1132. else if (props.selectedItem?.reportType === PressureReportType['MAINQUESTION']) return false
  1133. else
  1134. return (
  1135. props.selectedItem &&
  1136. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT']
  1137. // && props.selectedItem.reportUrl
  1138. )
  1139. })
  1140. // 判断“提交审核&提交审批”按钮是否显示
  1141. const isCanSubmitToAudit = computed(() => {
  1142. const { selectedItem } = props
  1143. if (selectedItem && selectedItem?.reportType === PressureReportType['SUBCONTRACT']){
  1144. return selectedItem.taskStatus === PressureCheckerMyTaskStatus['CONFIRMED']
  1145. }
  1146. if (props.selectedItem && props.selectedItem?.reportType === PressureReportType['SUGGUESTION'])
  1147. return (
  1148. props.selectedItem?.isApproval &&
  1149. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT']
  1150. )
  1151. else if (
  1152. props.selectedItem &&
  1153. props.selectedItem?.reportType === PressureReportType['MAINQUESTION']
  1154. )
  1155. return (
  1156. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT'] &&
  1157. props.selectedItem?.reportUrl
  1158. )
  1159. else
  1160. return (
  1161. props.selectedItem &&
  1162. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['REPORT_INPUT']
  1163. )
  1164. })
  1165. // 判断“填写记录”按钮是否显示
  1166. const isCanEditTestRecord = computed(
  1167. () =>
  1168. props.selectedItem &&
  1169. (props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['RECORD_INPUT'] ||
  1170. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['CONFIRMED']) && props.selectedItem.reportType !== PressureReportType['SUBCONTRACT']
  1171. )
  1172. // 判断“编制报告”按钮是否显示
  1173. const isCanEditReport = computed(
  1174. () =>
  1175. props.selectedItem &&
  1176. props.selectedItem.taskStatus === PressureCheckerMyTaskStatus['REPORT_INPUT']
  1177. )
  1178. // 判断“填写结果”按钮是否显示
  1179. const isCanEditRecordResult = computed(() => {
  1180. // 非我的任务详情页面,不显示
  1181. if ('BoilerCheckerTaskDetail' !== routeName.value) return false
  1182. if (!props.selectedItem?.isAutoAmount || props.selectedItem?.isAutoAmount === '0') return false
  1183. if (
  1184. (props.selectedItem?.reportType === 100 || props.selectedItem?.reportType === 300) &&
  1185. props.selectedItem.taskStatus !== PressureCheckerMyTaskStatus['REPORT_END']
  1186. ) {
  1187. // 独审报告&主报告--“填写结果”:报告办结之前都可以填写
  1188. return true
  1189. }
  1190. // 查找主报告
  1191. const mainReport = props.reportList?.find((item) => item.reportType === 100) || {
  1192. taskStatus: null
  1193. }
  1194. if (
  1195. props.selectedItem?.reportType !== 100 &&
  1196. props.selectedItem?.reportType !== 300 &&
  1197. mainReport?.taskStatus !== PressureCheckerMyTaskStatus['REPORT_END']
  1198. ) {
  1199. // 非主报告 & 非独审报告 -- “填写结果”:主报告办结之前都可以填写
  1200. return true
  1201. }
  1202. return false
  1203. })
  1204. // 1、重大问题线索告知表 2、作业指导书 3、检验方案 只显示pdf
  1205. const onlyShowPdf = computed(() => {
  1206. const reportTypes = [
  1207. PressureReportType.MAINQUESTION,
  1208. PressureReportType.INSPECTIONPLAN,
  1209. PressureReportType.WORKINSTRUCTION
  1210. ]
  1211. return !props.selectedItem?.reportType
  1212. ? false
  1213. : reportTypes.includes(props.selectedItem?.reportType)
  1214. })
  1215. // 模板参数
  1216. const templateParams = computed(() => {
  1217. if (!props.selectedItem) return {}
  1218. return {
  1219. ...props.selectedItem,
  1220. equipCode: props.taskOrderItem?.equipCode || '',
  1221. equipId: props.taskOrderItem?.id || ''
  1222. }
  1223. })
  1224. // 判断是否为独审报告且不需要审批
  1225. const isApprovalWithoutRatify = computed(() => {
  1226. if (!props.selectedItem) return false
  1227. const reportType = (props.selectedItem as any).reportType
  1228. const isApproval = (props.selectedItem as any).isApproval
  1229. const isRatify = (props.selectedItem as any).isRatify
  1230. return (
  1231. reportType === PressureReportType.SINGLE &&
  1232. isApproval === true &&
  1233. isRatify === false &&
  1234. props.reportId === props.selectedItem.id
  1235. )
  1236. })
  1237. /**** 葡萄城:记录录入的显示和隐藏 ****/
  1238. const showInlineEditCheckRecord = ref(false)
  1239. const templateId = ref('')
  1240. const handleEditSpreadRecord = () => {
  1241. // console.log('templateParams', templateParams.value)
  1242. // DynamicTbInsApi.getOrCreatePreviewData('dc8fbb6078b2a2f0eadc0f6aedbeafa0').then(res => {
  1243. // showInlineEditCheckRecord.value = true
  1244. // templateId.value = res.id
  1245. // })
  1246. editPreview('record')
  1247. showInlineEditCheckRecord.value = true
  1248. }
  1249. const handleTemplateConfirm = (templateUrl: string) => {
  1250. console.log('templateUrl', templateUrl)
  1251. emit('template-confirm', templateUrl)
  1252. }
  1253. const handleRefresh = () => {
  1254. emit('refresh')
  1255. }
  1256. /**** 葡萄城:记录录入的显示和隐藏 end****/
  1257. /**** 葡萄城:检验结果录入的显示和隐藏 ****/
  1258. const showInlineInspectionResultInput = ref(false)
  1259. const inspectionResultTemplateParams = ref({})
  1260. // 检验结果录入模板参数
  1261. const handleInputCheckConclusion = () => {
  1262. showInlineInspectionResultInput.value = true
  1263. if (!props.selectedItem) return {}
  1264. inspectionResultTemplateParams.value = {
  1265. ...props.selectedItem,
  1266. equipCode: props.taskOrderItem?.equipCode || ''
  1267. }
  1268. }
  1269. const handleInspectionResultConfirm = (resultUrl: string) => {
  1270. emit('template-confirm', resultUrl)
  1271. viewMode.value = 'normal'
  1272. }
  1273. const handleReturnToNormalMode = () => {
  1274. viewMode.value = 'normal'
  1275. }
  1276. /**** 葡萄城:检验结果录入的显示和隐藏 end ****/
  1277. /**** 葡萄城:报告编制的显示和隐藏 ****/
  1278. const showInlineReportEdit = ref(false)
  1279. const handleEditRreport = () => {
  1280. if (showReportPdfType.value !== 'report' && showReportPdfType.value !== 'result'){
  1281. ElMessage.warning('请切换报告后再进行报告编制!')
  1282. return
  1283. }
  1284. editPreview('report')
  1285. showInlineReportEdit.value = true
  1286. }
  1287. // 获取当前报告的配置信息
  1288. const currentReportConfig = computed(() => {
  1289. if (
  1290. !props.selectedItem ||
  1291. props.selectedItem.reportType !== PressureReportType.SINGLE ||
  1292. !props.reportList
  1293. ) {
  1294. return null
  1295. }
  1296. // 从reportList中找到当前报告的配置
  1297. const currentReport = props.reportList.find((report) => report.id === templateParams.value?.id)
  1298. return currentReport
  1299. ? {
  1300. isApproval: (currentReport as any).isApproval,
  1301. isRatify: (currentReport as any).isRatify
  1302. }
  1303. : null
  1304. })
  1305. // 选择报告审核人弹窗的显示和隐藏
  1306. const isShowReportAuditDialog = ref(false)
  1307. // 提交报告审核
  1308. const handleSubmitAudit = async () => {
  1309. try {
  1310. await spreadRef.value?.handleSave()
  1311. } catch (error) {
  1312. console.error('保存数据失败:', error)
  1313. ElMessage.error('保存数据失败,请重试')
  1314. return
  1315. }
  1316. if([PressureReportType.SUGGUESTION, PressureReportType.MAINQUESTION].includes(props?.selectedItem?.reportType) && !props?.selectedItem?.reportUrl) {
  1317. // 【重大问题线索告知表,检验意见通知书】必须先填写记录,才能提交审核
  1318. ElMessage.warning('请先“填写记录”!再提交审核!')
  1319. return
  1320. }
  1321. if(PressureReportType.SINGLE === props?.selectedItem?.reportType && !props?.selectedItem?.prepareUrl) {
  1322. // 独审报告:用户可以不走报告编制环节直接提交审核,需要调用handleUploadAPIReportPreviewBlob将reportPreview接口的文件流拿来提交一遍
  1323. return handleUploadAPIReportPreviewBlob(handleSubmitAudit)
  1324. }
  1325. // 检查检验意见通知书是否“报告完结”
  1326. const canSubmit = canSubmitMainReportType('该报告存在未办结检验意见通知书,无法提交审核、审批')
  1327. if(!canSubmit) return
  1328. // 检查其他报告状态
  1329. const checkResult = checkOtherReportsFinished()
  1330. if (!checkResult.canSubmit) {
  1331. try {
  1332. await ElMessageBox.alert(
  1333. checkResult.message || '请先办结其他报告再提交主报告审核',
  1334. '无法提交审核'
  1335. )
  1336. } catch (error) {
  1337. // 用户关闭对话框,不需要处理
  1338. }
  1339. return
  1340. }
  1341. // if(PressureReportType.MAIN === props?.selectedItem?.reportType && !props?.selectedItem?.prepareUrl) {
  1342. // // 主报告:用户可以不走报告编制环节直接提交审核,需要调用handleUploadAPIReportPreviewBlob将reportPreview接口的文件流拿来提交一遍
  1343. // return handleUploadAPIReportPreviewBlob(handleSubmitAudit)
  1344. // }
  1345. // 检验意见通知书 && 重大问题线索通知 不需要选择审核人
  1346. if (
  1347. [PressureReportType['SUGGUESTION'], PressureReportType['MAINQUESTION']].includes(
  1348. templateParams.value?.reportType
  1349. )
  1350. ) {
  1351. ElMessageBox.confirm(`确定提交【${templateParams.value?.reportName}】`, '提示', {
  1352. confirmButtonText: '确定',
  1353. cancelButtonText: '取消'
  1354. })
  1355. .then(async () => {
  1356. const submitResult = await BoilerTaskOrderApi.submitOpinionNoticeApproval({
  1357. id: templateParams.value?.id
  1358. })
  1359. if (submitResult) {
  1360. // 这里可以做页面刷新
  1361. emit('template-confirm')
  1362. }
  1363. })
  1364. .catch(() => {
  1365. console.log('用户取消提交审核')
  1366. })
  1367. } else {
  1368. let res = await UserApi.getApprovalDetail({}) // 判断是否有审批信息
  1369. if (res && res.approveUser) {
  1370. form.value.recheckUser = res.approveUser
  1371. }
  1372. schemaFlag.value = 'audit'
  1373. isShowAuditDialog.value = true
  1374. // isShowReportAuditDialog.value = true
  1375. }
  1376. }
  1377. const handleCompletion = async () => {
  1378. await BoilerTaskOrderApi.handleCompletion(props.selectedItem.id)
  1379. handleRefresh()
  1380. ElMessage.success('报告已办结')
  1381. }
  1382. const getRecheckUserList = async (params) => {
  1383. params.orderId = props.taskInfo.id
  1384. return await BoilerTaskOrderApi.getRecheckUserList(params)
  1385. }
  1386. // 上传主报告文件流
  1387. const handleUploadAPIReportPreviewBlob = async (submitApprovalFn) => {
  1388. if(!props.selectedItem || props.selectedItem.taskStatus !== PressureTaskOrderTaskStatus.REPORT_INPUT) return
  1389. // 获取文件流
  1390. const blob = await BoilerTaskOrderApi.getReportPreview({
  1391. reportId: props.selectedItem?.id,
  1392. type: 300, // 报告模板
  1393. fileType: 100 // xlsx
  1394. })
  1395. if(blob) {
  1396. // 上传文件流
  1397. const formData = new FormData()
  1398. formData.append('file', blob)
  1399. const response = await uploadFile(formData)
  1400. // 保存报告编制的url
  1401. const saveResult = await BoilerTaskOrderApi.saveReportPrepare({
  1402. id: props.selectedItem.id,
  1403. prepareUrl: response,
  1404. })
  1405. if(saveResult) {
  1406. await emit('update:selected-item', {...props.selectedItem, prepareUrl: response})
  1407. // 提交审核
  1408. await submitApprovalFn()
  1409. }
  1410. }
  1411. }
  1412. const handleChangeEntrustUnit = (unit: Record<string, any>) => {
  1413. form.value.recheckUser = unit
  1414. }
  1415. // 检查其他报告是否已办结
  1416. const checkOtherReportsFinished = (): { canSubmit: boolean; message?: string } => {
  1417. if (!props.selectedItem) return { canSubmit: false }
  1418. // 如果不是主报告,直接允许提交
  1419. if (props.selectedItem.reportType !== PressureReportType.MAIN) {
  1420. return { canSubmit: true }
  1421. }
  1422. // 主报告需要检查其他报告状态
  1423. const unfinishedReports = !props.reportList
  1424. ? []
  1425. : props.reportList.filter((report) => {
  1426. // 排除当前报告
  1427. if (report.id === templateParams.value?.id) {
  1428. return false
  1429. }
  1430. // 检查子报告和独审报告是否已办结
  1431. const isSubReport = report.reportType === PressureReportType.SUB
  1432. const isSingleReport = report.reportType === PressureReportType.SINGLE
  1433. const isSUGGUESTIONReport = report.reportType === PressureReportType.SUGGUESTION
  1434. if (isSubReport || isSingleReport || isSUGGUESTIONReport) {
  1435. return report.taskStatus !== PressureCheckerMyTaskStatus.REPORT_END
  1436. }
  1437. return false
  1438. })
  1439. if (unfinishedReports.length > 0) {
  1440. const unfinishedNames = unfinishedReports.map((report) => report.reportName).join('、')
  1441. return {
  1442. canSubmit: false,
  1443. message: `请先办结其他报告再提交主报告审核。未办结的报告:${unfinishedNames}`
  1444. }
  1445. }
  1446. // 检查是否确认费用
  1447. // const reportsWithoutConfirmFee: any[] = []
  1448. // 检查当前报告中是否存在应确认费用,但未确认的报错
  1449. const reportsWithoutConfirmFee: any[] = !props.reportList
  1450. ? []
  1451. : props.reportList.filter(
  1452. (report: any) => report.isAutoAmount === '1' && report.feeConfirm === false
  1453. )
  1454. // if (currentReport) {
  1455. // reportsWithoutConfirmFee.push(currentReport)
  1456. // }
  1457. // 检查子报告是否都已录入结果
  1458. // const subReports = !props.reportList ? [] : props.reportList.filter(report => {
  1459. // return report.id !== templateParams.value?.id &&
  1460. // report.reportType === PressureReportType.SUB
  1461. // })
  1462. // subReports.forEach(report => {
  1463. // if (!report.formulaJson) {
  1464. // reportsWithoutConfirmFee.push(report)
  1465. // }
  1466. // })
  1467. if (reportsWithoutConfirmFee.length > 0) {
  1468. const reportNames = reportsWithoutConfirmFee.map((report) => report.reportName).join('、')
  1469. return {
  1470. canSubmit: false,
  1471. message: `请先确认费用再提交主报告审核。未确认费用的报告:${reportNames}`
  1472. }
  1473. }
  1474. return { canSubmit: true }
  1475. }
  1476. // 报告审核人选择确认
  1477. const handleReportAuditSelectConfirm = async (res: any) => {
  1478. const approveId = res[0]
  1479. const submitResult = await BoilerTaskOrderApi.submitReportAudit({
  1480. id: templateParams.value?.id,
  1481. approveId
  1482. })
  1483. if (submitResult) {
  1484. // 这里可以做页面刷新
  1485. emit('template-confirm')
  1486. }
  1487. isShowReportAuditDialog.value = false
  1488. }
  1489. /**** 葡萄城:报告编制的显示和隐藏 end ****/
  1490. const handleModifyChecker = () => {
  1491. if (props.selectedItem) {
  1492. emit('modify-checker', props.selectedItem)
  1493. }
  1494. }
  1495. // 审批人选择确认
  1496. const handleApprovalSelectConfirm = async (res: any) => {
  1497. if (!props.selectedItem || !res || res.length === 0) {
  1498. ElMessage.warning('请选择审批人')
  1499. return
  1500. }
  1501. const ratifyId = res[0] // 获取选中的审批人ID
  1502. try {
  1503. await BoilerTaskOrderApi.submitReportApprove({
  1504. id: props.selectedItem.id,
  1505. ratifyId: ratifyId
  1506. })
  1507. ElMessage.success('提交审批成功')
  1508. isShowApprovalDialog.value = false
  1509. emit('submit-approval')
  1510. } catch (error: any) {
  1511. console.error('提交审批失败:', error)
  1512. ElMessage.error('提交审批失败,请稍后重试')
  1513. isShowApprovalDialog.value = false
  1514. }
  1515. }
  1516. // 加载流转记录列表
  1517. const recordList = ref<any[]>([])
  1518. const recordListLoading = ref(false)
  1519. const loadRecordList = async () => {
  1520. if (!props.selectedItem) return
  1521. try {
  1522. let response = null
  1523. // 检验意见通知书&重大问题线索
  1524. switch (props.selectedItem.reportType) {
  1525. case PressureReportType['SUGGUESTION']:
  1526. case PressureReportType['MAINQUESTION']:
  1527. response = await BoilerTaskOrderApi.getOpinionNoticeApprovalRecordList({
  1528. id: props.selectedItem.id
  1529. })
  1530. break
  1531. default:
  1532. // 其他
  1533. response = await BoilerTaskOrderApi.getTaskOrderItemReportRecordPage({
  1534. pageSize: 10,
  1535. pageNo: 1,
  1536. reportId: props.selectedItem.id
  1537. })
  1538. }
  1539. // 根据实际接口返回的数据结构获取数据
  1540. recordList.value = response?.data?.list || response?.list || response || []
  1541. } catch (error: any) {
  1542. console.error('获取流转记录失败:', error)
  1543. ElMessage.error('获取流转记录失败,请稍后重试')
  1544. recordList.value = []
  1545. } finally {
  1546. recordListLoading.value = false
  1547. }
  1548. }
  1549. // 获取报告字段纠错列表
  1550. const checkInputList = ref<any[]>([])
  1551. const handleGetCheckKeyInputs = async () => {
  1552. checkInputList.value = []
  1553. //if (!dataJson) return
  1554. if (!props.selectedItem?.id) return ElMessage.warning('字段纠错传参有误')
  1555. let reportId = props.selectedItem?.id
  1556. // const templateId = isShowReportPdf.value? props.selectedItem?.reportTemplateId : props.selectedItem?.templateId;
  1557. // if (isShowReportPdf.value){
  1558. // reportId = "report_" + reportId;
  1559. // }
  1560. let templateId = showReportPdfType.value === 'report' ? props.selectedItem?.reportTemplateId :
  1561. showReportPdfType.value === 'result' ? props.selectedItem?.resultTemplateId : props.selectedItem?.templateId;
  1562. if (showReportPdfType.value === 'report'){
  1563. reportId = "report_" + reportId;
  1564. }else if (showReportPdfType.value === 'result'){
  1565. reportId = "result_" + reportId;
  1566. }
  1567. const response = await BoilerTaskOrderApi.getCheckKeyIsInput(
  1568. { id: templateId,reportId: reportId },
  1569. JSON.parse("{}")
  1570. )
  1571. //console.log(JSON.parse(dataJson))
  1572. if (response) checkInputList.value = formatCheckInputList(response)
  1573. }
  1574. function formatCheckInputList(response, checkInputList = [] as any[]) {
  1575. if (!response) return []
  1576. for (let checkItem of response) {
  1577. if (!checkItem.child) {
  1578. checkInputList.push({ code: checkItem.code, name: checkItem.name })
  1579. }
  1580. if (is(checkItem.child, 'Array') && checkItem.type === 'object') {
  1581. formatCheckInputList(checkItem.child, checkInputList)
  1582. }
  1583. if (is(checkItem.child, 'Array') && checkItem.type === 'array') {
  1584. const childMapper = checkItem.child.map((item, i) => {
  1585. return {
  1586. code: `${checkItem.code}: ${item.code}`,
  1587. name: item.name
  1588. }
  1589. })
  1590. formatCheckInputList(childMapper, checkInputList)
  1591. }
  1592. }
  1593. return checkInputList
  1594. }
  1595. // 获取版本记录列表
  1596. const showVersionDetail = ref(false)
  1597. const historyList = ref<any[]>([])
  1598. async function getOrderHistoryVersion(id: string) {
  1599. try {
  1600. const response = await BoilerTaskOrderApi.getSafetyCheckRecordVersionPage({
  1601. pageNo: 1,
  1602. pageSize: 100,
  1603. businessType: 0,
  1604. orderItemReportId: id
  1605. })
  1606. historyList.value = response.list || []
  1607. } catch (error) {
  1608. console.error('获取历史版本失败:', error)
  1609. ElMessage.error('获取历史版本失败')
  1610. }
  1611. }
  1612. const versionDataCompareList = ref([])
  1613. const versionColumns = ref([
  1614. {
  1615. label: '字段名',
  1616. prop: 'displayName'
  1617. },
  1618. {
  1619. label: '修改前',
  1620. prop: 'oldValue',
  1621. render: (row, value) => (
  1622. <el-text link type="default">
  1623. {value || '-'}
  1624. </el-text>
  1625. )
  1626. },
  1627. {
  1628. label: '修改后',
  1629. prop: 'newValue',
  1630. render: (row, value) => <el-text type="primary">{value || '-'}</el-text>
  1631. }
  1632. ])
  1633. const versionDetailButtons = ref([
  1634. {
  1635. render: () => (
  1636. <el-button type="success" onClick={() => handleShowReportPdf()}>
  1637. 查看原文件PDF
  1638. </el-button>
  1639. )
  1640. }
  1641. ])
  1642. const showReportDialog = ref(false)
  1643. const currentUrl = ref('')
  1644. const reportSource = ref<any | null>(null)
  1645. const pdfLoading = ref(false)
  1646. // 恢复版本
  1647. const restoreVersion = (item: any) => {
  1648. ElMessageBox.confirm('是否确定恢复到该版本?', '提示', {
  1649. confirmButtonText: '确定',
  1650. cancelButtonText: '取消',
  1651. type: 'info',
  1652. center: true
  1653. })
  1654. .then(async () => {
  1655. const result = await BoilerTaskOrderApi.saveTaskReportTemplate({
  1656. id: props.selectedItem?.id,
  1657. reportUrl: item.oldReportUrl,
  1658. prepareJson: item.oldPrepareJson,
  1659. reportType: showReportPdfType.value,
  1660. modifiedReason: '恢复版本'
  1661. })
  1662. console.log('restoreVersion', result)
  1663. if (result) {
  1664. ElMessage({
  1665. type: 'success',
  1666. message: '操作成功'
  1667. })
  1668. handleRefresh()
  1669. } else {
  1670. ElMessage.warning('操作失败,请联系管理员!')
  1671. }
  1672. })
  1673. .catch(() => {})
  1674. }
  1675. // 查看版本详情的pdf
  1676. const handleShowReportPdf = async () => {
  1677. if (currentUrl.value) {
  1678. const reportId = props.selectedItem?.id;
  1679. reportInitData.value.refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1680. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1681. reportInitData.value.templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1682. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1683. reportInitData.value.dataSource = currentUrl.value.oldPrepareJson ? JSON.parse(currentUrl.value.oldPrepareJson) : {}
  1684. console.log(currentUrl)
  1685. showReportDialog.value = true
  1686. setTimeout(()=> {
  1687. reportSpreadRef.value?.reloadView();
  1688. })
  1689. pdfLoading.value = false
  1690. } else {
  1691. ElMessage.warning('报告缺失,请联系管理员!')
  1692. }
  1693. }
  1694. const handlePdfRendered = () => {
  1695. pdfLoading.value = false
  1696. currentUrl.value = ''
  1697. }
  1698. // 查看详情
  1699. const handleShowVersionInfo = (item) => {
  1700. showVersionDetail.value = true
  1701. currentUrl.value = item
  1702. versionDataCompareList.value = JSON.parse(item.modifiedObject)
  1703. }
  1704. // 检验项目添加上传附件功能
  1705. const reportListUploadModalRef = ref<InstanceType<typeof ReportListUploadModal>>()
  1706. const handleUploadItem = () => {
  1707. reportListUploadModalRef.value?.openModal(route.query.type === 'BoilerMyTask')
  1708. }
  1709. //切换记录和报告的显示
  1710. const handleChangeShowReportPdf = (showType: string) => {
  1711. if (showType === 'report' || showType === 'result'){
  1712. if (![PressureCheckerMyTaskStatus.REPORT_INPUT,PressureCheckerMyTaskStatus.REPORT_AUDIT,PressureCheckerMyTaskStatus.REPORT_APPROVE,PressureCheckerMyTaskStatus.REPORT_END].includes(props.selectedItem.taskStatus)){
  1713. ElMessage.error('该检验项目暂未生成报告!')
  1714. showReportPdfType.value = 'record';
  1715. return;
  1716. }
  1717. }
  1718. if (showType === 'result'){
  1719. if (!props.selectedItem?.resultTemplateId){
  1720. ElMessage.error('该检验项目没有结论报告!')
  1721. showReportPdfType.value = 'record';
  1722. return;
  1723. }
  1724. }
  1725. refreshPdfFlag.value = false;
  1726. showReportPdfType.value = showType;
  1727. handleRefreshData()
  1728. }
  1729. const isCanSyncReportData = computed(() => {
  1730. return true
  1731. //return [PressureCheckerMyTaskStatus.CONFIRMED,PressureCheckerMyTaskStatus.RECORD_INPUT].includes(props.selectedItem.taskStatus)
  1732. })
  1733. const handleSyncReportData = async () => {
  1734. try {
  1735. const response = await BoilerTaskOrderApi.syncReportData({
  1736. refId: props.selectedItem.id,
  1737. reportType : showReportPdfType.value
  1738. })
  1739. if (response){
  1740. ElMessage.success('同步数据成功')
  1741. handleRefresh()
  1742. }else{
  1743. ElMessage.error('同步数据失败,请稍后重试')
  1744. }
  1745. } catch (error: any) {
  1746. console.error('同步数据失败:', error)
  1747. ElMessage.error('同步数据失败,请稍后重试')
  1748. }
  1749. }
  1750. const showAssociationOperationManual = ref(false)
  1751. const handleShowAssociationOperationManual = () => {
  1752. showAssociationOperationManual.value = true
  1753. }
  1754. onMounted(() => {
  1755. console.log(props)
  1756. //initPreview()
  1757. })
  1758. const initPreview=()=>{
  1759. const reportId = props.selectedItem?.id;
  1760. const refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1761. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1762. const templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1763. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1764. initData.value.templateId = templateId;
  1765. initData.value.refId = refId;
  1766. 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;
  1767. if (props.selectedItem.reportType === PressureReportType['INSPECTIONPLAN'] && props.selectedItem.manualUrl){
  1768. initData.value.manualUrl = props.selectedItem.manualUrl;
  1769. }else{
  1770. initData.value.manualUrl = '';
  1771. }
  1772. setTimeout(()=>{
  1773. spreadRef.value?.reloadView();
  1774. },50)
  1775. console.log('initPreview', initData.value)
  1776. }
  1777. const editPreview=(reportType: string)=>{
  1778. const reportId = props.selectedItem?.id;
  1779. const refId = showReportPdfType.value === 'report' ? "report_" + reportId :
  1780. showReportPdfType.value === 'result' ? "result_" + reportId : reportId
  1781. const templateId = showReportPdfType.value === 'report' ? templateParams.value.reportTemplateId :
  1782. showReportPdfType.value === 'result' ? templateParams.value.resultTemplateId : templateParams.value.templateId
  1783. editData.value.templateId = templateId;
  1784. editData.value.refId = refId;
  1785. editData.value.opType = 0;
  1786. setTimeout(()=>{
  1787. if (reportType === 'record'){
  1788. editSpreadRecordRef.value?.reloadView();
  1789. }else if(reportType === 'report'){
  1790. editSpreadReportRef.value?.reloadView();
  1791. }
  1792. },50)
  1793. console.log('editDataPreview', editData.value)
  1794. }
  1795. const saveSuccess = async (data)=>{
  1796. if (props.selectedItem.taskStatus >= PressureCheckerMyTaskStatus.REPORT_INPUT){
  1797. saveSuccessReport(data)
  1798. }else {
  1799. saveSuccessRecord(data)
  1800. }
  1801. }
  1802. const saveSuccessRecord = async (data)=>{
  1803. const dataJson = !data.dataSource ? '' : JSON.stringify(data.dataSource)
  1804. const params = {
  1805. id: props.selectedItem?.id,
  1806. reportUrl: props.selectedItem?.id,
  1807. prepareJson: dataJson
  1808. }
  1809. const saveResult = await BoilerTaskOrderApi.saveTaskReportTemplate(params)
  1810. if (saveResult) {
  1811. showInlineEditCheckRecord.value = false
  1812. handleRefresh()
  1813. }
  1814. }
  1815. const handleClose = () => {
  1816. ElMessageBox.confirm('是否关闭?', {
  1817. confirmButtonText: '确认',
  1818. cancelButtonText: '取消',
  1819. type: 'warning',
  1820. }).then(() => {
  1821. showInlineEditCheckRecord.value = false
  1822. showInlineReportEdit.value = false
  1823. handleRefresh()
  1824. })
  1825. }
  1826. const saveSuccessReport = async (data)=>{
  1827. const dataJson = !data.dataSource ? '' : JSON.stringify(data.dataSource)
  1828. const saveResult = BoilerTaskOrderApi.saveReportPrepare({
  1829. id: props.selectedItem?.id,
  1830. prepareJson: dataJson,
  1831. })
  1832. if(saveResult) {
  1833. showInlineReportEdit.value = false
  1834. handleRefresh()
  1835. }
  1836. }
  1837. const handleRefreshData = () => {
  1838. loadRecordList()
  1839. initPreview()
  1840. handleGetCheckKeyInputs()
  1841. getOrderHistoryVersion(props.selectedItem?.id)
  1842. }
  1843. defineExpose({
  1844. handleShowAssociationOperationManual
  1845. })
  1846. //新加
  1847. // 添加控制展开/收缩状态的变量
  1848. const isExpanded = ref(false);
  1849. // 添加切换面板展开/收缩的方法
  1850. const togglePanel = () => {
  1851. isExpanded.value = !isExpanded.value;
  1852. setTimeout((() => {
  1853. nextTick(handleWindowResize)
  1854. }), 300);
  1855. };
  1856. // 获取PDF宽度
  1857. const pdfContentWidth = ref<number>(1030)
  1858. const pdfPanelRef = ref<HTMLDivElement>()
  1859. const handleWindowResize = debounce(() => {
  1860. if(!pdfPanelRef.value) return
  1861. const width = pdfPanelRef.value?.clientWidth - 20
  1862. pdfContentWidth.value = width > 1030 ? 1030 : width
  1863. //重新加载适应宽度
  1864. spreadRef.value?.reloadView();
  1865. }, 100)
  1866. onMounted(() => {
  1867. handleWindowResize()
  1868. window.addEventListener('resize', handleWindowResize)
  1869. })
  1870. onUnmounted(() => {
  1871. window.removeEventListener('resize', handleWindowResize)
  1872. })
  1873. </script>
  1874. <style lang="scss" scoped>
  1875. .capsule-tabs {
  1876. display: inline-flex;
  1877. align-items: center;
  1878. gap: 2px;
  1879. padding: 2px;
  1880. border-radius: 20px;
  1881. margin-right: 12px;
  1882. flex-shrink: 0;
  1883. .tab-item {
  1884. display: inline-flex;
  1885. align-items: center;
  1886. justify-content: center;
  1887. padding: 4px 12px;
  1888. font-size: 12px;
  1889. background: white;
  1890. border-radius: 16px;
  1891. cursor: pointer;
  1892. transition: all 0.3s ease;
  1893. color: #606266;
  1894. font-weight: 500;
  1895. border: 1px solid transparent;
  1896. user-select: none;
  1897. white-space: nowrap;
  1898. min-width: 50px;
  1899. span {
  1900. font-size: 12px !important;
  1901. }
  1902. &:hover {
  1903. color: #409eff;
  1904. border-color: #409eff;
  1905. }
  1906. &.active {
  1907. background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
  1908. color: white;
  1909. border-color: #409eff;
  1910. box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
  1911. }
  1912. }
  1913. }
  1914. .container-panel {
  1915. height: 100%;
  1916. border: 1px solid var(--el-border-color);
  1917. .info-panel {
  1918. display: flex;
  1919. height: 32px;
  1920. padding: 0 8px 0 22px;
  1921. font-size: 14px;
  1922. color: #41475c;
  1923. background-color: #effaff;
  1924. justify-content: space-between;
  1925. align-items: center;
  1926. }
  1927. .status-operation-panel {
  1928. height: calc(100% - 32px);
  1929. .single-item-panel {
  1930. display: flex;
  1931. align-items: stretch;
  1932. justify-content: space-between;
  1933. width: 100%;
  1934. height: 100%;
  1935. }
  1936. .pdf-panel {
  1937. height: 100%;
  1938. padding: 10px;
  1939. flex: 1;
  1940. overflow: hidden;
  1941. }
  1942. .right-panel-container {
  1943. display: flex;
  1944. position: relative;
  1945. // 收缩展开按钮样式
  1946. .toggle-btn {
  1947. position: absolute;
  1948. left: -30px;
  1949. top: 50%;
  1950. transform: translateY(-50%);
  1951. width: 30px;
  1952. height: 60px;
  1953. background-color: #fff;
  1954. border: 1px solid var(--el-border-color);
  1955. border-radius: 10px 0 0 10px;
  1956. display: flex;
  1957. align-items: center;
  1958. justify-content: center;
  1959. cursor: pointer;
  1960. z-index: 100;
  1961. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  1962. transition: all 0.3s ease;
  1963. &:hover {
  1964. background-color: #f5f5f5;
  1965. }
  1966. &.collapsed {
  1967. left: -18px;
  1968. // border-radius: 0 10px 10px 0;
  1969. }
  1970. }
  1971. }
  1972. .operation-panel {
  1973. flex-basis: 300px;
  1974. padding: 10px 10px 10px 0;
  1975. box-sizing: border-box;
  1976. transition: all 0.3s ease;
  1977. // 展开状态样式
  1978. &.expanded {
  1979. width: 300px;
  1980. }
  1981. // 收缩状态样式
  1982. &.collapsed {
  1983. width: 0;
  1984. padding: 0;
  1985. border: none;
  1986. .default-toolbar,
  1987. .operation-inner {
  1988. display: none;
  1989. }
  1990. }
  1991. .operation-btns {
  1992. display: flex;
  1993. flex-wrap: wrap;
  1994. gap: 12px;
  1995. .el-button {
  1996. margin-bottom: 10px;
  1997. margin-left: 0;
  1998. }
  1999. }
  2000. }
  2001. .operation-inner {
  2002. height: 100%;
  2003. padding: 7px 10px 20px;
  2004. background-color: #fff;
  2005. border: 1px solid var(--el-border-color);
  2006. box-sizing: border-box;
  2007. }
  2008. .custom-inner{
  2009. display: flex;
  2010. flex-direction: column;
  2011. overflow: hidden;
  2012. height: 100%;
  2013. padding: 7px 10px 20px;
  2014. background-color: #fff;
  2015. border: 1px solid var(--el-border-color);
  2016. box-sizing: border-box;
  2017. .operation-item1 {
  2018. position: relative;
  2019. margin-bottom: 10px;
  2020. overflow-y: auto;
  2021. .item-header {
  2022. position: sticky;
  2023. top: 0;
  2024. left: 0;
  2025. z-index: 1000;
  2026. width: 100%;
  2027. height: 28px;
  2028. padding-left: 20px;
  2029. font-size: 16px;
  2030. line-height: 28px;
  2031. color: #fff;
  2032. background: #fff url('@/assets/imgs/pressure/my-task-detail-operation-bg.png') no-repeat
  2033. left top;
  2034. background-size: 100% 28px;
  2035. }
  2036. .item-content1 {
  2037. display: flex;
  2038. margin-top: 10px;
  2039. &-item {
  2040. font-size: 14px;
  2041. }
  2042. &-img {
  2043. flex: 1;
  2044. display: grid;
  2045. grid-template-columns: repeat(3, 1fr);
  2046. grid-gap: 10px;
  2047. .item-content1-img-item{
  2048. width: 100px;
  2049. height: 100px;
  2050. position: relative;
  2051. .list-item-tool {
  2052. position: absolute;
  2053. top: 0;
  2054. left: 0;
  2055. width: 100%;
  2056. height: 100%;
  2057. z-index: 99;
  2058. border-radius: 8px;
  2059. transition: all 0.5s ease;
  2060. cursor: pointer;
  2061. display: flex;
  2062. justify-content: center;
  2063. align-items: center;
  2064. gap: 5px;
  2065. &:hover {
  2066. backdrop-filter: blur(2px);
  2067. background-color: #00000076;
  2068. z-index: 1;
  2069. .icon {
  2070. display: inline-block;
  2071. opacity: 1;
  2072. &:hover {
  2073. color: #ffffff;
  2074. transition: all 0.5s ease;
  2075. }
  2076. }
  2077. }
  2078. .icon {
  2079. color: #ffffff99;
  2080. opacity: 0;
  2081. transition: all 0.5s ease;
  2082. font-size: 16px;
  2083. }
  2084. }
  2085. }
  2086. .img-item {
  2087. width: 100px;
  2088. height: 100px;
  2089. }
  2090. }
  2091. }
  2092. .record-item {
  2093. margin-bottom: 10px;
  2094. background-color: #f5f5fa;
  2095. border-radius: 2px;
  2096. }
  2097. .item-content {
  2098. padding: 10px 0;
  2099. font-size: 14px;
  2100. .el-empty {
  2101. width: 100%;
  2102. height: 150px;
  2103. padding: 0;
  2104. box-sizing: border-box;
  2105. }
  2106. &-item {
  2107. height: 32px;
  2108. display: flex;
  2109. align-items: center;
  2110. gap: 8px;
  2111. }
  2112. }
  2113. .record-item-title {
  2114. height: 31px;
  2115. padding: 0 13px;
  2116. line-height: 31px;
  2117. background: linear-gradient(270deg, rgb(128 176 251 / 20%) 0%, rgb(73 120 246 / 20%) 100%);
  2118. border-radius: 2px;
  2119. }
  2120. .record-item-inner {
  2121. padding: 11px 13px 8px;
  2122. .content {
  2123. display: flex;
  2124. align-items: center;
  2125. .el-button {
  2126. margin-left: 8px;
  2127. }
  2128. :deep(.el-button--small.is-round) {
  2129. height: auto;
  2130. padding: 3px 11px;
  2131. }
  2132. .time {
  2133. color: rgb(31 31 31 / 88%);
  2134. text-align: right;
  2135. opacity: 0.5;
  2136. flex: 1;
  2137. }
  2138. }
  2139. .desc {
  2140. margin-top: 7px;
  2141. color: #41475c;
  2142. opacity: 0.8;
  2143. span {
  2144. opacity: 0.5;
  2145. }
  2146. }
  2147. }
  2148. .error-item {
  2149. display: flex;
  2150. padding: 7px 10px;
  2151. color: #41475c;
  2152. background-color: #f5f5fa;
  2153. border: 1px solid var(--el-border-color);
  2154. border-width: 1px 0;
  2155. align-items: center;
  2156. .el-icon {
  2157. margin-right: 6px;
  2158. }
  2159. &:nth-child(n + 1) {
  2160. margin-top: -1px;
  2161. }
  2162. &:nth-child(even) {
  2163. background-color: #fff;
  2164. }
  2165. }
  2166. .history-item {
  2167. padding: 7px 10px 10px;
  2168. margin-bottom: 13px;
  2169. color: #41475c;
  2170. background-color: #f5f5fa;
  2171. border-radius: 2px;
  2172. .history-title {
  2173. display: flex;
  2174. align-items: center;
  2175. margin-left: -10px;
  2176. font-weight: 600;
  2177. line-height: 20px;
  2178. &::before {
  2179. display: block;
  2180. width: 4px;
  2181. height: 15px;
  2182. margin-right: 7px;
  2183. background: #4978f6;
  2184. content: '';
  2185. }
  2186. }
  2187. p {
  2188. margin: 10px 0;
  2189. line-height: 20px;
  2190. }
  2191. .history-footer {
  2192. display: flex;
  2193. // align-items: center;
  2194. font-size: 12px;
  2195. .name {
  2196. color: #4978f6;
  2197. }
  2198. .time {
  2199. margin-left: 2px;
  2200. color: rgb(65 71 92 / 50%);
  2201. }
  2202. div {
  2203. flex: 1;
  2204. display: flex;
  2205. justify-content: flex-end;
  2206. .el-button span {
  2207. font-size: 12px;
  2208. }
  2209. }
  2210. }
  2211. }
  2212. }
  2213. .videoAndImg {
  2214. flex: 1;
  2215. width: 100%;
  2216. overflow-y: auto;
  2217. }
  2218. }
  2219. .operation-item {
  2220. position: relative;
  2221. max-height: calc(100% / 3 - 10px);
  2222. margin-bottom: 10px;
  2223. overflow-y: auto;
  2224. .item-header {
  2225. position: sticky;
  2226. top: 0;
  2227. left: 0;
  2228. z-index: 1000;
  2229. width: 100%;
  2230. height: 28px;
  2231. padding-left: 20px;
  2232. font-size: 16px;
  2233. line-height: 28px;
  2234. color: #fff;
  2235. background: #fff url('@/assets/imgs/pressure/my-task-detail-operation-bg.png') no-repeat
  2236. left top;
  2237. background-size: 100% 28px;
  2238. }
  2239. .item-content1 {
  2240. display: flex;
  2241. margin-top: 10px;
  2242. &-item {
  2243. font-size: 14px;
  2244. }
  2245. &-img {
  2246. flex: 1;
  2247. display: grid;
  2248. grid-template-columns: repeat(3, 1fr);
  2249. grid-gap: 10px;
  2250. .item-content1-img-item{
  2251. width: 100px;
  2252. height: 100px;
  2253. position: relative;
  2254. .list-item-tool {
  2255. position: absolute;
  2256. top: 0;
  2257. left: 0;
  2258. width: 100%;
  2259. height: 100%;
  2260. z-index: 99;
  2261. border-radius: 8px;
  2262. transition: all 0.5s ease;
  2263. cursor: pointer;
  2264. display: flex;
  2265. justify-content: center;
  2266. align-items: center;
  2267. gap: 5px;
  2268. &:hover {
  2269. backdrop-filter: blur(2px);
  2270. background-color: #00000076;
  2271. z-index: 1;
  2272. .icon {
  2273. display: inline-block;
  2274. opacity: 1;
  2275. &:hover {
  2276. color: #ffffff;
  2277. transition: all 0.5s ease;
  2278. }
  2279. }
  2280. }
  2281. .icon {
  2282. color: #ffffff99;
  2283. opacity: 0;
  2284. transition: all 0.5s ease;
  2285. font-size: 16px;
  2286. }
  2287. }
  2288. }
  2289. .img-item {
  2290. width: 100px;
  2291. height: 100px;
  2292. }
  2293. }
  2294. }
  2295. .record-item {
  2296. margin-bottom: 10px;
  2297. background-color: #f5f5fa;
  2298. border-radius: 2px;
  2299. }
  2300. .item-content {
  2301. padding: 10px 0;
  2302. font-size: 14px;
  2303. .el-empty {
  2304. width: 100%;
  2305. height: 150px;
  2306. padding: 0;
  2307. box-sizing: border-box;
  2308. }
  2309. &-item {
  2310. height: 32px;
  2311. display: flex;
  2312. align-items: center;
  2313. gap: 8px;
  2314. }
  2315. }
  2316. .record-item-title {
  2317. height: 31px;
  2318. padding: 0 13px;
  2319. line-height: 31px;
  2320. background: linear-gradient(270deg, rgb(128 176 251 / 20%) 0%, rgb(73 120 246 / 20%) 100%);
  2321. border-radius: 2px;
  2322. }
  2323. .record-item-inner {
  2324. padding: 11px 13px 8px;
  2325. .content {
  2326. display: flex;
  2327. align-items: center;
  2328. .el-button {
  2329. margin-left: 8px;
  2330. }
  2331. :deep(.el-button--small.is-round) {
  2332. height: auto;
  2333. padding: 3px 11px;
  2334. }
  2335. .time {
  2336. color: rgb(31 31 31 / 88%);
  2337. text-align: right;
  2338. opacity: 0.5;
  2339. flex: 1;
  2340. }
  2341. }
  2342. .desc {
  2343. margin-top: 7px;
  2344. color: #41475c;
  2345. opacity: 0.8;
  2346. span {
  2347. opacity: 0.5;
  2348. }
  2349. }
  2350. }
  2351. .error-item {
  2352. display: flex;
  2353. padding: 7px 10px;
  2354. color: #41475c;
  2355. background-color: #f5f5fa;
  2356. border: 1px solid var(--el-border-color);
  2357. border-width: 1px 0;
  2358. align-items: center;
  2359. .el-icon {
  2360. margin-right: 6px;
  2361. }
  2362. &:nth-child(n + 1) {
  2363. margin-top: -1px;
  2364. }
  2365. &:nth-child(even) {
  2366. background-color: #fff;
  2367. }
  2368. }
  2369. .history-item {
  2370. padding: 7px 10px 10px;
  2371. margin-bottom: 13px;
  2372. color: #41475c;
  2373. background-color: #f5f5fa;
  2374. border-radius: 2px;
  2375. .history-title {
  2376. display: flex;
  2377. align-items: center;
  2378. margin-left: -10px;
  2379. font-weight: 600;
  2380. line-height: 20px;
  2381. &::before {
  2382. display: block;
  2383. width: 4px;
  2384. height: 15px;
  2385. margin-right: 7px;
  2386. background: #4978f6;
  2387. content: '';
  2388. }
  2389. }
  2390. p {
  2391. margin: 10px 0;
  2392. line-height: 20px;
  2393. }
  2394. .history-footer {
  2395. display: flex;
  2396. // align-items: center;
  2397. font-size: 12px;
  2398. .name {
  2399. color: #4978f6;
  2400. }
  2401. .time {
  2402. margin-left: 2px;
  2403. color: rgb(65 71 92 / 50%);
  2404. }
  2405. div {
  2406. flex: 1;
  2407. display: flex;
  2408. justify-content: flex-end;
  2409. .el-button span {
  2410. font-size: 12px;
  2411. }
  2412. }
  2413. }
  2414. }
  2415. }
  2416. }
  2417. }
  2418. .default-toolbar {
  2419. display: flex;
  2420. justify-content: flex-end;
  2421. gap: 16px;
  2422. margin-bottom: 20px;
  2423. white-space: nowrap;
  2424. ::v-deep .el-button {
  2425. margin-left: 0;
  2426. }
  2427. }
  2428. // 退回对话框样式
  2429. .reject-dialog-content {
  2430. .form-item {
  2431. margin-bottom: 20px;
  2432. &:last-child {
  2433. margin-bottom: 0;
  2434. }
  2435. .form-label {
  2436. display: block;
  2437. margin-bottom: 8px;
  2438. font-size: 14px;
  2439. font-weight: 500;
  2440. color: #606266;
  2441. }
  2442. }
  2443. }
  2444. :deep(.preview-dialog) {
  2445. background-color: transparent !important;
  2446. width: auto !important;
  2447. padding: 0 !important;
  2448. .el-dialog__header {
  2449. display: none;
  2450. }
  2451. .el-dialog__body{
  2452. padding: 0;
  2453. .preview-container{
  2454. padding: 0;
  2455. position: relative;
  2456. }
  2457. .preview-image,.preview-video {
  2458. height: 65vh;
  2459. max-width: 100vw;
  2460. // object-fit: cover;
  2461. }
  2462. }
  2463. }
  2464. </style>