areaCheckPlanManagementDetail.vue 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. <template>
  2. <!-- 查看模式:由 顶部摘要、基本信息、检查内容与业务工作、检查记录 组成 -->
  3. <main v-if="isViewMode" class="safety-platform-container__main area-check-plan-view">
  4. <section class="view-section view-summary">
  5. <div class="view-summary__title">一级危险点:{{ viewDetail.checkVenue || '-' }}</div>
  6. <div class="view-summary__meta">
  7. <span>检查类别:{{ viewDetail.venueCategoryName || '-' }}</span>
  8. <span>创建人:{{ viewDetail.createdBy || '-' }}</span>
  9. <span>创建时间:{{ viewDetail.createdAt || '-' }}</span>
  10. </div>
  11. </section>
  12. <section class="view-section audit-content">
  13. <h4 class="section-title">
  14. <el-icon class="section-title__icon"><Document /></el-icon>
  15. <span>基本信息</span>
  16. </h4>
  17. <div class="detail-ct detail-ct--table">
  18. <div class="row">
  19. <div class="col">
  20. <div class="label">区域计划名称:</div>
  21. <div class="value">{{ viewDetail.planName || '-' }}</div>
  22. </div>
  23. <div class="col">
  24. <div class="label">状态:</div>
  25. <div class="value">{{ viewDetail.statusName || '进行中' }}</div>
  26. </div>
  27. </div>
  28. <div class="row">
  29. <div class="col">
  30. <div class="label">主责部门:</div>
  31. <div class="value">{{ viewDetail.primary_responsible_dept_name || viewDetail.mainDeptName || '-' }}</div>
  32. </div>
  33. <div class="col">
  34. <div class="label">自查频率:</div>
  35. <div class="value">{{ viewDetail.selfCheckFrequency || '-' }}</div>
  36. </div>
  37. </div>
  38. <div class="row">
  39. <div class="col">
  40. <div class="label">主责部门执行人所属分组名称:</div>
  41. <div class="value">{{ viewDetail.mainDeptExecutorGroupName || '-' }}</div>
  42. </div>
  43. <div class="col">
  44. <div class="label">主责部门责任人:</div>
  45. <div class="value">{{ viewDetail.mainDeptResponsiblePerson || '-' }}</div>
  46. </div>
  47. </div>
  48. <div class="row">
  49. <div class="col">
  50. <div class="label">安全应急部部门名称:</div>
  51. <div class="value">{{ viewDetail.safetyEmergencyDeptName || '-' }}</div>
  52. </div>
  53. <div class="col">
  54. <div class="label">安全应急部检查频次:</div>
  55. <div class="value">{{ viewDetail.safetyEmergencyCheckFrequency || '-' }}</div>
  56. </div>
  57. </div>
  58. <div class="row">
  59. <div class="col">
  60. <div class="label">安全应急部执行人所属分组名称:</div>
  61. <div class="value">{{ viewDetail.safetyEmergencyExecutorGroupName || '-' }}</div>
  62. </div>
  63. <div class="col">
  64. <div class="label">安全应急部责任人:</div>
  65. <div class="value">{{ viewDetail.safetyEmergencyResponsiblePerson || '-' }}</div>
  66. </div>
  67. </div>
  68. <div class="row">
  69. <div class="col">
  70. <div class="label">院领导部门名称:</div>
  71. <div class="value">{{ viewDetail.hospitalLeaderDeptName || '-' }}</div>
  72. </div>
  73. <div class="col">
  74. <div class="label">院领导检查频次:</div>
  75. <div class="value">{{ viewDetail.hospitalLeaderCheckFrequency || '-' }}</div>
  76. </div>
  77. </div>
  78. <div class="row">
  79. <div class="col">
  80. <div class="label">院领导执行人所属分组名称:</div>
  81. <div class="value">{{ viewDetail.hospitalLeaderExecutorGroupName || '-' }}</div>
  82. </div>
  83. <div class="col">
  84. <div class="label">院领导责任人:</div>
  85. <div class="value">{{ viewDetail.hospitalLeaderResponsiblePerson || '-' }}</div>
  86. </div>
  87. </div>
  88. <div class="row">
  89. <div class="col">
  90. <div class="label">检查单所属类别名称:</div>
  91. <div class="value">{{ viewDetail.categoryName || '-' }}</div>
  92. </div>
  93. <div class="col">
  94. <div class="label">检查单模版名称:</div>
  95. <div class="value">{{ viewDetail.checklistTemplateName || '-' }}</div>
  96. </div>
  97. </div>
  98. <div class="row">
  99. <div class="col">
  100. <div class="label">是否需要整体检查情况描述:</div>
  101. <div class="value">{{ viewDetail.needOverallDesc === true ? '是' : viewDetail.needOverallDesc === false ? '否' : '-' }}</div>
  102. </div>
  103. <div class="col">
  104. <div class="label">是否需要被检查人签字:</div>
  105. <div class="value">{{ viewDetail.needInspectedSign === true ? '是' : viewDetail.needInspectedSign === false ? '否' : '-' }}</div>
  106. </div>
  107. </div>
  108. <div class="row">
  109. <div class="col">
  110. <div class="label">计划开始日期:</div>
  111. <div class="value">{{ viewDetail.planStartTime || '-' }}</div>
  112. </div>
  113. <div class="col">
  114. <div class="label">计划完成日期:</div>
  115. <div class="value">{{ viewDetail.planEndTime || '-' }}</div>
  116. </div>
  117. </div>
  118. <div class="row">
  119. <div class="col">
  120. <div class="label">检查内容:</div>
  121. <div class="value value--list">
  122. <ol class="inspection-content-list">
  123. <li v-for="(item, i) in inspectionContentList" :key="i">{{ item }}</li>
  124. </ol>
  125. </div>
  126. </div>
  127. <div class="col">
  128. <div class="label">业务工作:</div>
  129. <div class="value">{{ viewDetail.businessWork || '-' }}</div>
  130. </div>
  131. </div>
  132. </div>
  133. </section>
  134. <section class="view-section">
  135. <div class="view-section__title">
  136. <span class="view-section__icon" />
  137. 检查记录
  138. </div>
  139. <div class="view-record-toolbar">
  140. <el-input
  141. v-model="recordSearchKeyword"
  142. placeholder="检查场所类别/检查场所/检查人员"
  143. clearable
  144. style="width: 280px; margin-right: 12px"
  145. />
  146. <el-date-picker
  147. v-model="recordDateRange"
  148. type="daterange"
  149. range-separator="-"
  150. start-placeholder="开始日期"
  151. end-placeholder="结束日期"
  152. value-format="YYYY-MM-DD"
  153. style="margin-right: 12px"
  154. />
  155. <el-button type="primary" @click="onRecordSearch">查询</el-button>
  156. <el-button @click="onRecordExport">导出</el-button>
  157. </div>
  158. <BasicTable
  159. :tableData="paginatedRecordList"
  160. :tableConfig="recordTableConfig"
  161. class="view-record-table"
  162. @update:pageSize="handleRecordSizeChange"
  163. @update:pageNumber="handleRecordPageChange"
  164. >
  165. <template #unqualifiedItemNum="scope">
  166. <el-button
  167. v-if="Number(scope.row.unqualifiedItemNum) > 0"
  168. type="primary"
  169. link
  170. size="small"
  171. @click="openUnqualifiedDialog(scope.row)"
  172. >
  173. {{ scope.row.unqualifiedItemNum }}
  174. </el-button>
  175. <span v-else>{{ scope.row.unqualifiedItemNum ?? 0 }}</span>
  176. </template>
  177. <template #sign="scope">
  178. <template v-if="parseSignFiles(scope.row.checkedPersonSign || scope.row.signFile).length">
  179. <div
  180. class="file-container--div"
  181. v-for="item in parseSignFiles(scope.row.checkedPersonSign || scope.row.signFile)"
  182. :key="item.fileUrl || item.fileName"
  183. >
  184. <img
  185. class="file-container--div__icon"
  186. :src="FILE_TYPE_ICON[item.fileType as keyof typeof FILE_TYPE_ICON]"
  187. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  188. />
  189. <span
  190. class="file-container--div__name"
  191. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  192. >{{ item.fileName }}</span
  193. >
  194. <img
  195. class="file-container--div__download"
  196. :src="DownloadIcon"
  197. @click="downloadFile(item.fileUrl, item.fileName)"
  198. />
  199. </div>
  200. </template>
  201. <span v-else>-</span>
  202. </template>
  203. <template #action="scope">
  204. <el-button type="danger" link size="small" @click="onDeleteRecord(scope.row)">删除</el-button>
  205. <el-button type="primary" link size="small" @click="onViewRecord(scope.row)">检查记录查看</el-button>
  206. </template>
  207. </BasicTable>
  208. </section>
  209. </main>
  210. <main v-else class="safety-platform-container__main">
  211. <BasicForm
  212. ref="basicFormRef"
  213. :formData="ruleFormData"
  214. :formRules="isViewMode ? undefined : formRules"
  215. :formConfig="computedFormConfig"
  216. >
  217. <template #mainDept>
  218. <el-cascader
  219. ref="mainDeptCascaderRef"
  220. v-model="ruleFormData.primary_responsible_dept_id"
  221. :options="deptTree"
  222. :props="cascaderDeptProp"
  223. :show-all-levels="false"
  224. placeholder="请选择部门"
  225. filterable
  226. clearable
  227. :disabled="isViewMode"
  228. style="width: 100%"
  229. @change="onMainDeptChange"
  230. />
  231. </template>
  232. <template #safetyEmergencyDept>
  233. <el-cascader
  234. ref="safetyEmergencyDeptCascaderRef"
  235. v-model="ruleFormData.safetyEmergencyDeptId"
  236. :options="deptTree"
  237. :props="cascaderDeptProp"
  238. :show-all-levels="false"
  239. placeholder="请选择部门"
  240. filterable
  241. clearable
  242. :disabled="isViewMode"
  243. style="width: 100%"
  244. @change="onSafetyEmergencyDeptChange"
  245. />
  246. </template>
  247. <template #hospitalLeaderDept>
  248. <el-cascader
  249. ref="hospitalLeaderDeptCascaderRef"
  250. v-model="ruleFormData.hospitalLeaderDeptId"
  251. :options="deptTree"
  252. :props="cascaderDeptProp"
  253. :show-all-levels="false"
  254. placeholder="请选择部门"
  255. filterable
  256. clearable
  257. :disabled="isViewMode"
  258. style="width: 100%"
  259. @change="onHospitalLeaderDeptChange"
  260. />
  261. </template>
  262. <template #selfCheckFrequency>
  263. <el-radio-group v-model="ruleFormData.selfCheckFrequency" :disabled="isViewMode">
  264. <el-radio
  265. v-for="opt in CHECK_FREQUENCY_OPTIONS"
  266. :key="opt.value"
  267. :value="opt.value"
  268. >
  269. {{ opt.label }}
  270. </el-radio>
  271. </el-radio-group>
  272. </template>
  273. <template #safetyEmergencyCheckFrequency>
  274. <el-radio-group v-model="ruleFormData.safetyEmergencyCheckFrequency" :disabled="isViewMode">
  275. <el-radio
  276. v-for="opt in CHECK_FREQUENCY_OPTIONS"
  277. :key="opt.value"
  278. :value="opt.value"
  279. >
  280. {{ opt.label }}
  281. </el-radio>
  282. </el-radio-group>
  283. </template>
  284. <template #hospitalLeaderCheckFrequency>
  285. <el-radio-group v-model="ruleFormData.hospitalLeaderCheckFrequency" :disabled="isViewMode">
  286. <el-radio
  287. v-for="opt in CHECK_FREQUENCY_OPTIONS"
  288. :key="opt.value"
  289. :value="opt.value"
  290. >
  291. {{ opt.label }}
  292. </el-radio>
  293. </el-radio-group>
  294. </template>
  295. </BasicForm>
  296. </main>
  297. <footer class="safety-platform-container__footer">
  298. <el-button @click="router.back()">返回</el-button>
  299. <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
  300. {{ isCreateMode ? '提交' : '保存' }}
  301. </el-button>
  302. </footer>
  303. <PreviewOnline ref="previewOnlineRef" />
  304. <!-- 检查不合格数据弹窗(管理员) -->
  305. <el-dialog
  306. v-model="showUnqualifiedDialog"
  307. title="检查不合格数据"
  308. width="800px"
  309. destroy-on-close
  310. >
  311. <BasicTable
  312. :tableData="unqualifiedList"
  313. :tableConfig="unqualifiedTableConfig"
  314. @update:pageSize="handleUnqualifiedSizeChange"
  315. @update:pageNumber="handleUnqualifiedPageChange"
  316. >
  317. <template #action="scope">
  318. <el-button
  319. v-if="Number(scope.row.isSand) === 0"
  320. type="primary"
  321. link
  322. size="small"
  323. @click="handleSandToHiddenDanger(scope.row)"
  324. >
  325. 下入账
  326. </el-button>
  327. <span v-else-if="Number(scope.row.isSand) === 1" style="color: #999999">已入账</span>
  328. <span v-else>-</span>
  329. </template>
  330. </BasicTable>
  331. </el-dialog>
  332. <!-- 检查记录入账隐患台账确认弹窗 -->
  333. <el-dialog
  334. v-model="showSandConfirmDialog"
  335. title="检查记录入账隐患台账"
  336. width="900px"
  337. destroy-on-close
  338. >
  339. <BasicForm
  340. ref="sandHiddenDangerFormRef"
  341. :formData="sandHiddenDangerFormData"
  342. :formRules="sandHiddenDangerFormRules"
  343. :formConfig="sandHiddenDangerFormConfig"
  344. >
  345. <template #reviewDepartmentId>
  346. <el-cascader
  347. v-model="sandHiddenDangerFormData.reviewDepartmentId"
  348. :options="deptTree"
  349. :props="cascaderDeptProp"
  350. :show-all-levels="false"
  351. placeholder="请选择复查人员所属部门"
  352. filterable
  353. clearable
  354. style="width: 100%"
  355. />
  356. </template>
  357. <template #reviewPerson>
  358. <el-select
  359. v-model="sandHiddenDangerFormData.reviewPersonId"
  360. placeholder="请选择复查人员"
  361. clearable
  362. filterable
  363. style="width: 100%"
  364. >
  365. <el-option
  366. v-for="u in reviewUserList"
  367. :key="u.id"
  368. :label="u.realname || u.username"
  369. :value="u.id"
  370. />
  371. </el-select>
  372. </template>
  373. <template #isDrawLessonsPush>
  374. <el-radio-group v-model="sandHiddenDangerFormData.isDrawLessonsPush">
  375. <el-radio :value="0">否</el-radio>
  376. <el-radio :value="1">是</el-radio>
  377. </el-radio-group>
  378. </template>
  379. <template #drawLessonsDepartmentIds>
  380. <el-select
  381. v-model="drawLessonsDeptIdsArray"
  382. placeholder="请选择举一反三责任部门,可多选"
  383. clearable
  384. filterable
  385. multiple
  386. collapse-tags
  387. collapse-tags-tooltip
  388. style="width: 100%"
  389. @change="() => { sandHiddenDangerFormData.drawLessonsDepartmentIds = drawLessonsDeptIdsArray.join(','); }"
  390. >
  391. <el-option
  392. v-for="d in deptOptions"
  393. :key="d.id"
  394. :label="d.deptName"
  395. :value="d.id"
  396. />
  397. </el-select>
  398. </template>
  399. </BasicForm>
  400. <template #footer>
  401. <el-button @click="showSandConfirmDialog = false">取消</el-button>
  402. <el-button type="primary" :loading="sandConfirmLoading" @click="confirmSandToHiddenDanger">
  403. 提交
  404. </el-button>
  405. </template>
  406. </el-dialog>
  407. </template>
  408. <script setup lang="ts">
  409. import { computed, onMounted, ref, watch } from 'vue';
  410. import { useRoute, useRouter } from 'vue-router';
  411. import { ElMessage } from 'element-plus';
  412. import { Document } from '@element-plus/icons-vue';
  413. import BasicForm from '@/components/BasicForm.vue';
  414. import BasicTable from '@/components/BasicTable.vue';
  415. import { FILE_TYPE_ICON } from '@/components/UploadFiles/constants';
  416. import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
  417. import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
  418. import { downloadFile } from '@/views/disaster/utils';
  419. import { useFormConfigHook } from '@/hooks/useFormConfigHook';
  420. import useTableConfig from '@/hooks/useTableConfigHook';
  421. import type { TableColumnProps } from '@/types/basic-table';
  422. import {
  423. AREA_CHECK_PLAN_FORM_CONFIG as AREA_CHECK_PLAN_FORM_CONFIG_IMPORT,
  424. AREA_CHECK_PLAN_FORM_DATA as AREA_CHECK_PLAN_FORM_DATA_IMPORT,
  425. AREA_CHECK_PLAN_FORM_RULES as AREA_CHECK_PLAN_FORM_RULES_IMPORT,
  426. CHECK_FREQUENCY_OPTIONS as CHECK_FREQUENCY_OPTIONS_IMPORT,
  427. } from '../configs/form';
  428. import type { AreaCheckPlanRecord } from '../configs/types';
  429. import { AREA_CHECK_PLAN_STATUS_LABEL } from '../configs/status';
  430. import { getAllDepartments } from '@/api/auth/dept';
  431. import type { DeptTree } from '@/types/dept/type';
  432. import { cloneDeep } from 'lodash-es';
  433. import {
  434. queryAreaCheckPlanManageDetail,
  435. saveAreaCheckPlanManage,
  436. updateAreaCheckPlanManage,
  437. queryAreaCheckPlanDetailPage,
  438. deleteAreaCheckPlanDetail,
  439. queryAreaCheckRecord,
  440. mapAreaCheckPlanApiRecordToUi,
  441. queryCheckListTemplateNameList,
  442. queryUnqualifiedItemNumPage,
  443. sandAreaCheckRecordToProductionHiddenDanger,
  444. type ChecklistTemplate,
  445. type UnqualifiedItemNumRecord,
  446. type SandAreaCheckRecordToHiddenDangerReq,
  447. } from '@/api/production-safety-system';
  448. import { queryDictTypeDetail } from '@/api/dict';
  449. import {
  450. HIDDEN_DANGER_FORM_CONFIG,
  451. HIDDEN_DANGER_FORM_DATA,
  452. HIDDEN_DANGER_FORM_RULES,
  453. } from '@/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleAccountManagement/configs/form';
  454. const router = useRouter();
  455. const route = useRoute();
  456. const operate = computed(() => (route.query.operate as string) || 'area-check-plan-create');
  457. const currentId = computed(() => Number(route.query.id));
  458. const isCreateMode = computed(() => operate.value === 'area-check-plan-create');
  459. const isEditMode = computed(() => operate.value === 'area-check-plan-edit');
  460. const isViewMode = computed(() => operate.value === 'area-check-plan-view');
  461. const AREA_CHECK_PLAN_FORM_CONFIG = AREA_CHECK_PLAN_FORM_CONFIG_IMPORT ?? [];
  462. const AREA_CHECK_PLAN_FORM_DATA = AREA_CHECK_PLAN_FORM_DATA_IMPORT ?? {};
  463. const AREA_CHECK_PLAN_FORM_RULES = AREA_CHECK_PLAN_FORM_RULES_IMPORT ?? {};
  464. const CHECK_FREQUENCY_OPTIONS = CHECK_FREQUENCY_OPTIONS_IMPORT ?? [];
  465. const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } = useFormConfigHook(
  466. AREA_CHECK_PLAN_FORM_CONFIG,
  467. AREA_CHECK_PLAN_FORM_DATA as Record<string, unknown>,
  468. AREA_CHECK_PLAN_FORM_RULES,
  469. );
  470. // 部门树,与新增物品领取记录页的部门下拉一致(getAllDepartments,取第一级 children)
  471. const mainDeptCascaderRef = ref();
  472. const safetyEmergencyDeptCascaderRef = ref();
  473. const hospitalLeaderDeptCascaderRef = ref();
  474. const deptTree = ref<DeptTree[]>([]);
  475. const cascaderDeptProp = {
  476. checkStrictly: true,
  477. expandTrigger: 'hover' as const,
  478. value: 'id',
  479. label: 'deptName',
  480. emitPath: false,
  481. };
  482. /** 部门树:主责部门、安全应急部门、院领导部门均使用 getAllDepartments 接口 */
  483. const getDeptTreeData = async () => {
  484. try {
  485. const res = await getAllDepartments();
  486. deptTree.value = res?.[0]?.children ?? [];
  487. } catch (e) {
  488. console.error('获取部门树失败:', e);
  489. deptTree.value = [];
  490. }
  491. };
  492. const findDeptIdByName = (nodes: DeptTree[] | undefined, name: string): number | undefined => {
  493. if (!nodes?.length) return undefined;
  494. for (const n of nodes) {
  495. if (n.deptName === name) return n.id ?? undefined;
  496. const found = findDeptIdByName(n.children, name);
  497. if (found != null) return found;
  498. }
  499. return undefined;
  500. };
  501. const setDeptNameFromCascader = (refVal: any, nameKey: 'primary_responsible_dept_name' | 'safetyEmergencyDeptName' | 'hospitalLeaderDeptName') => {
  502. const nodes = refVal?.getCheckedNodes?.();
  503. const label = nodes?.[0]?.label ?? '';
  504. const value = nodes?.[0]?.value;
  505. if (nameKey === 'primary_responsible_dept_name') {
  506. ruleFormData.primary_responsible_dept_name = label;
  507. (ruleFormData as Record<string, unknown>).primary_responsible_dept_code = value != null ? String(value) : '';
  508. } else {
  509. (ruleFormData as Record<string, unknown>)[nameKey] = label;
  510. }
  511. };
  512. const onMainDeptChange = () => {
  513. setDeptNameFromCascader(mainDeptCascaderRef.value, 'primary_responsible_dept_name');
  514. };
  515. const onSafetyEmergencyDeptChange = () => {
  516. setDeptNameFromCascader(safetyEmergencyDeptCascaderRef.value, 'safetyEmergencyDeptName');
  517. };
  518. const onHospitalLeaderDeptChange = () => {
  519. setDeptNameFromCascader(hospitalLeaderDeptCascaderRef.value, 'hospitalLeaderDeptName');
  520. };
  521. // 检查单模版类别:使用 admin/dict/queryDictTypeDetail 接口
  522. const checklistCategoryOptions = ref<Array<{ label: string; value: string }>>([]);
  523. const loadChecklistCategoryOptions = async () => {
  524. try {
  525. const res = await queryDictTypeDetail('checklist_template');
  526. const list = res?.sysDictDataList ?? [];
  527. checklistCategoryOptions.value = list.map((item) => ({
  528. label: item.itemValue,
  529. value: item.itemCode,
  530. }));
  531. } catch (e) {
  532. console.error('获取检查单模版类别字典失败:', e);
  533. checklistCategoryOptions.value = [];
  534. }
  535. };
  536. // 检查单模版名称:来自接口,可按类别筛选
  537. const checklistTemplateOptions = ref<Array<{ label: string; value: string }>>([]);
  538. const allChecklistTemplates = ref<ChecklistTemplate[]>([]);
  539. /** 根据类别名称(form 静态选项的 value)筛选模版下拉 */
  540. const updateChecklistTemplateOptionsByCategory = (categoryName?: string) => {
  541. const list = allChecklistTemplates.value || [];
  542. const filtered = categoryName
  543. ? list.filter((item) => (item.categoryName as string) === categoryName)
  544. : list;
  545. checklistTemplateOptions.value = filtered
  546. .filter((item) => !!item.templateName)
  547. .map((item) => ({
  548. label: item.templateName as string,
  549. value: item.templateName as string,
  550. }));
  551. };
  552. /** 加载检查单模版名称列表(仅模版名称下拉用,类别用 form 静态数据) */
  553. const loadChecklistTemplateOptions = async () => {
  554. try {
  555. const res = await queryCheckListTemplateNameList();
  556. const list = ((res as { data?: ChecklistTemplate[] })?.data ?? (res as ChecklistTemplate[] | undefined)) || [];
  557. allChecklistTemplates.value = list;
  558. const currentCategoryName = ruleFormData.categoryName as string | undefined;
  559. updateChecklistTemplateOptionsByCategory(currentCategoryName);
  560. } catch (e) {
  561. console.error('获取检查单模版名称列表失败:', e);
  562. checklistTemplateOptions.value = [];
  563. }
  564. };
  565. const viewFormConfig = ref(
  566. AREA_CHECK_PLAN_FORM_CONFIG.map((item) => ({
  567. ...item,
  568. componentProps: {
  569. ...item.componentProps,
  570. disabled: true,
  571. },
  572. })),
  573. );
  574. const computedFormConfig = computed(() => {
  575. const base = isViewMode.value ? viewFormConfig.value : cloneDeep(AREA_CHECK_PLAN_FORM_CONFIG);
  576. return base.map((item) => {
  577. if (item.prop === 'categoryCode') {
  578. const opts = checklistCategoryOptions.value;
  579. return {
  580. ...item,
  581. selectOptions: opts,
  582. componentProps: {
  583. ...(item.componentProps || {}),
  584. onChange: (val: string) => {
  585. const opt = opts.find((o) => o.value === val);
  586. ruleFormData.categoryName = opt?.label ?? '';
  587. (ruleFormData as Record<string, unknown>).categoryCode = val;
  588. ruleFormData.checklistTemplateName = '';
  589. updateChecklistTemplateOptionsByCategory(opt?.label);
  590. },
  591. },
  592. };
  593. }
  594. if (item.prop === 'checklistTemplateName') {
  595. return {
  596. ...item,
  597. selectOptions: checklistTemplateOptions.value,
  598. componentProps: {
  599. ...(item.componentProps || {}),
  600. },
  601. };
  602. }
  603. return item;
  604. });
  605. });
  606. const basicFormRef = ref<InstanceType<typeof BasicForm>>();
  607. // 查看页:详情数据
  608. const viewDetailData = ref<Record<string, unknown>>({});
  609. const viewDetail = computed(() => {
  610. const d = viewDetailData.value;
  611. const status = d?.status as number | undefined;
  612. return {
  613. ...d,
  614. statusName: status != null ? AREA_CHECK_PLAN_STATUS_LABEL[String(status)] ?? '-' : '-',
  615. planName: d?.planName ?? ruleFormData.planName ?? '-',
  616. venueCategoryName: d?.venueCategoryName ?? ruleFormData.venueCategoryName ?? '-',
  617. checkVenue: d?.checkVenue ?? ruleFormData.checkVenue ?? '-',
  618. primary_responsible_dept_name: d?.primary_responsible_dept_name ?? d?.mainDeptName ?? (ruleFormData as Record<string, unknown>).primary_responsible_dept_name ?? ruleFormData.mainDeptName ?? '-',
  619. mainDeptName: d?.mainDeptName ?? ruleFormData.mainDeptName ?? '-',
  620. selfCheckFrequency: d?.selfCheckFrequency ?? ruleFormData.selfCheckFrequency ?? '-',
  621. mainDeptExecutorGroupName: d?.mainDeptExecutorGroupName ?? '-',
  622. mainDeptResponsiblePerson: d?.mainDeptResponsiblePerson ?? '-',
  623. safetyEmergencyDeptName: d?.safetyEmergencyDeptName ?? ruleFormData.safetyEmergencyDeptName ?? '-',
  624. safetyEmergencyCheckFrequency: d?.safetyEmergencyCheckFrequency ?? ruleFormData.safetyEmergencyCheckFrequency ?? '-',
  625. safetyEmergencyExecutorGroupName: d?.safetyEmergencyExecutorGroupName ?? '-',
  626. safetyEmergencyResponsiblePerson: d?.safetyEmergencyResponsiblePerson ?? '-',
  627. hospitalLeaderDeptName: d?.hospitalLeaderDeptName ?? ruleFormData.hospitalLeaderDeptName ?? '-',
  628. hospitalLeaderCheckFrequency: d?.hospitalLeaderCheckFrequency ?? ruleFormData.hospitalLeaderCheckFrequency ?? '-',
  629. hospitalLeaderExecutorGroupName: d?.hospitalLeaderExecutorGroupName ?? '-',
  630. hospitalLeaderResponsiblePerson: d?.hospitalLeaderResponsiblePerson ?? '-',
  631. categoryName: d?.categoryName ?? ruleFormData.categoryName ?? '-',
  632. checklistTemplateName: d?.checklistTemplateName ?? ruleFormData.checklistTemplateName ?? '-',
  633. needOverallDesc: d?.needOverallDesc ?? ruleFormData.needOverallDesc,
  634. needInspectedSign: d?.needInspectedSign ?? ruleFormData.needInspectedSign,
  635. planStartTime: d?.planStartTime ?? ruleFormData.planStartTime ?? '-',
  636. planEndTime: d?.planEndTime ?? ruleFormData.planEndTime ?? '-',
  637. createdBy: d?.createdBy ?? '-',
  638. createdAt: d?.createdAt ?? '-',
  639. businessWork: d?.businessWork ?? '-',
  640. };
  641. });
  642. const inspectionContentList = computed(() => {
  643. const content = (viewDetailData.value?.checkKeyContent ?? ruleFormData.checkKeyContent) as string;
  644. if (!content || typeof content !== 'string') return [];
  645. return content.split(/[;;]/).map((s) => s.trim()).filter(Boolean);
  646. });
  647. const RECORD_TABLE_COLUMNS: TableColumnProps[] = [
  648. { label: '编号', type: 'index', align: 'center', width: '60px' },
  649. { label: '检查时间', prop: 'checkTime', minWidth: '160px' },
  650. { label: '检查人员', prop: 'checkPerson', minWidth: '100px' },
  651. { label: '检查场所类别', prop: 'checkPlaceCategory', minWidth: '120px' },
  652. { label: '检查场所', prop: 'checkPlace', minWidth: '120px' },
  653. { label: '检查项总数', prop: 'checkItemTotal', align: 'center', width: '100px' },
  654. { label: '合格项数', prop: 'qualifiedItemNum', align: 'center', width: '90px' },
  655. { label: '不合格项数', prop: 'unqualifiedItemNum', slot: 'unqualifiedItemNum', align: 'center', width: '100px' },
  656. { label: '整体检查情况描述', prop: 'overallCheckDesc', minWidth: '180px', showOverflowTooltip: true },
  657. { label: '被检查人签字', slot: 'sign', align: 'center', width: '140px' },
  658. { label: '操作', slot: 'action', align: 'center', width: '160px', fixed: 'right' },
  659. ];
  660. const RECORD_TABLE_OPTIONS = {
  661. emptyText: '暂无检查记录',
  662. loading: false,
  663. maxHeight: '400px',
  664. stripe: true,
  665. };
  666. const { tableConfig: recordTableConfig, pagination: recordPagination } = useTableConfig(
  667. RECORD_TABLE_COLUMNS,
  668. RECORD_TABLE_OPTIONS,
  669. true,
  670. );
  671. const recordSearchKeyword = ref('');
  672. const recordDateRange = ref<[string, string] | null>(null);
  673. const inspectionRecordList = ref<Array<Record<string, unknown>>>([]);
  674. const paginatedRecordList = computed(() => inspectionRecordList.value);
  675. // 检查不合格数据弹窗
  676. const showUnqualifiedDialog = ref(false);
  677. const currentRecordIdForUnqualified = ref<number | null>(null);
  678. const currentRowForUnqualified = ref<Record<string, unknown> | null>(null);
  679. const unqualifiedList = ref<UnqualifiedItemNumRecord[]>([]);
  680. const UNQUALIFIED_TABLE_COLUMNS: TableColumnProps[] = [
  681. { label: '编号', type: 'index', align: 'center', width: '60px' },
  682. { label: '检查场所', prop: 'checkPlace', minWidth: '200px' },
  683. { label: '发现问题', prop: 'checkProblem', minWidth: '220px' },
  684. { label: '检查时间', prop: 'checkTime', minWidth: '180px' },
  685. { label: '操作', slot: 'action', align: 'center', width: '100px' },
  686. ];
  687. const UNQUALIFIED_TABLE_OPTIONS = {
  688. emptyText: '暂无不合格数据',
  689. loading: false,
  690. maxHeight: '400px',
  691. stripe: true,
  692. };
  693. const { tableConfig: unqualifiedTableConfig, pagination: unqualifiedPagination } = useTableConfig(
  694. UNQUALIFIED_TABLE_COLUMNS,
  695. UNQUALIFIED_TABLE_OPTIONS,
  696. true,
  697. );
  698. // 入账确认弹窗数据(复用隐患台账新增表单字段与样式)
  699. const showSandConfirmDialog = ref(false);
  700. const sandConfirmLoading = ref(false);
  701. const sandHiddenDangerFormRef = ref<InstanceType<typeof BasicForm>>();
  702. const {
  703. ruleFormData: sandHiddenDangerFormData,
  704. formRules: sandHiddenDangerFormRules,
  705. ruleFormConfig: sandHiddenDangerFormConfig,
  706. } = useFormConfigHook(
  707. HIDDEN_DANGER_FORM_CONFIG,
  708. HIDDEN_DANGER_FORM_DATA as Record<string, unknown>,
  709. HIDDEN_DANGER_FORM_RULES,
  710. );
  711. const handleRecordSizeChange = (value: number) => {
  712. recordPagination.pageSize = value;
  713. recordPagination.pageNumber = 1;
  714. loadRecordList();
  715. };
  716. const handleRecordPageChange = (value: number) => {
  717. recordPagination.pageNumber = value;
  718. loadRecordList();
  719. };
  720. const loadUnqualifiedList = async () => {
  721. if (!currentRecordIdForUnqualified.value) return;
  722. unqualifiedTableConfig.loading = true;
  723. try {
  724. const res = await queryUnqualifiedItemNumPage({
  725. pageNumber: unqualifiedPagination.pageNumber,
  726. pageSize: unqualifiedPagination.pageSize,
  727. queryParam: {
  728. id: currentRecordIdForUnqualified.value,
  729. checkPlace: String(currentRowForUnqualified.value?.checkPlace ?? ''),
  730. checkProblem: String(currentRowForUnqualified.value?.checkProblem ?? ''),
  731. checkTime: String(currentRowForUnqualified.value?.checkTime ?? ''),
  732. },
  733. });
  734. const raw = (res as { data?: { records?: UnqualifiedItemNumRecord[]; totalRow?: number } })?.data ?? res;
  735. unqualifiedList.value = raw?.records ?? [];
  736. unqualifiedPagination.total = raw?.totalRow ?? 0;
  737. } catch (e) {
  738. console.error('查询不合格数据失败:', e);
  739. unqualifiedList.value = [];
  740. unqualifiedPagination.total = 0;
  741. } finally {
  742. unqualifiedTableConfig.loading = false;
  743. }
  744. };
  745. const handleUnqualifiedSizeChange = (value: number) => {
  746. unqualifiedPagination.pageSize = value;
  747. unqualifiedPagination.pageNumber = 1;
  748. loadUnqualifiedList();
  749. };
  750. const handleUnqualifiedPageChange = (value: number) => {
  751. unqualifiedPagination.pageNumber = value;
  752. loadUnqualifiedList();
  753. };
  754. const openUnqualifiedDialog = (row: { id?: number } & Record<string, unknown>) => {
  755. if (!row.id) return;
  756. currentRecordIdForUnqualified.value = Number(row.id);
  757. currentRowForUnqualified.value = row;
  758. unqualifiedPagination.pageNumber = 1;
  759. showUnqualifiedDialog.value = true;
  760. loadUnqualifiedList();
  761. };
  762. const loadRecordList = async () => {
  763. if (!currentId.value) return;
  764. recordTableConfig.loading = true;
  765. try {
  766. const [start, end] = recordDateRange.value && recordDateRange.value.length === 2
  767. ? recordDateRange.value
  768. : ['', ''];
  769. const res = await queryAreaCheckPlanDetailPage(currentId.value, {
  770. pageNumber: recordPagination.pageNumber,
  771. pageSize: recordPagination.pageSize,
  772. queryParam: {
  773. searchKey: recordSearchKeyword.value || undefined,
  774. startDate: start || undefined,
  775. endDate: end || undefined,
  776. },
  777. });
  778. const raw = (res as { data?: { records?: Array<Record<string, unknown>>; totalRow?: number } })?.data ?? res;
  779. const records = raw?.records ?? [];
  780. inspectionRecordList.value = records.map((r: Record<string, unknown>) => ({
  781. ...r,
  782. checkPerson: r.checkPerson ?? r.checkPersonName,
  783. checkedCompany: r.checkedCompany ?? r.checkedCompanyName,
  784. }));
  785. recordPagination.total = raw?.totalRow ?? 0;
  786. } catch (e) {
  787. console.error('查询检查记录失败:', e);
  788. inspectionRecordList.value = [];
  789. recordPagination.total = 0;
  790. } finally {
  791. recordTableConfig.loading = false;
  792. }
  793. };
  794. const onRecordSearch = () => {
  795. recordPagination.pageNumber = 1;
  796. loadRecordList();
  797. };
  798. const onRecordExport = () => {
  799. ElMessage.success('导出功能开发中');
  800. };
  801. const handleSandToHiddenDanger = (row: { id?: number } & Record<string, unknown>) => {
  802. if (!row.id) return;
  803. currentRecordIdForUnqualified.value = Number(row.id);
  804. // 每次打开入账弹窗都使用一份全新的隐患台账初始数据,不带入检查记录旧数据
  805. Object.assign(sandHiddenDangerFormData, HIDDEN_DANGER_FORM_DATA);
  806. showSandConfirmDialog.value = true;
  807. };
  808. const validateSandHiddenDangerForm = async () => {
  809. if (!sandHiddenDangerFormRef.value) return false;
  810. return await sandHiddenDangerFormRef.value.validateForm();
  811. };
  812. const confirmSandToHiddenDanger = async () => {
  813. if (!currentRecordIdForUnqualified.value) return;
  814. const valid = await validateSandHiddenDangerForm();
  815. if (!valid) return;
  816. sandConfirmLoading.value = true;
  817. try {
  818. const d = sandHiddenDangerFormData;
  819. const payload: SandAreaCheckRecordToHiddenDangerReq = {
  820. areaCheckRecordId: currentRecordIdForUnqualified.value,
  821. sourceType: 4,
  822. sourceRefId: currentRecordIdForUnqualified.value,
  823. dangerProblem: d.dangerProblem || '',
  824. typeId: d.typeId,
  825. reasonId: d.reasonId,
  826. taskSource: d.taskSource || '',
  827. rectificationRequirement: d.rectificationRequirement || '',
  828. rectificationDeadline: d.rectificationDeadline || '',
  829. rectificationDepartmentIds: d.rectificationDepartmentIds || '',
  830. rectificationResponsiblePerson: d.rectificationResponsiblePerson || '',
  831. reviewDepartmentId: d.reviewDepartmentId,
  832. reviewPersonId: d.reviewPersonId,
  833. reviewPersonName: d.reviewPersonName || '',
  834. isDrawLessonsPush: d.isDrawLessonsPush ?? 0,
  835. drawLessonsContent: d.drawLessonsContent || '',
  836. drawLessonsDepartmentIds: d.drawLessonsDepartmentIds || '',
  837. drawLessonsDeadline: d.drawLessonsDeadline || '',
  838. attachments: d.attachments || '',
  839. };
  840. await sandAreaCheckRecordToProductionHiddenDanger(payload);
  841. ElMessage.success('下入账成功');
  842. // 关闭入账表单弹窗和“不合格数据”弹窗
  843. showSandConfirmDialog.value = false;
  844. showUnqualifiedDialog.value = false;
  845. // 重新加载检查记录列表,刷新 isSand 状态和数量
  846. await loadRecordList();
  847. } catch (e) {
  848. console.error('下入账失败:', e);
  849. ElMessage.error('下入账失败,请稍后重试');
  850. } finally {
  851. sandConfirmLoading.value = false;
  852. }
  853. };
  854. const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
  855. const previewOnline = (url: string | undefined, type: keyof typeof FILE_TYPE_ICON) => {
  856. if (url) previewOnlineRef.value?.open(url, type);
  857. };
  858. const parseSignFiles = (signFile: string | undefined): Array<{ fileUrl: string; fileName: string; fileType: string }> => {
  859. if (!signFile || !String(signFile).trim()) return [];
  860. const parts = String(signFile)
  861. .split(',')
  862. .map((s) => s.trim())
  863. .filter(Boolean);
  864. return parts.map((part) => {
  865. const urlParts = part.split('/');
  866. const fileName = urlParts[urlParts.length - 1] || part || '未知文件';
  867. const extension = fileName.split('.').pop()?.toLowerCase() || '';
  868. let fileType = 'pdf';
  869. if (extension === 'doc' || extension === 'docx') fileType = 'word';
  870. else if (extension === 'xls' || extension === 'xlsx') fileType = 'excel';
  871. else if (extension === 'ppt' || extension === 'pptx') fileType = 'ppt';
  872. return { fileUrl: part, fileName, fileType };
  873. });
  874. };
  875. const onDeleteRecord = async (row: { id?: number }) => {
  876. if (!row.id) return;
  877. try {
  878. await deleteAreaCheckPlanDetail(row.id);
  879. ElMessage.success('删除成功');
  880. loadRecordList();
  881. } catch (e) {
  882. console.error('删除检查记录失败:', e);
  883. }
  884. };
  885. const onViewRecord = (row: Record<string, unknown>) => {
  886. router.push({
  887. name: 'areaCheckPlanManagementItem',
  888. query: {
  889. operate: 'area-check-plan-record-view',
  890. recordId: row.id,
  891. planId: currentId.value,
  892. inspectedUnit: String(row.checkedCompanyName ?? row.checkedCompany ?? viewDetail.value.primary_responsible_dept_name ?? viewDetail.value.mainDeptName ?? viewDetail.value.checkVenue ?? ''),
  893. inspector: String(row.checkPersonName ?? row.checkPerson ?? row.inspector ?? ''),
  894. checkTime: String(row.checkTime ?? row.inspectionTime ?? ''),
  895. checkPlace: String(row.checkAddress ?? row.checkPlace ?? row.venue ?? ''),
  896. overallDesc: String(row.overallCheckDesc ?? row.overallDesc ?? ''),
  897. signFile: String(row.checkedPersonSign ?? row.signFile ?? ''),
  898. },
  899. });
  900. };
  901. const handleValidate = async () => {
  902. if (!basicFormRef.value) return;
  903. return await basicFormRef.value.validateForm();
  904. };
  905. const getDetail = async () => {
  906. if (!currentId.value) return;
  907. try {
  908. const res = await queryAreaCheckPlanManageDetail(currentId.value);
  909. const raw = (res as { data?: unknown })?.data ?? res;
  910. const detail = mapAreaCheckPlanApiRecordToUi(raw);
  911. viewDetailData.value = { ...detail };
  912. ruleFormData.planName = detail.planName ?? '';
  913. ruleFormData.venueCategoryName = detail.venueCategoryName ?? '';
  914. ruleFormData.checkVenue = detail.checkVenue ?? '';
  915. const mainDeptName = detail.primary_responsible_dept_name ?? detail.mainDeptName ?? '';
  916. (ruleFormData as Record<string, unknown>).primary_responsible_dept_name = mainDeptName;
  917. (ruleFormData as Record<string, unknown>).primary_responsible_dept_code = detail.primary_responsible_dept_code ?? detail.mainDeptCode ?? '';
  918. const primaryCode = detail.primary_responsible_dept_code ?? detail.mainDeptCode;
  919. const idFromCode = primaryCode != null && /^\d+$/.test(String(primaryCode)) ? Number(primaryCode) : undefined;
  920. (ruleFormData as Record<string, unknown>).primary_responsible_dept_id = idFromCode ?? findDeptIdByName(deptTree.value, mainDeptName) ?? null;
  921. ruleFormData.selfCheckFrequency = detail.selfCheckFrequency ?? '';
  922. ruleFormData.safetyEmergencyDeptName = detail.safetyEmergencyDeptName ?? '';
  923. ruleFormData.safetyEmergencyDeptId = findDeptIdByName(deptTree.value, ruleFormData.safetyEmergencyDeptName as string) ?? null;
  924. ruleFormData.safetyEmergencyCheckFrequency = detail.safetyEmergencyCheckFrequency ?? '';
  925. ruleFormData.hospitalLeaderDeptName = detail.hospitalLeaderDeptName ?? '';
  926. ruleFormData.hospitalLeaderDeptId = findDeptIdByName(deptTree.value, ruleFormData.hospitalLeaderDeptName as string) ?? null;
  927. ruleFormData.hospitalLeaderCheckFrequency = detail.hospitalLeaderCheckFrequency ?? '';
  928. (ruleFormData as Record<string, unknown>).categoryCode = detail.categoryCode ?? '';
  929. ruleFormData.categoryName = detail.categoryName ?? '';
  930. ruleFormData.checklistTemplateName = detail.checklistTemplateName ?? '';
  931. ruleFormData.checkKeyContent = detail.checkKeyContent ?? '';
  932. updateChecklistTemplateOptionsByCategory(ruleFormData.categoryName as string | undefined);
  933. cloneRuleFormData();
  934. if (isViewMode.value) {
  935. loadRecordList();
  936. }
  937. } catch (e) {
  938. console.error('获取详情失败:', e);
  939. }
  940. };
  941. const handleSubmit = async () => {
  942. const valid = await handleValidate();
  943. if (!valid) return;
  944. try {
  945. if (isCreateMode.value) {
  946. await saveAreaCheckPlanManage(ruleFormData as AreaCheckPlanRecord);
  947. ElMessage.success('创建成功');
  948. } else if (isEditMode.value) {
  949. await updateAreaCheckPlanManage({ ...ruleFormData, id: currentId.value } as AreaCheckPlanRecord & { id: number });
  950. ElMessage.success('保存成功');
  951. }
  952. router.back();
  953. } catch (e) {
  954. console.error('提交失败:', e);
  955. }
  956. };
  957. onMounted(async () => {
  958. cloneRuleFormData();
  959. beforeRouteLeave();
  960. await getDeptTreeData();
  961. await loadChecklistCategoryOptions();
  962. await loadChecklistTemplateOptions();
  963. if (isEditMode.value || isViewMode.value) {
  964. getDetail();
  965. }
  966. });
  967. </script>
  968. <style scoped lang="scss">
  969. @use '@/styles/page-details-layout.scss' as *;
  970. @use '@/styles/basic-table-file.scss' as *;
  971. .area-check-plan-view {
  972. padding: 16px 24px;
  973. display: flex;
  974. flex-direction: column;
  975. gap: 24px;
  976. }
  977. .view-section {
  978. .view-section__title {
  979. font-weight: 600;
  980. margin-bottom: 12px;
  981. display: flex;
  982. align-items: center;
  983. gap: 6px;
  984. &--small {
  985. font-size: 13px;
  986. margin-bottom: 8px;
  987. }
  988. }
  989. .view-section__icon {
  990. width: 4px;
  991. height: 14px;
  992. background: var(--el-color-primary);
  993. border-radius: 2px;
  994. }
  995. }
  996. .view-summary {
  997. .view-summary__title {
  998. font-weight: 600;
  999. font-size: 15px;
  1000. margin-bottom: 4px;
  1001. }
  1002. .view-summary__venue {
  1003. margin-bottom: 8px;
  1004. }
  1005. .view-summary__meta {
  1006. font-size: 13px;
  1007. color: var(--el-text-color-secondary);
  1008. span + span {
  1009. margin-left: 16px;
  1010. }
  1011. }
  1012. }
  1013. /* 基本信息:与 OneByOneAuditDetail 保持一致 */
  1014. .audit-content {
  1015. .section-title {
  1016. display: flex;
  1017. align-items: center;
  1018. gap: 8px;
  1019. margin: 20px 0 12px 0;
  1020. font-size: 16px;
  1021. font-weight: 600;
  1022. color: #333;
  1023. .section-title__icon {
  1024. font-size: 18px;
  1025. color: #333;
  1026. }
  1027. }
  1028. .section-title:first-child {
  1029. margin-top: 0;
  1030. }
  1031. .detail-ct {
  1032. font-size: 14px;
  1033. margin-bottom: 20px;
  1034. &--table {
  1035. border: 1px solid #dcdfe6;
  1036. .row {
  1037. display: flex;
  1038. border-bottom: 1px solid #dcdfe6;
  1039. &:last-child {
  1040. border-bottom: none;
  1041. }
  1042. }
  1043. .col {
  1044. display: flex;
  1045. flex: 1;
  1046. min-height: 40px;
  1047. align-items: stretch;
  1048. .label {
  1049. display: flex;
  1050. align-items: center;
  1051. justify-content: flex-end;
  1052. flex-shrink: 0;
  1053. width: 200px;
  1054. padding: 0 12px;
  1055. background-color: #f5f5f5;
  1056. border-right: 1px solid #dcdfe6;
  1057. color: #333;
  1058. }
  1059. .value {
  1060. flex: 1;
  1061. display: flex;
  1062. align-items: center;
  1063. padding: 10px 20px;
  1064. background-color: #fff;
  1065. border-right: 1px solid #dcdfe6;
  1066. color: #333;
  1067. &--list {
  1068. align-items: flex-start;
  1069. .inspection-content-list {
  1070. margin: 0;
  1071. padding-left: 20px;
  1072. line-height: 1.8;
  1073. color: #333;
  1074. }
  1075. }
  1076. }
  1077. }
  1078. .row .col:last-child .value {
  1079. border-right: none;
  1080. }
  1081. .row .col:nth-child(2) .label {
  1082. border-left: 1px solid #dcdfe6;
  1083. }
  1084. }
  1085. }
  1086. }
  1087. .view-record-toolbar {
  1088. margin-bottom: 12px;
  1089. display: flex;
  1090. align-items: center;
  1091. flex-wrap: wrap;
  1092. gap: 8px;
  1093. }
  1094. .view-record-table {
  1095. margin-bottom: 16px;
  1096. }
  1097. </style>