StatusOperationPanel.vue 81 KB

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