| | |
| | | <div class="bottom"> |
| | | <div class="left"> |
| | | <span style="font-weight: 600;font-size: 24px">目录</span> |
| | | <el-tree |
| | | v-if="data.treeData" |
| | | style="max-width: 600px;margin-top: 20px" |
| | | :data="data.treeData" |
| | | :props="data.defaultProps" |
| | | :default-expand-all="true" |
| | | :expand-on-click-node="false" |
| | | highlight-current |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | <div class="tree-container tree-hide-scrollbar" v-if="data.treeData"> |
| | | <el-tree |
| | | ref="treeRef" |
| | | :data="data.treeData" |
| | | :props="data.defaultProps" |
| | | :default-expand-all="true" |
| | | :expand-on-click-node="false" |
| | | highlight-current |
| | | node-key="id" |
| | | :current-node-key="currentSelectedKey" |
| | | @node-click="handleNodeClick" |
| | | ></el-tree> |
| | | </div> |
| | | <el-empty v-else description="暂无数据" /> |
| | | </div> |
| | | <div class="right"> |
| | | <el-form :model="state.form" size="default" ref="noticeRef" :rules="data.formRules" label-position="left" label-width="125px" > |
| | | <el-form-item label="具体内容" prop="content" > |
| | | |
| | | <t-editor style="width: 100%;" :height="300" ref="myEditor1" :value="state.form.content" ></t-editor> |
| | | <!-- <el-input v-model="state.form.content" :rows="4" type="textarea" />--> |
| | | <el-form-item label="具体内容" prop="content" v-if="data.isAdmin"> |
| | | <t-editor style="width: 100%;" :height="400" ref="myEditor1" :value="state.form.content" ></t-editor> |
| | | </el-form-item> |
| | | <el-form-item label="标准分析" prop="analysis" > |
| | | <t-editor style="width: 100%;" :height="300" ref="myEditor2" :value="state.form.analysis" ></t-editor> |
| | | <!-- <el-input v-model="state.form.analysis" :rows="4" type="textarea" />--> |
| | | <el-form-item label="具体内容" prop="content" v-else> |
| | | <div class="ql-container ql-snow" style="height: 500px;width: 100%;margin-top: 10px;" > |
| | | <div class="ql-editor"> |
| | | <div v-if="state.form.content" class="reviewTable" v-html="state.form.content" @click="showFile($event)"></div> |
| | | <el-empty v-else description="暂无数据" /> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="标准分析" prop="analysis" v-if="data.isAdmin"> |
| | | <t-editor style="width: 100%;" :height="400" ref="myEditor2" :value="state.form.analysis" ></t-editor> |
| | | </el-form-item> |
| | | <el-form-item label="标准分析" prop="content" v-else> |
| | | <div class="ql-container ql-snow" style="height: 500px;width: 100%;margin-top: 10px;" > |
| | | <div class="ql-editor"> |
| | | <div v-if="state.form.analysis" class="reviewTable" v-html="state.form.analysis" @click="showFile($event)"></div> |
| | | <el-empty v-else description="暂无数据" /> |
| | | |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="应准备材料" prop="dataList"> |
| | | <el-button type="primary" @click="openDataDialog('add',{})">新增</el-button> |
| | | <el-button v-if="data.isAdmin" type="primary" @click="openDataDialog('add',{})">新增</el-button> |
| | | </el-form-item> |
| | | <el-table style="margin:15px 0;width: 100%" :data="state.form.dataList" :border="true" > |
| | | <el-table-column type="index" label="序号" width="80" align="center"></el-table-column> |
| | | <el-table-column label="材料名称" prop="name" align="center" /> |
| | | <!-- <el-table-column label="材料模板" prop="fileName" align="center" >--> |
| | | <!-- <template #default="scope">--> |
| | | <!-- <el-link v-if="scope.row.fileName" style="" type="primary" @click="downloadFile(scope.row)">{{scope.row.fileName}}</el-link>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | <el-table-column label="材料模板" prop="fileName" align="center" > |
| | | <template #default="scope"> |
| | | <el-link v-if="scope.row.fileName" style="" type="primary" @click="openFile(scope.row.filePath)">{{scope.row.fileName}}</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" align="center" class-name="small-padding fixed-width" > |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="openDataDialog('edit',scope.row)" >编辑</el-button> |
| | | <el-button link type="danger" @click="handleDataDelete(scope.row)" >删除</el-button> |
| | | <el-button v-if="scope.row.filePath" link type="primary" @click="downloadFile(scope.row)" >下载</el-button> |
| | | <el-button v-if="data.isAdmin" link type="primary" @click="openDataDialog('edit',scope.row)" >编辑</el-button> |
| | | <el-button v-if="data.isAdmin" link type="danger" @click="handleDataDelete(scope.row)" >删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <!-- </el-table>--> |
| | | </el-form> |
| | | <div style="display: flex;align-items: center;justify-content: right;margin-top: 10px"> |
| | | <el-button v-if="state.form.id" type="danger" @click="deleteData">删除</el-button> |
| | | <el-button type="primary" @click="addData()">保存</el-button> |
| | | <el-button v-if="state.form.id && data.isAdmin" type="danger" @click="deleteData">删除</el-button> |
| | | <el-button v-if="data.isAdmin" type="primary" @click="addData()">保存</el-button> |
| | | </div> |
| | | |
| | | </div> |
| | |
| | | </div> |
| | | </template> |
| | | <script setup> |
| | | import {getCurrentInstance, onMounted, reactive, ref, toRefs} from "vue"; |
| | | import {getCurrentInstance, nextTick, onMounted, reactive, ref, toRefs} from "vue"; |
| | | import Cookies from "js-cookie"; |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import {getCompany} from "@/api/onlineEducation/company"; |
| | |
| | | } from "@/api/qualityManage/range"; |
| | | import axios from "axios"; |
| | | import TEditor from "@/components/Tinymce/Tinymce.vue"; |
| | | import {renderAsync} from "docx-preview"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const loading = ref(false); |
| | |
| | | const dialogRef = ref(); |
| | | const myEditor1 = ref(); |
| | | const myEditor2 = ref(); |
| | | const treeRef = ref() |
| | | const dialogRecordRef = ref(); |
| | | const currentSelectedKey = ref() |
| | | const loadingCompany = ref(false) |
| | | const data = reactive({ |
| | | queryParams: { |
| | |
| | | state.form.companyId = userInfo.companyId |
| | | } |
| | | await getList(); |
| | | if(data.treeData.length >0){ |
| | | state.form.catalogueId = data.treeData[0].id |
| | | currentSelectedKey.value = state.form.catalogueId |
| | | await getCatalogDataList() |
| | | await getFileList() |
| | | |
| | | } |
| | | |
| | | }) |
| | | const getList = async () => { |
| | |
| | | ElMessage.warning(res.message) |
| | | } |
| | | loading.value = false; |
| | | |
| | | } |
| | | const handleTree = (val) => { |
| | | const traverse = (nodes, currentPath = '') => { |
| | |
| | | const selectValue = async (val) => { |
| | | state.form.analysis = '' |
| | | state.form.content = '' |
| | | myEditor1.value.myValue = '' |
| | | myEditor2.value.myValue = '' |
| | | if(data.isAdmin){ |
| | | myEditor1.value.myValue = '' |
| | | myEditor2.value.myValue = '' |
| | | } |
| | | state.form.id = '' |
| | | data.companyList.forEach(item => { |
| | | if(item.name === val){ |
| | |
| | | const handleNodeClick = async (val) => { |
| | | state.form.analysis = '' |
| | | state.form.content = '' |
| | | myEditor1.value.myValue = '' |
| | | myEditor2.value.myValue = '' |
| | | if(data.isAdmin){ |
| | | myEditor1.value.myValue = '' |
| | | myEditor2.value.myValue = '' |
| | | } |
| | | |
| | | |
| | | state.form.id = '' |
| | | state.form.catalogueId = val.id |
| | | currentSelectedKey.value = val.id |
| | | await getCatalogDataList() |
| | | await getFileList() |
| | | } |
| | |
| | | ElMessage.warning(res.message) |
| | | } |
| | | } |
| | | const openFile = async(path)=>{ |
| | | try { |
| | | // 1. 获取文件 |
| | | const response = await fetch(import.meta.env.VITE_APP_BASE_API + '/' + path); |
| | | const arrayBuffer = await response.arrayBuffer(); |
| | | // 2. 创建新窗口 |
| | | const win = window.open('', '_blank') |
| | | win.document.write(` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <title>预览</title> |
| | | <style> |
| | | body { margin: 20px; font-family: Arial; } |
| | | .docx-container { width: 100%; height: 100%; } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div id="container" class="docx-container"></div> |
| | | </body> |
| | | </html> |
| | | `); |
| | | // 3. 渲染 DOCX |
| | | await renderAsync(arrayBuffer, win.document.getElementById('container')); |
| | | |
| | | } catch (error) { |
| | | console.error('预览失败:', error); |
| | | alert(`预览失败: ${error.message}`); |
| | | } |
| | | } |
| | | const downloadFile = (e)=>{ |
| | | axios.get(import.meta.env.VITE_APP_BASE_API + '/' +e.filePath,{headers:{'Content-Type': 'application/json','Authorization': `${getToken()}`},responseType: 'blob'}).then(res=>{ |
| | | if (res) { |
| | |
| | | } |
| | | }) |
| | | } |
| | | |
| | | const showFile = (e) => { |
| | | if(e.target.nodeName === 'A'){ |
| | | console.log("e",e) |
| | | e.preventDefault(); |
| | | const file = { |
| | | fileUrl: e.target.href, |
| | | fileName: e.target.innerHTML |
| | | } |
| | | axios.get( file.fileUrl,{ |
| | | headers: |
| | | { |
| | | 'Content-Type': 'application/json', |
| | | 'Authorization':getToken(), |
| | | }, |
| | | responseType: 'blob' |
| | | } |
| | | ).then(res=>{ |
| | | if (res) { |
| | | const link = document.createElement('a') |
| | | let blob = new Blob([res.data],{type: res.data.type}) |
| | | link.style.display = "none"; |
| | | link.href = URL.createObjectURL(blob); // 创建URL |
| | | link.setAttribute("download", file.fileName); |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | } else { |
| | | this.$message.error('获取文件失败') |
| | | } |
| | | // handleClose(); |
| | | }) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | margin: 20px; |
| | | |
| | | .left{ |
| | | border-right: 1px solid darkgray; |
| | | //border-right: 1px solid darkgray; |
| | | display: flex; |
| | | min-width: 240px; |
| | | margin: 20px 20px 20px 50px; |
| | | flex-direction: column; |
| | | :deep(.el-tree){ |
| | | background: none; |
| | | } |
| | | .tree-container { |
| | | max-width: 600px; |
| | | margin-top: 20px; |
| | | height: 100%; |
| | | box-shadow: 8px 0 15px rgba(0,21,41,0.08); |
| | | overflow: auto; /* 确保出现滚动条 */ |
| | | } |
| | | |
| | | /* 隐藏默认滚动条 */ |
| | | .tree-hide-scrollbar::-webkit-scrollbar { |
| | | width: 5px; |
| | | background-color: transparent; |
| | | } |
| | | .tree-hide-scrollbar::-webkit-scrollbar-thumb { |
| | | background-color: transparent; |
| | | border-radius: 4px; |
| | | } |
| | | /* 鼠标悬停时显示滚动条 */ |
| | | .tree-hide-scrollbar:hover::-webkit-scrollbar-thumb { |
| | | background-color: #e1e1e1; |
| | | } |
| | | .tree-hide-scrollbar:hover::-webkit-scrollbar-track { |
| | | background-color: #f5f7fa; |
| | | } |
| | | .tree{ |
| | | max-width: 600px; |
| | | margin-top: 20px; |
| | | height: 800px; |
| | | overflow-x: hidden; |
| | | box-shadow: 8px 0 15px rgba(0,21,41,0.08) |
| | | } |
| | | } |
| | | .right{ |
| | |
| | | :deep(.el-form-item__label){ |
| | | font-weight: 600;font-size: 20px |
| | | } |
| | | .reviewTable { |
| | | :deep(table){ |
| | | border: 1px solid #ccc; |
| | | text-align: center; |
| | | } |
| | | :deep(table td){ |
| | | border: 1px solid #ccc; |
| | | text-align: center; |
| | | padding: 0 5px; |
| | | } |
| | | :deep(table th){ |
| | | border: 1px solid #ccc; |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |