DynamicTbForm.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. <template>
  2. <div class="unit-create-and-edit" v-loading="formLoading">
  3. <el-tabs v-model="activeTab" @tab-click="handleTabClick" tab-position="left" class="unit-content"
  4. :before-leave="handleBeforeTabLeave">
  5. <div class="c-header">
  6. <div class="title">模板详情</div>
  7. <el-button class="close" link @click="handleClose"><el-icon size="22">
  8. <Close />
  9. </el-icon></el-button>
  10. </div>
  11. <el-tab-pane label="模板信息" name="模板信息">
  12. <div class="form-container">
  13. <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
  14. <el-form-item label="模板名字" prop="tbName">
  15. <el-input v-model="formData.tbName" placeholder="请输入模板名字" :disabled="formType === 'view'" />
  16. </el-form-item>
  17. <el-form-item label="模板编号" prop="tbCode">
  18. <el-input v-model="formData.tbCode" placeholder="请输入模板编号" :disabled="formType === 'view'" />
  19. </el-form-item>
  20. <el-form-item label="模板分类" prop="tbType">
  21. <el-select v-model="formData.tbType" placeholder="请选择模板分类" :disabled="formType === 'view'">
  22. <el-option v-for="dict in getIntDictOptions(DICT_TYPE.PRESSURE2_TB_TYPE)" :key="dict.value"
  23. :label="dict.label" :value="dict.value" />
  24. </el-select>
  25. </el-form-item>
  26. <el-form-item label="模板类型" prop="reportType">
  27. <el-select v-model="formData.reportType" placeholder="请选择模板类型" :disabled="formType === 'view'">
  28. <el-option v-for="dict in getIntDictOptions(DICT_TYPE.PRESSURE2_DYNAMIC_REPORT_TYPE)" :key="dict.value"
  29. :label="dict.label" :value="dict.value" />
  30. </el-select>
  31. </el-form-item>
  32. <el-form-item label="项目分类" prop="pjType">
  33. <el-select v-model="formData.pjType" placeholder="请选择项目分类" :disabled="formType === 'view'">
  34. <el-option v-for="dict in getIntDictOptions(DICT_TYPE.PRESSURE2_DYNAMIC_PROJECT_TYPE)"
  35. :key="dict.value" :label="dict.label" :value="dict.value" />
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item v-if="false" label="模板地址" prop="tbUrl">
  39. <el-input v-model="formData.tbUrl" placeholder="请输入模板地址" :disabled="formType === 'view'" />
  40. </el-form-item>
  41. <el-form-item label="版本号" prop="versionNo">
  42. <el-input v-model="formData.versionNo" placeholder="请输入版本号" :disabled="formType === 'view'" />
  43. </el-form-item>
  44. <el-form-item label="跳过页码数" prop="skipPageCount">
  45. <el-input-number v-model="formData.skipPageCount" :min="0" :max="10" :disabled="formType === 'view'" />
  46. </el-form-item>
  47. <el-form-item label="模板说明" prop="tbNote">
  48. <el-input v-model="formData.tbNote" type="textarea" placeholder="请输入模板说明" :disabled="formType === 'view'" />
  49. </el-form-item>
  50. <el-form-item label="创建人名" prop="creatorName">
  51. <el-input v-model="formData.creatorName" placeholder="请输入创建人名" :disabled="formType === 'view'" />
  52. </el-form-item>
  53. <el-form-item label="报告原件" prop="filePaths">
  54. <CustomUploadFile
  55. v-model:fileList="formData.filePaths"
  56. apiUrl="infra/file/upload"
  57. accept=".pdf,.jpg,.png,.doc,.wps,.docx,.DOC"
  58. list-type="text"
  59. :disabled="formType === 'view'"
  60. />
  61. </el-form-item>
  62. </el-form>
  63. </div>
  64. </el-tab-pane>
  65. <el-tab-pane label="模板文件" name="模板文件">
  66. <!--<SpreadView v-if="isSpredaShow" :dtParams="dtParams" :formData="formData" @success="getData" />-->
  67. <SpreadEditor v-if="isSpredaShow" :formType="formType" :dtParams="dtParams" :formData="formData" @success="getData" />
  68. </el-tab-pane>
  69. <!-- <el-tab-pane label="模板pdf" name="模板pdf">
  70. <div class="default-toolbar">
  71. <el-button type="primary" @click="handleOpenFileUploadModal" :disabled="formType === 'view'">上传模板</el-button>
  72. <el-button type="primary" @click="saveDocument" :disabled="formType === 'view'">保存模板</el-button>
  73. </div>
  74. <docEditor :config="officeConfig" @docReady="onDocumentReady" @docCreate="onCreateDoc" ref="officeEvents"/>
  75. -->
  76. <!--<DocumentEditor
  77. id="docEditor"
  78. v-if="officeVisible"
  79. :documentServerUrl="documentServerUrl"
  80. :config="officeConfig"
  81. :events_onDocumentReady="onDocumentReady"
  82. :onLoadComponentError="onLoadComponentError"
  83. />-->
  84. <!-- </el-tab-pane> -->
  85. <el-tab-pane :label="showInfos.title" :name="showInfos.title" v-if="formType !== 'create' && connectInfos?.length">
  86. <el-tabs v-model="activeSpreadTab" type="border-card" class="spread-tabs">
  87. <el-tab-pane
  88. v-for="(item, index) in spreadDataList"
  89. :key="index"
  90. :label="getTemplateName(item)"
  91. :name="index"
  92. class="spread-tab-pane"
  93. >
  94. <div class="spread-scrollbar-wrapper">
  95. <el-scrollbar>
  96. <SpreadViewer :initData="item.initData" ref="spreadRefs" />
  97. </el-scrollbar>
  98. </div>
  99. </el-tab-pane>
  100. </el-tabs>
  101. </el-tab-pane>
  102. </el-tabs>
  103. <div class="unit-footer-btns">
  104. <el-button @click="submitForm" type="primary" :disabled="formLoading" v-if="formType !== 'view'">确 定</el-button>
  105. <el-button @click="handleClose">{{ formType === 'view' ? '关 闭' : '取 消' }}</el-button>
  106. </div>
  107. <FileUploadModal ref="fileUploadModalRef" @success="handleFileUploadSuccess" />
  108. </div>
  109. </template>
  110. <script setup lang="ts">
  111. import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
  112. import { DynamicTbApi, DynamicTbVO } from '@/api/pressure2/dynamictb'
  113. import { Close } from "@element-plus/icons-vue";
  114. //import SpreadView from "@/components/DynamicReport/index1.vue";
  115. import {SpreadEditor, SpreadViewer} from '@/components/DynamicReport/index';
  116. //import { DocumentEditor } from "@onlyoffice/document-editor-vue";
  117. import { DocEditor,DocEditorEvents } from '@/components/BwDocEditor'
  118. import FileUploadModal from './ImportFile.vue'
  119. import {ref } from "vue";
  120. import GC from "@grapecity-software/spread-sheets";
  121. import undo = GC.Spread.Sheets.Commands.undo;
  122. import {useUserStore} from "@/store/modules/user";
  123. import {InitParams} from "@/components/DynamicReport/SpreadInterface";
  124. import {DynamicTbInsApi} from '@/api/pressure2/dynamictbins'
  125. import {BoilerConnectRecordReportApi} from "@/api/pressure2/boilerconnectrecordreport";
  126. /** 承压动态报表表单 表单 */
  127. defineOptions({ name: 'DynamicTbForm' })
  128. const { t } = useI18n() // 国际化
  129. const message = useMessage() // 消息弹窗
  130. const {getUser} = useUserStore()
  131. const dialogVisible = ref(false) // 弹窗的是否展示
  132. const dialogTitle = ref('') // 弹窗的标题
  133. const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  134. const formType = ref('') // 表单的类型:create - 新增;update - 修改;view - 查看
  135. const formData = ref({
  136. id: undefined,
  137. tbName: undefined,
  138. tbCode: undefined,
  139. tbType: undefined,
  140. reportType: undefined,
  141. pjType: undefined,
  142. tbUrl: undefined,
  143. versionNo: undefined,
  144. tbNote: undefined,
  145. creatorName: getUser.nickname,
  146. inPath: undefined,
  147. formUrl: undefined,
  148. formPath: undefined,
  149. filePaths: [],
  150. skipPageCount: 0,
  151. status: 400, // 默认下架状态
  152. })
  153. const formRules = reactive({
  154. tbName: [{ required: true, message: '模板名字不能为空', trigger: 'blur' }],
  155. tbCode: [{ required: true, message: '模板编号不能为空', trigger: 'blur' }],
  156. tbType: [{ required: true, message: '模板分类不能为空', trigger: 'change' }],
  157. reportType: [{ required: true, message: '模板类型不能为空', trigger: 'change' }],
  158. pjType: [{ required: true, message: '项目分类不能为空', trigger: 'change' }]
  159. })
  160. //const documentServerUrl = import.meta.env.VITE_ONLY_OFFICE_SERVER_URL;
  161. const fileUploadModalRef = ref<InstanceType<typeof FileUploadModal>>();
  162. const currentUploadMap = reactive({
  163. field: '',
  164. fieldAttr: '',
  165. })
  166. // 预览
  167. const router = useRouter();
  168. const connectInfos = ref<[]>(null);
  169. const showInfos = ref({
  170. title : undefined,
  171. type : undefined
  172. })
  173. // 根据 reportType 获取对应的模板 ID
  174. const getTemplateId = (item: any) => {
  175. return formData.value.reportType === 100 ? item.reportTemplateId : item.recordTemplateId
  176. }
  177. // SpreadViewer 相关数据
  178. const activeSpreadTab = ref<number | string>(0)
  179. const spreadRefs = ref()
  180. const spreadDataList = ref<Array<any>>([])
  181. // 根据 reportType 获取对应的模板名称
  182. const getTemplateName = (item: any) => {
  183. return formData.value.reportType === 100 ? item.reportTemplateName : item.recordTemplateName
  184. }
  185. const initConnectInfos = async () => {
  186. if (!tbId.value || !formData.value.reportType) return
  187. const isRecord = formData.value.reportType === 100
  188. const isReport = formData.value.reportType === 200
  189. if (isRecord || isReport) {
  190. showInfos.value = {
  191. title: isRecord ? '报告模板' : '记录模板',
  192. type: isRecord ? 'record' : 'report'
  193. }
  194. connectInfos.value = await BoilerConnectRecordReportApi.getByTemplateId({
  195. templateId: tbId.value,
  196. type: showInfos.value.type
  197. })
  198. // 为每个 connectInfo 创建对应的 SpreadViewer 数据
  199. spreadDataList.value = []
  200. const currentIndex = spreadDataList.value.length
  201. for (const [index, item] of connectInfos.value.entries()) {
  202. const templateId = getTemplateId(item)
  203. try {
  204. const res = await DynamicTbInsApi.getOrCreatePreviewData(templateId)
  205. spreadDataList.value.push({
  206. ...item,
  207. initData: {
  208. templateId: templateId,
  209. refId: res.refId,
  210. refName: '',
  211. insId: '',
  212. opType: 1, // 0:excel,1: pdf
  213. } as InitParams
  214. })
  215. // 等待 DOM 更新后刷新对应的 SpreadViewer
  216. setTimeout(() => {
  217. if (spreadRefs.value && Array.isArray(spreadRefs.value)) {
  218. spreadRefs.value[index]?.reloadView()
  219. }
  220. }, 400)
  221. } catch (error) {
  222. console.error(`加载模板 ${getTemplateName(item)} 失败:`, error)
  223. }
  224. }
  225. }
  226. }
  227. const handleOpenFileUploadModal = () => {
  228. //type: string, attach: string
  229. //currentUploadMap.field = type
  230. //currentUploadMap.fieldAttr = attach
  231. if(formData.value.id){
  232. fileUploadModalRef.value?.open();
  233. } else {
  234. message.alert("先保存才能导入模板!");
  235. }
  236. }
  237. const handleFileUploadSuccess = (fileInfo:{fileName: string, fileUrl: string,fileInfo:any}) => {
  238. //formData.value.tbUrl = fileInfo.fileUrl;
  239. //存filePath
  240. formData.value.inPath = fileInfo.fileUrl;
  241. getDocToDPFToken(formData.value.inPath,true);
  242. console.log('handleFileUploadSuccess:',fileInfo);
  243. //exceptionInfo.value[currentUploadMap.field] = fileInfo.fileName
  244. //exceptionInfo.value[currentUploadMap.fieldAttr] = fileInfo.fileUrl
  245. //console.log('handleFileUploadSuccess:', exceptionInfo.value)
  246. }
  247. //const officeVisible = ref(false)
  248. const officeEditor = ref<any>(null);
  249. const officeKey=ref<string>(null);
  250. const officeEvents=ref<DocEditorEvents>(null);
  251. const officeVisible=ref<boolean>(false);
  252. const officeConfig = ref({
  253. document: {
  254. fileType: 'pdf',
  255. key: null,
  256. permissions: {
  257. edit: true,
  258. },
  259. title: 'Form Template QC12005-202400',
  260. url: 'http://192.168.0.53/temp/QC12005-202400.pdf'
  261. },
  262. documentType: "pdf",
  263. token: ''
  264. });
  265. const officeParam=ref({
  266. documentType: 'PDF',
  267. fileType:'pdf',
  268. key: 'QC12005-202402_pdf',
  269. title: 'QC12005-202402',
  270. url: 'http://192.168.0.53/temp/QC12005-202402.pdf',
  271. pm_edit: true,
  272. pm_fillForms: false,
  273. refId: '',
  274. });
  275. const setToken=async ()=>{
  276. let oConfig= await DynamicTbApi.getToken(officeParam.value);
  277. //oConfig.token='';
  278. if(officeEditor.value){
  279. officeEditor.value.refreshFile(oConfig);
  280. } else {
  281. officeConfig.value =oConfig;
  282. }
  283. //officeVisible.value=true;
  284. }
  285. //setToken();
  286. const getDocToDPFToken=async (filePath:string,isNew:boolean)=>{
  287. officeVisible.value=false;
  288. let oConfig= await DynamicTbApi.getDocToDPFToken(filePath,formData.value.id,isNew);
  289. officeConfig.value =oConfig;
  290. formData.value.formUrl=oConfig.document.url;
  291. formData.value.formPath=oConfig.document.key;
  292. officeKey.value=oConfig.document.key;
  293. /*
  294. if(officeEditor.value){
  295. officeEditor.value.refreshFile(oConfig);
  296. }*/
  297. officeVisible.value=true;
  298. //officeVisible.value=true;
  299. }
  300. /*
  301. const loadPdfInit=()=>{
  302. getDocToDPFToken
  303. }*/
  304. const loadDPFToekn = async()=>{
  305. //officeVisible.value=false;
  306. //officeEditor.value?.destroyEditor();
  307. //officeParam.value.url='http://192.168.0.53:6180/cache/files/data/conv_b41bf875f729618600e4cc4ab04ae2296e239d9f80da814cdd8c26a710fa86fd.docx_513/output.pdf/QC12005-202400.pdf?md5=0CU3XwzCCGbb59DmozCQVA&expires=1763603489&shardkey=b41bf875f729618600e4cc4ab04ae2296e239d9f80da814cdd8c26a710fa86fd.docx&filename=QC12005-202400.pdf';
  308. officeParam.value.key="QC12005-202402_pdf";
  309. officeEditor.value?.destroyEditor();
  310. let oConfig= await DynamicTbApi.getToken(officeParam.value);
  311. officeConfig.value =oConfig;
  312. /*
  313. if(officeEditor.value){
  314. officeEditor.value.refreshFile(oConfig);
  315. } */
  316. //officeVisible.value=true;
  317. }
  318. const loadFilePathToekn = async ()=>{
  319. //officeVisible.value=false;
  320. officeEditor.value?.destroyEditor();
  321. let filePath='b41bf875f729618600e4cc4ab04ae2296e239d9f80da814cdd8c26a710fa86fd.docx';
  322. getDocToDPFToken(filePath,false);
  323. }
  324. const onDocumentReady = (event)=>{
  325. //const documentEditor = window.DocEditor.instances["docEditor"];
  326. //var a=window.DocEditor;
  327. //officeEditor.value = documentEditor;
  328. //const documentEditor =
  329. //officeEditor.value= event.target; //event.target.DocEditor();
  330. officeEditor.value?.showMessage("Welcome to ONLYOFFICE Editor!");
  331. console.log("Document is loaded");
  332. };
  333. const onCreateDoc=(e)=>{
  334. officeEditor.value= e.target; // event.target.DocEditor();
  335. officeEditor.value?.showMessage("Welcome to ONLYOFFICE Editor!");
  336. console.log("Document is create");
  337. }
  338. const clearDocument=()=>{
  339. //const documentEditor = window.DocEditor?.instances["docEditor"];
  340. //documentEditor?.destroyEditor();
  341. officeEvents.value?.closeEditor();
  342. }
  343. const saveDocument=async ()=>{
  344. //const documentEditor = window.DocEditor.instances["docEditor"];
  345. //documentEditor.destroyEditor();
  346. //const docAPI = await import(documentServerUrl+'web-apps/apps/api/documents/api.js');
  347. //let docEditor =new window.DocsAPI.DocEditor("docEditor", officeConfig.value);
  348. let connector=officeEditor.value.createConnector();
  349. connector.executeMethod("GetAllContentControls", [],(data)=>{
  350. var a=data;
  351. console.log("Document is GetAllContentControls:"+JSON.stringify(data));
  352. });
  353. //let a=officeEditor.value?.serviceCommand('init',officeConfig.value);
  354. console.log("Document is save click");
  355. }
  356. const onLoadComponentError= (errorCode, errorDescription)=>{
  357. switch(errorCode) {
  358. case -1: // Unknown error loading component
  359. console.log(errorDescription);
  360. break;
  361. case -2: // Error load DocsAPI from http://documentserver/
  362. console.log(errorDescription);
  363. break;
  364. case -3: // DocsAPI is not defined
  365. console.log(errorDescription);
  366. break;
  367. }
  368. };
  369. const dtParams = ref({
  370. tbCode: '',
  371. tbVersion: null
  372. });
  373. const isSpredaShow = ref(false);
  374. const formRef = ref() // 表单 Ref
  375. // el-tab 点击事件
  376. const activeTab = ref('模板信息');
  377. const handleTabClick = async (pane: {
  378. paneName: string
  379. }) => {
  380. let name = pane.paneName;
  381. if (name == '模板文件') {
  382. if (!tbId.value){
  383. message.alert("先保存才能导入模板!");
  384. return
  385. }
  386. if (formData.value.tbCode) {
  387. dtParams.value.tbCode = formData.value.tbCode;
  388. isSpredaShow.value = true;
  389. } else {
  390. isSpredaShow.value = false;
  391. }
  392. }
  393. /*
  394. const spreadRefMap = {
  395. '模板': recordDesignerRef.value,
  396. }
  397. const spreadMap = {
  398. '报告记录': recordDesigner,
  399. '报告模板': reportDesigner,
  400. '检验结果': resultDesigner,
  401. '金额计算': moneyDesigner
  402. }
  403. try {
  404. if(!spreadMap[name]) return;
  405. spreadMap[name].refresh();
  406. spreadMap[name].setData("treeNodeFromJson", basicForm.value.bindingPathSchema);
  407. // 设置工作表数据源字段释义
  408. spreadRefMap[name]?.handleUpdateDesignerState.set('bindingPathDataJSON', basicForm.value.bindingPathNameJson)
  409. } catch (error) {
  410. console.error('handleTabClick报错了', error)
  411. } */
  412. }
  413. const handleBeforeTabLeave = (active, oldActive) => {
  414. }
  415. const props = defineProps({
  416. visible: {
  417. type: Boolean,
  418. default: false
  419. },
  420. id: {
  421. type: Number,
  422. default: 0
  423. },
  424. type: {
  425. type: String,
  426. default: ''
  427. }
  428. })
  429. const tbId = ref()
  430. /** 打开弹窗 */
  431. const open = async () => {
  432. /** dialogVisible.value = true
  433. // dialogTitle.value = t('action.' + type) */
  434. formType.value = props.type
  435. tbId.value = props.id
  436. // 修改时,设置数据
  437. if (tbId.value) {
  438. formLoading.value = true
  439. try {
  440. formData.value = await DynamicTbApi.getDynamicTb(tbId.value)
  441. if(formData.value.id && formData.value.formPath){
  442. getDocToDPFToken(formData.value.formPath,false);
  443. }
  444. await initConnectInfos()
  445. } finally {
  446. formLoading.value = false
  447. }
  448. } else {
  449. resetForm();
  450. }
  451. }
  452. open();
  453. //defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  454. /** 提交表单 */
  455. const emit = defineEmits(['success', 'update:visible']) // 定义 success 事件,用于操作成功后的回调
  456. const submitForm = async () => {
  457. // view 模式下直接关闭
  458. if (formType.value === 'view') {
  459. handleClose()
  460. return
  461. }
  462. // 校验表单
  463. await formRef.value.validate()
  464. // 提交请求
  465. formLoading.value = true
  466. try {
  467. const data = formData.value as unknown as DynamicTbVO
  468. if (formType.value === 'create') {
  469. tbId.value = await DynamicTbApi.createDynamicTb(data)
  470. formData.value.id = tbId.value
  471. formType.value = 'update'
  472. message.success(t('common.createSuccess'))
  473. } else {
  474. await DynamicTbApi.updateDynamicTb(data)
  475. message.success(t('common.updateSuccess'))
  476. }
  477. dialogVisible.value = false
  478. // 发送操作成功的事件
  479. emit('success')
  480. } finally {
  481. formLoading.value = false
  482. }
  483. }
  484. /** 关闭表单 */
  485. const handleClose = () => {
  486. clearDocument();
  487. emit('update:visible', false);
  488. }
  489. const getData = async () => {
  490. }
  491. /** 重置表单 */
  492. const resetForm = () => {
  493. formData.value = {
  494. id: undefined,
  495. tbName: undefined,
  496. tbCode: undefined,
  497. tbType: undefined,
  498. reportType: undefined,
  499. pjType: undefined,
  500. tbUrl: undefined,
  501. versionNo: undefined,
  502. tbNote: undefined,
  503. creatorName: getUser.nickname,
  504. inPath: undefined,
  505. formUrl: undefined,
  506. formPath: undefined,
  507. filePaths: [],
  508. skipPageCount: 0,
  509. status: 400, // 默认下架状态
  510. }
  511. formRef.value?.resetFields()
  512. }
  513. </script>
  514. <style lang="scss" scoped>
  515. .unit-create-and-edit {
  516. position: absolute;
  517. left: 0;
  518. top: 0;
  519. right: 0;
  520. bottom: 0;
  521. z-index: 1000;
  522. box-sizing: border-box;
  523. background-color: #fff;
  524. overflow: hidden;
  525. :deep(.lab-designer-container) {
  526. height: 100% !important;
  527. }
  528. :deep(.spread-designer-container) {
  529. height: 100% !important;
  530. padding: 0;
  531. .default-toolbar {
  532. padding-top: 0px;
  533. }
  534. }
  535. }
  536. .c-header {
  537. position: sticky;
  538. top: 0;
  539. left: 0;
  540. display: flex;
  541. justify-content: space-between;
  542. align-items: center;
  543. height: 50px;
  544. padding: 0 20px;
  545. margin-bottom: -1px;
  546. font-size: 20px;
  547. line-height: 50px;
  548. border: 1px solid var(--el-border-color-light);
  549. background-color: #fff;
  550. z-index: 1000;
  551. }
  552. .unit-content {
  553. height: 100%;
  554. width: 100%;
  555. padding: 20px 0 56px 20px;
  556. overflow-y: hidden;
  557. :deep(.el-table) {
  558. margin-bottom: 12px;
  559. .el-table__header tr th.el-table__cell {
  560. color: #333;
  561. background-color: var(--el-border-color-light);
  562. }
  563. }
  564. :deep(.add-btn) {
  565. margin-bottom: 12px;
  566. }
  567. :deep(.c-title) {
  568. display: flex;
  569. justify-content: flex-start;
  570. align-items: center;
  571. width: 100%;
  572. height: 36px;
  573. margin-bottom: 18px;
  574. line-height: 36px;
  575. background-color: var(--el-color-primary-light-9);
  576. &::before {
  577. content: '';
  578. height: 100%;
  579. width: 3px;
  580. margin-right: 12px;
  581. background-color: var(--el-color-primary);
  582. }
  583. }
  584. :deep(.el-tabs__content) {
  585. padding-right: 20px;
  586. overflow-y: hidden;
  587. .el-row {
  588. margin: 0 !important;
  589. box-sizing: border-box;
  590. }
  591. .el-tab-pane {
  592. border: 1px solid var(--el-border-color-light);
  593. box-sizing: border-box;
  594. height: calc(100% - 49px);
  595. overflow: hidden;
  596. }
  597. }
  598. :deep(.el-tabs__header-vertical) {
  599. margin-right: -1px;
  600. border: 1px solid var(--el-border-color-light);
  601. .el-tabs__nav-wrap.is-left:after {
  602. display: none;
  603. }
  604. .el-tabs__active-bar {
  605. display: none;
  606. }
  607. .el-tabs__item {
  608. width: 220px;
  609. height: 50px;
  610. font-size: 14px;
  611. text-align: center;
  612. justify-content: center;
  613. &.is-active {
  614. background-color: var(--el-color-primary-light-9);
  615. }
  616. }
  617. }
  618. :deep(.el-table__cell) {
  619. .el-form-item {
  620. margin-bottom: 0;
  621. }
  622. }
  623. }
  624. .unit-footer-btns {
  625. position: absolute;
  626. left: 0;
  627. right: 0;
  628. bottom: 0;
  629. background: #fff;
  630. padding: 12px 0;
  631. display: flex;
  632. justify-content: center;
  633. }
  634. .form-container{
  635. height: 100%;
  636. padding-top: 15px;
  637. overflow-y: auto;
  638. }
  639. .record-template-buttons {
  640. padding: 10px 0;
  641. .el-button {
  642. margin-right: 10px;
  643. margin-bottom: 10px;
  644. }
  645. }
  646. .spread-tabs {
  647. height: 100%;
  648. :deep(.el-tabs__content) {
  649. height: calc(100% - 40px);
  650. overflow: hidden;
  651. }
  652. :deep(.el-tabs__header) {
  653. margin-bottom: 0;
  654. }
  655. }
  656. .spread-tab-pane {
  657. height: 100%;
  658. padding: 0 !important;
  659. }
  660. .spread-scrollbar-wrapper {
  661. height: 100%;
  662. padding: 10px;
  663. box-sizing: border-box;
  664. :deep(.el-scrollbar) {
  665. height: 100%;
  666. }
  667. }
  668. </style>