Detail.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. <template>
  2. <div class="prepare-detail-container">
  3. <!-- 固定头部区域 -->
  4. <div class="header fixed-header">
  5. <div class="btns">
  6. <el-button v-for="(btn, index) in getButtonListByStatus" :key="index" :type="btn.type" @click="btn.callback">
  7. <el-icon v-if="btn.icon"><component :is="btn.icon" :key="index"/></el-icon>
  8. {{btn.title}}
  9. </el-button>
  10. </div>
  11. </div>
  12. <!-- 可滚动内容区域 -->
  13. <div class="scrollable-content">
  14. <div id="prepareDetail" v-loading="loading">
  15. <el-collapse :model-value="['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14']" class="custom-collapse-form" v-loading="functionalStore.loading">
  16. <!-- <el-collapse-item title="基础信息" name="1"><BasicInfo ref="basicInfoRef" :instanceId="instanceId" :isEdit="false"/></el-collapse-item> -->
  17. <!-- <el-collapse-item title="委托单位" name="2"><UnitInfo ref="unitInfoRef" :instanceId="instanceId" :isEdit="false"/></el-collapse-item> -->
  18. <!-- <el-collapse-item title="使用单位" name="3" v-if="['2636eba25f3aae0f04fc85706da9f748'].includes(baseInfo.acceptanceTemplateId)">
  19. <UseUnitInfo ref="useUnitInfoRef" :instanceId="instanceId" :isEdit="false"/>
  20. </el-collapse-item> -->
  21. <!-- <el-collapse-item title="样品信息" name="4"><SampleList :instanceId="instanceId" :isEdit="false"/></el-collapse-item> -->
  22. <!-- <el-collapse-item title="样品信息" name="5"><SampleProcessInfo ref="sampleProcessInfoRef" :instanceId="instanceId" :isEdit="false"/></el-collapse-item> -->
  23. <el-collapse-item title="检验信息" name="6"><CheckItemInfo ref="checkItemInfoRef" :instanceId="instanceId" :isEdit="false" :rollbackFlag="'authorized'"/></el-collapse-item>
  24. <!-- <el-collapse-item title="检验项目" name="7"><CheckItemList :instanceId="instanceId" :showChildren="true" :showTool="false" page="report"/></el-collapse-item> -->
  25. <el-collapse-item title="报告结论" name="13"><ReportConclusion ref="reportConclusionRef" :instanceId="instanceId" :isDetail="isDetail"/></el-collapse-item>
  26. <el-collapse-item title="报告附件" name="14" v-if="!isDetail">
  27. <el-row :gutter="36">
  28. <el-col :span="12" style="margin-bottom: 18px;">
  29. <el-button type="primary" @click="handleEditAttachment">编辑报告附件</el-button>
  30. </el-col>
  31. </el-row>
  32. </el-collapse-item>
  33. <!-- <el-collapse-item title="检验收费" name="8"><CheckFeeCopy ref="checkFeeRef" :instanceId="instanceId" :isEdit="false"/></el-collapse-item>
  34. <el-collapse-item title="报告信息" name="9"><ReportInfo :instanceId="instanceId" :isEdit="false"/></el-collapse-item>
  35. <el-collapse-item title="特殊要求" name="11"><SpecialRequirements :instanceId="instanceId" :isEdit="false"/></el-collapse-item>
  36. <el-collapse-item title="科技成果" name="12"><TechnicalAchievements :instanceId="instanceId" :isEdit="false"/></el-collapse-item> -->
  37. </el-collapse>
  38. </div>
  39. </div>
  40. </div>
  41. <EditSpreadRecord
  42. v-if="showPreviewReport"
  43. v-model:visible="showPreviewReport"
  44. :type="reportType"
  45. :reportUrl="currentInstance.reportConclusion.reportUrl"
  46. :templateParams="templateParams"
  47. @refresh="handleUpdateDetailData"
  48. />
  49. <!-- 型式试验 -->
  50. <EditSpreadEditOtherFileRecord
  51. v-if="showPreviewEditOtherFileReport"
  52. v-model:visible="showPreviewEditOtherFileReport"
  53. :type="showPreviewEditOtherFileReportType"
  54. :reportUrl="currentInstance.reportConclusion.typeInspectionReportUrl"
  55. :templateParams="editOtherFileTemplateParams"
  56. @refresh="handleUpdateDetailData"
  57. />
  58. <AuditUserDialog
  59. v-if="isShowApprovalByDialog"
  60. v-model="isShowApprovalByDialog"
  61. :apiFn="getAuditList"
  62. :apiParams="{roleCode: 'sysbgspr'}"
  63. title="请选择报告审批人"
  64. :deptIdDefaultFlag="true"
  65. selectedAlertText="已选择报告审批人"
  66. :columns="auditDialogColumns"
  67. :searchFormProps="labelWidthDefault"
  68. @confirm="handleApprovalBySelectConfirm"
  69. />
  70. <!-- 文件预览组件 -->
  71. <FilePreview
  72. v-if="previewVisible"
  73. v-model="previewVisible"
  74. :id="currentPreviewId"
  75. :filename="currentFilename"
  76. :title="'文件预览'"
  77. :isEditOtherFileFlag="typeFlag"
  78. @close="handlePreviewClose"
  79. />
  80. </template>
  81. <script lang="tsx" setup>
  82. const EditSpreadRecord = defineAsyncComponent(() => import('./EditSpreadRecord.vue'))
  83. const EditSpreadEditOtherFileRecord = defineAsyncComponent(() => import('./components/EditSpreadEditOtherFileRecord.vue'))
  84. const BasicInfo = defineAsyncComponent(() => import('@/views/Functional/components/BasicInfo.vue'))
  85. const UnitInfo = defineAsyncComponent(() => import('@/views/Functional/components/UnitInfo.vue'))
  86. const UseUnitInfo = defineAsyncComponent(() => import('@/views/Functional/components/UseUnitInfo.vue'))
  87. // const SampleList = defineAsyncComponent(() => import('@/views/Functional/components/SampleList.vue'))
  88. const SampleList = defineAsyncComponent(() => import('@/views/Task/components/SampleList.vue'))
  89. const SampleProcessInfo = defineAsyncComponent(() => import('@/views/Functional/components/SampleProcessInfo.vue'))
  90. const CheckItemInfo = defineAsyncComponent(() => import('@/views/Functional/components/CheckItemInfoCopy.vue'))
  91. // const CheckFee = defineAsyncComponent(() => import('@/views/Functional/components/CheckFee.vue'))
  92. const CheckFeeCopy = defineAsyncComponent(() => import('@/views/Functional/components/CheckFeeCopy.vue'))
  93. const ReportInfo = defineAsyncComponent(() => import('@/views/Functional/components/ReportInfo.vue'))
  94. const ReportDistributionMethod = defineAsyncComponent(() => import('@/views/Functional/components/ReportDistributionMethod.vue'))
  95. const SpecialRequirements = defineAsyncComponent(() => import('@/views/Functional/components/SpecialRequirements.vue'))
  96. const TechnicalAchievements = defineAsyncComponent(() => import('@/views/Functional/components/TechnicalAchievements.vue'))
  97. const ReportConclusion = defineAsyncComponent(() => import('./components/ReportConclusion.vue'))
  98. const CheckItemList = defineAsyncComponent(() => import('@/views/TaskEnter/components/CreateOrEditCheckRecord.vue'))
  99. const AuditUserDialog = defineAsyncComponent(() => import('@/views/Functional/components/AuditUserDialog.vue'))
  100. import FilePreview from './components/FilePreview.vue'
  101. import { DocumentCopy, Check, Close, CircleCheck, ArrowLeft, Document } from '@element-plus/icons-vue'
  102. import { useFunctionalStore } from '@/store/modules/laboratory/functional'
  103. import { useTagsViewStore } from '@/store/modules/tagsView'
  104. import { useRoute, useRouter } from "vue-router";
  105. import { getAuditList } from '@/api/laboratory/functional'
  106. import { updateReportFileUrl, previewPrepareReport, withdrawReportPreparation } from '@/api/laboratory/functional/report'
  107. import _ from 'lodash'
  108. import { useEmitt } from '@/hooks/web/useEmitt'
  109. const { emitter } = useEmitt()
  110. const currentFilename = ref<string>('')
  111. const currentFilesize = ref<string>('200')
  112. const currentPreviewId = ref<string>('')
  113. const previewVisible = ref<boolean>(false)
  114. const typeFlag = ref<boolean>(false)
  115. const tagsViewStore = useTagsViewStore()
  116. const functionalStore = useFunctionalStore()
  117. const route = useRoute()
  118. const router = useRouter()
  119. const reportConclusionRef = ref()
  120. const labelWidthDefault = ref({labelWidth: 'auto'})
  121. const auditDialogColumns = computed(() => [
  122. {
  123. type: 'selection',
  124. fieldProps: {
  125. reserveSelection: true
  126. }
  127. },
  128. {
  129. label: '姓名',
  130. prop: 'nickName',
  131. search: {
  132. type: 'input',
  133. span: 12,
  134. placeholder: '请输入姓名'
  135. },
  136. render: (row) => {
  137. return row?.nickname || '-'
  138. }
  139. },
  140. {
  141. label: '部门',
  142. prop: 'deptId',
  143. search: {
  144. type: 'DeptSelect',
  145. span: 12,
  146. placeholder: '请选择部门'
  147. },
  148. render: (row) => {
  149. return row?.deptName || '-'
  150. }
  151. }
  152. ])
  153. // 生成唯一实例ID(使用路由路径+参数)
  154. const instanceId = computed(() =>
  155. `reportPreparation-${route.query.id}`
  156. )
  157. // 获取当前实例状态(自动创建隔离状态)
  158. let currentInstance = reactive(functionalStore.getInstance(instanceId.value))
  159. console.log(currentInstance, 'currentInstance数据')
  160. const { baseInfo } = toRefs(currentInstance)
  161. const loading = ref(false)
  162. // 在onMounted中合并初始化请求
  163. onMounted(async () => {
  164. if(route.query?.id) {
  165. console.log('进入详情页')
  166. await functionalStore.getReportPreparationInfo(instanceId.value, route.query.id)
  167. }
  168. functionalStore.fecthDeptList(),
  169. functionalStore.fetchStandardClassList(),
  170. functionalStore.fetchUnitList()
  171. })
  172. // 组件卸载时清理状态(可选)
  173. onUnmounted(() => {
  174. functionalStore.clearInstance(instanceId.value)
  175. })
  176. const isShowApprovalByDialog = ref(false) // 审批人弹窗
  177. const buttonsList = shallowRef([
  178. {
  179. type: 'primary',
  180. title: '预览报告',
  181. icon: CircleCheck,
  182. callback: () => handlePreviewContracts(),
  183. show: () => !currentInstance.reportConclusion.reportUrl ? false : true,
  184. reportStatus: ['0', '1', '2', '3']
  185. },
  186. {
  187. type: 'warning',
  188. title: '预览型式试验报告',
  189. icon: CircleCheck,
  190. callback: () => handlePreviewTypeInspectionRepor(),
  191. show: () => !currentInstance.reportConclusion.typeInspectionReportUrl ? false : true,
  192. reportStatus: ['0', '1', '2', '3']
  193. },
  194. {
  195. type: 'warning',
  196. title: '编制型式试验报告',
  197. icon: Document,
  198. callback: () => handleEditOtherFileFn(),
  199. show: () => currentInstance.allTaskInfo?.businessAcceptanceRespVO?.isTypeTest =='1' ? true : false,
  200. reportStatus: ['0', '1', '3']
  201. },
  202. {
  203. type: 'primary',
  204. title: '编制报告',
  205. icon: Document,
  206. callback: () => handlePrepareReport(),
  207. reportStatus: ['0', '1', '3']
  208. },
  209. {
  210. type: 'success',
  211. title: '档案管理',
  212. icon: Document,
  213. callback: () => handleArchivesManagement(),
  214. reportStatus: ['0', '1', '2', '3']
  215. },
  216. {
  217. type: 'primary',
  218. title: '提交',
  219. icon: Check,
  220. callback: () => handleSubmit(),
  221. show: () => !currentInstance.reportConclusion.reportUrl ? false : true,
  222. reportStatus: ['0', '1', '3']
  223. },
  224. {
  225. type: 'primary',
  226. title: '保存数据',
  227. icon: DocumentCopy,
  228. callback: () => handleCache(),
  229. reportStatus: ['0', '1', '3']
  230. },
  231. {
  232. type: 'primary',
  233. title: '回退',
  234. icon: ArrowLeft,
  235. callback: () => handleRejectSubmit(),
  236. reportStatus: ['0', '1', '3']
  237. },
  238. {
  239. type: 'danger',
  240. title: '退出',
  241. icon: Close,
  242. callback: () => handleClose(),
  243. reportStatus: ['0', '1', '2', '3']
  244. }
  245. ])
  246. const isDetail = computed(()=> {
  247. return currentInstance.allTaskInfo.reportStatus == '2' ? true : false;
  248. })
  249. const getButtonListByStatus = computed(() => {
  250. console.log(currentInstance, 'currentInstance')
  251. return buttonsList.value.filter(item => {
  252. const checkTypeCondition = !_.has(item, 'checkType') || (item.checkType || []).some(x => currentInstance.CheckItemInfo.checkType.includes(x));
  253. const reportStatusCondition = item.reportStatus.includes(currentInstance.allTaskInfo.reportStatus);
  254. const showCondition = !item.show || item.show();
  255. return checkTypeCondition && reportStatusCondition && showCondition;
  256. });
  257. });
  258. // 提交详情页
  259. const showPreviewReport = ref(false)
  260. const showPreviewEditOtherFileReport = ref(false)
  261. const reportType = ref('')
  262. const showPreviewEditOtherFileReportType = ref('')
  263. const templateParams = ref({})
  264. const editOtherFileTemplateParams = ref({})
  265. // 必须要报告编制完成之后,才能提交审核
  266. const handleSubmit = async () => {
  267. if(!currentInstance.reportConclusion.reportUrl) {
  268. ElMessage.error('请先编制报告')
  269. return
  270. }
  271. //如果是型式试验 要判断型式试验报告url是否存在
  272. if (currentInstance.allTaskInfo?.businessAcceptanceRespVO?.isTypeTest =='1') {
  273. if(!currentInstance.reportConclusion.typeInspectionReportUrl) {
  274. ElMessage.error('请先编制型式试验报告')
  275. return
  276. }
  277. }
  278. // console.log(currentInstance, 'currentInstance')
  279. Promise.all([reportConclusionRef.value.validateForm()]).then(async () => {
  280. isShowApprovalByDialog.value = true
  281. }).catch(err => {
  282. ElMessage.error('存在未填写的必填项!')
  283. console.log(err)
  284. })
  285. }
  286. // 选择审批人
  287. const handleApprovalBySelectConfirm = async (res) => {
  288. currentInstance.reportConclusion.reportApprovalBy = res[0]
  289. const result = await functionalStore.submitReport(instanceId.value, route.query.id)
  290. if(result === 'success') {
  291. // 提交成功
  292. handleClose()
  293. }
  294. }
  295. // 暂存详情页
  296. const handleCache = async () => {
  297. const result = await functionalStore.reportCache(instanceId.value, route.query.id)
  298. if(result === 'success') {
  299. handleClose()
  300. }
  301. }
  302. // 退出详情页
  303. const handleClose = () => {
  304. functionalStore.clearInstance(instanceId.value)
  305. tagsViewStore.closeSelectedTag(route)
  306. router.push({ path: '/laboratory/reportPreparation/list' })
  307. emitter.emit('refresh-reportPreparationIndex-list')
  308. }
  309. const handlePreviewClose = () => {
  310. currentPreviewId.value = ''
  311. currentFilename.value = ''
  312. previewVisible.value = false
  313. }
  314. // 撤回
  315. const handleRejectSubmit = () => {
  316. ElMessageBox.confirm('确认回撤该已编制的报告吗?', '提示', {
  317. confirmButtonText: '确 认',
  318. cancelButtonText: '取 消'
  319. })
  320. .then(async () => {
  321. try {
  322. const result = await withdrawReportPreparation({id: route.query.id})
  323. if(result) {
  324. ElMessage.success('回撤成功!')
  325. handleClose()
  326. }
  327. } catch (err) {
  328. ElMessage.error('回撤失败' + JSON.stringify(err))
  329. }
  330. })
  331. .catch(() => console.info('取消回撤'))
  332. }
  333. // 预览并打印合同
  334. const handlePreviewContracts = async () => {
  335. if (!currentInstance.reportConclusion.reportUrl) {
  336. return ElMessage.error('请先编制报告')
  337. }
  338. typeFlag.value = false
  339. currentPreviewId.value = route.query.id?.toString()
  340. currentFilename.value = `报告编号 ${currentInstance.allTaskInfo.reportNo}`
  341. previewVisible.value = true
  342. // const result = await previewPrepareReport({id: route.query.id})
  343. // loading.value = true
  344. // const previewFile = await previewPrepareReport({id: route.query.id})
  345. // if(previewFile) {
  346. // const flow = new Blob([previewFile], { type: 'application/pdf' })
  347. // const url = window.URL.createObjectURL(flow)
  348. // window.open(url, '_blank')
  349. // loading.value = false
  350. // }
  351. }
  352. const handlePreviewTypeInspectionRepor = async () => {
  353. console.log(currentInstance.reportConclusion, 'currentInstance.reportConclusion')
  354. if (!currentInstance.reportConclusion.typeInspectionReportUrl) {
  355. return ElMessage.error('请先编制型式试验报告')
  356. }
  357. typeFlag.value = true
  358. currentPreviewId.value = route.query.id?.toString()
  359. currentFilename.value = `报告编号 ${currentInstance.allTaskInfo.reportNo}`
  360. previewVisible.value = true
  361. // const result = await previewPrepareReport({id: route.query.id})
  362. // loading.value = true
  363. // const previewFile = await previewPrepareReport({id: route.query.id})
  364. // if(previewFile) {
  365. // const flow = new Blob([previewFile], { type: 'application/pdf' })
  366. // const url = window.URL.createObjectURL(flow)
  367. // window.open(url, '_blank')
  368. // loading.value = false
  369. // }
  370. }
  371. // 编辑附件报告
  372. const handleEditAttachment = () => {
  373. // 先填写报告结论,并且保存报告结论后,才可以编制报告
  374. Promise.all([reportConclusionRef.value.validateField('checkConclusion')]).then(async () => {
  375. if (!currentInstance.reportConclusion.checkConclusionOld) {
  376. const result = await functionalStore.reportCache(instanceId.value, route.query.id)
  377. await functionalStore.getReportPreparationInfo(instanceId.value, route.query.id)
  378. if (result === 'success') {
  379. showPreviewReport.value = true
  380. templateParams.value = {
  381. type: '2'
  382. }
  383. }
  384. }else {
  385. showPreviewReport.value = true
  386. }
  387. }).catch(err => {
  388. return ElMessage.warning('请先填写检验结论')
  389. })
  390. }
  391. // 编制报告
  392. const handlePrepareReport = () => {
  393. const verifyStatusFlag = currentInstance.businessCheckProjectDOS.every(x => x.verifyStatus == '1');
  394. if (!verifyStatusFlag) {
  395. return ElMessage.error('存在待校核的检验项目')
  396. }
  397. if (currentInstance.businessCheckProjectDOS)
  398. // 先填写报告结论,并且保存报告结论后,才可以编制报告
  399. Promise.all([reportConclusionRef.value.validateField('checkConclusion')]).then(async () => {
  400. if (!currentInstance.reportConclusion.checkConclusionOld) {
  401. const result = await functionalStore.reportCache(instanceId.value, route.query.id)
  402. await functionalStore.getReportPreparationInfo(instanceId.value, route.query.id)
  403. if (result === 'success') {
  404. showPreviewReport.value = true
  405. }
  406. }else {
  407. showPreviewReport.value = true
  408. }
  409. }).catch(err => {
  410. return ElMessage.warning('请先填写检验结论')
  411. })
  412. }
  413. // 编制型式试验报告
  414. const handleEditOtherFileFn = () => {
  415. const verifyStatusFlag = currentInstance.businessCheckProjectDOS.every(x => x.verifyStatus == '1');
  416. if (!verifyStatusFlag) {
  417. return ElMessage.error('存在待校核的检验项目')
  418. }
  419. // 先填写报告结论,并且保存报告结论后,才可以编制报告
  420. Promise.all([reportConclusionRef.value.validateField('checkConclusion')]).then(async () => {
  421. if (!currentInstance.reportConclusion.checkConclusionOld) {
  422. const result = await functionalStore.reportCache(instanceId.value, route.query.id)
  423. await functionalStore.getReportPreparationInfo(instanceId.value, route.query.id)
  424. if (result === 'success') {
  425. showPreviewEditOtherFileReport.value = true
  426. }
  427. }else {
  428. showPreviewEditOtherFileReport.value = true
  429. }
  430. }).catch(err => {
  431. return ElMessage.warning('请先填写检验结论')
  432. })
  433. }
  434. const handleArchivesManagement = ()=> {
  435. router.push({ name: 'reportArchivedFilesDetail',
  436. query: {
  437. id: route.query.id,
  438. }})
  439. }
  440. const { reportConclusion } = toRefs(currentInstance)
  441. // 获取新的报告编制详情
  442. const handleUpdateDetailData = async () => {
  443. templateParams.value = {}
  444. // 缓存报告结论等
  445. const cacheConclusion = JSON.parse(JSON.stringify(currentInstance.reportConclusion))
  446. await functionalStore.getReportPreparationInfo(instanceId.value, route.query.id)
  447. // 将缓存的报告结论回填
  448. reportConclusion.value = {
  449. ...cacheConclusion,
  450. reportUrl: currentInstance.allTaskInfo.reportUrl || '',
  451. typeInspectionReportUrl: currentInstance.allTaskInfo.typeInspectionReportUrl || '',
  452. reportAttachmentSjs: currentInstance.allTaskInfo.reportAttachmentSjs
  453. }
  454. currentInstance = reactive(functionalStore.getInstance(instanceId.value))
  455. }
  456. </script>
  457. <style lang="scss" scoped>
  458. /* 主容器 - 使用flexbox布局 */
  459. .prepare-detail-container {
  460. height: calc(100vh - 200px);
  461. display: flex;
  462. flex-direction: column;
  463. overflow: hidden; /* 关键:阻止主容器出现滚动条 */
  464. }
  465. /* 固定头部 */
  466. .fixed-header {
  467. flex-shrink: 0; /* 防止头部被压缩 */
  468. background-color: #fff;
  469. border-bottom: 1px solid #ebeef5;
  470. padding: 0 12px 10px 20px;
  471. z-index: 100;
  472. }
  473. .header {
  474. display: flex;
  475. justify-content: flex-end;
  476. align-items: center;
  477. .btns {
  478. display: flex;
  479. gap: 8px;
  480. flex-wrap: wrap;
  481. }
  482. }
  483. /* 可滚动的内容区域 */
  484. .scrollable-content {
  485. flex: 1; /* 占用剩余空间 */
  486. overflow-y: auto; /* 只在这里显示滚动条 */
  487. overflow-x: hidden;
  488. padding: 20px;
  489. /* 优化滚动体验 */
  490. scroll-behavior: smooth;
  491. /* 自定义滚动条样式 */
  492. &::-webkit-scrollbar {
  493. width: 6px;
  494. }
  495. &::-webkit-scrollbar-track {
  496. background: #f1f1f1;
  497. border-radius: 3px;
  498. }
  499. &::-webkit-scrollbar-thumb {
  500. background: #c1c1c1;
  501. border-radius: 3px;
  502. &:hover {
  503. background: #a8a8a8;
  504. }
  505. }
  506. /* Firefox滚动条样式 */
  507. scrollbar-width: thin;
  508. scrollbar-color: #c1c1c1 #f1f1f1;
  509. }
  510. /* 确保collapse组件不会影响布局 */
  511. .custom-collapse-form {
  512. width: 100%;
  513. }
  514. /* 响应式调整 */
  515. @media (max-width: 768px) {
  516. .fixed-header {
  517. padding: 10px 15px;
  518. }
  519. .scrollable-content {
  520. padding: 15px;
  521. }
  522. .header .btns {
  523. gap: 6px;
  524. }
  525. }
  526. /* 如果页面有其他容器,可以调整高度 */
  527. .prepare-detail-container.with-navbar {
  528. height: calc(100vh - 60px); /* 减去导航栏高度 */
  529. }
  530. .prepare-detail-container.with-tabs {
  531. height: calc(100vh - 100px); /* 减去导航栏和标签页高度 */
  532. }
  533. </style>