zhouwx
2025-07-07 e1fb583646c1497eee415334b54daebe1b5b098d
修改
已修改3个文件
202 ■■■■ 文件已修改
src/components/Tinymce/Tinymce.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/build/conpanyFunctionConsult/digitalFileDep/manageType/qualityManual/index.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/build/conpanyFunctionConsult/qualityManage/rangeManage/range/index.vue 187 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Tinymce/Tinymce.vue
@@ -70,6 +70,19 @@
                relative_urls: false,
                remove_script_host: true,
                statusbar: false,
              font_formats: '默认字体=default;' +
                  'Arial=arial,helvetica,sans-serif;' +
                  '楷体=KaiTi, "Kai", serif;' +
                  '圆体=Microsoft YaHei UI, sans-serif;' +
                  '思源宋体=Source Han Serif SC, serif;' +
                  '宋体=SimSun, NSimSun, "Songti SC", serif;' +  // Windows宋体
                  '新宋体=NSimSun, serif;' +
                  '黑体=SimHei, "Microsoft YaHei", "PingFang SC", sans-serif;' + // Windows黑体
                  '微软雅黑=Microsoft YaHei, sans-serif;' +
                  '仿宋=FangSong, "Fang", serif;',
              // 字体样式应用到文本时使用 <span> 而非 <font>
              inline_styles: true,
                images_upload_handler: async (blobInfo, success, failure) => {
                    const formData = new FormData(); // 和后端协商后用formData格式进行传参
                    formData.append("file", blobInfo.blob());// 传递的参数
src/views/build/conpanyFunctionConsult/digitalFileDep/manageType/qualityManual/index.vue
@@ -43,7 +43,7 @@
      </el-table-column>
    </el-table>
<!--    <org-tree :data="companyInfo.deptList" />-->
    <button @click="exportOrgChart">导出组织架构图</button>
<!--    <button @click="exportOrgChart">导出组织架构图</button>-->
    <pagination
        v-show="total > 0"
        :total="total"
src/views/build/conpanyFunctionConsult/qualityManage/rangeManage/range/index.vue
@@ -31,44 +31,62 @@
    <div class="bottom">
      <div class="left">
        <span style="font-weight: 600;font-size: 24px">目录</span>
        <div  class="tree-container tree-hide-scrollbar"  v-if="data.treeData">
        <el-tree
            v-if="data.treeData"
            style="max-width: 600px;margin-top: 20px"
              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>
@@ -92,8 +110,8 @@
<!--          </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>
@@ -103,7 +121,7 @@
  </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";
@@ -123,6 +141,7 @@
} 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);
@@ -130,7 +149,9 @@
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: {
@@ -191,6 +212,13 @@
    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 () => {
@@ -207,7 +235,6 @@
    ElMessage.warning(res.message)
  }
  loading.value = false;
}
const handleTree = (val) => {
  const traverse = (nodes, currentPath = '') => {
@@ -255,8 +282,10 @@
const selectValue = async (val) => {
  state.form.analysis = ''
  state.form.content = ''
  if(data.isAdmin){
  myEditor1.value.myValue = ''
  myEditor2.value.myValue = ''
  }
  state.form.id = ''
  data.companyList.forEach(item => {
    if(item.name === val){
@@ -274,10 +303,15 @@
const handleNodeClick = async (val) => {
  state.form.analysis = ''
  state.form.content = ''
  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()
}
@@ -451,6 +485,36 @@
    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) {
@@ -470,6 +534,40 @@
    }
  })
}
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">
@@ -482,13 +580,44 @@
    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{
@@ -498,6 +627,20 @@
      :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;
        }
      }
    }
  }