Browse Source

表单管理

SanHQin 5 months ago
parent
commit
fca95ccd4d

+ 720 - 93
src/components/pages/test/check/docxTemplateDialog.vue

@@ -7,14 +7,26 @@
     top="10vh"
     :before-close="handleClose"
     class="dialog_diy"
+    ref="docxTemplateDialogRef"
   >
     <div class="box" v-loading="loading">
-      <div class="b_left">
-				<topicVue :cJson="checkJson" :checktype="2" :see="true" :isTeacher="1" title="" brief="" ref="topicVue"/>
-			</div>
+      <div
+        class="b_left"
+        v-loading="wordContentLoading"
+        ref="wordAreaRef"
+        contenteditable="true"
+      >
+        <VueOfficeDocx
+          ref="vueOfficeDocxRef"
+          v-if="downFileData &&  !downFileData.txtUrl"
+          :src="downFileData ? downFileData.url : ''"
+        />
+
+				<txtHtmlView  ref="txtHtmlViewRef" v-if="downFileData && downFileData.txtUrl" :url="downFileData.txtUrl" @getTxtContent="getTxtContent"/>
+      </div>
       <div class="b_right">
         <div class="d_box">
-          <div class="d_b_step">
+          <!-- <div class="d_b_step">
             <h2>第一步:下载模板文档</h2>
             <p>点击下载模板文档来下载指定文档</p>
             <el-button
@@ -24,41 +36,55 @@
               @click="downloadTemplateDocx()"
               >下载模板文档</el-button
             >
-          </div>
+          </div> -->
 
           <div class="d_b_step">
-            <h2>第步:填入模板变量</h2>
+            <h2>第步:填入模板变量</h2>
             <p>按需制作排版Word模板文档,目前支持docx格式</p>
             <p>
               在文件中指定位置输入下方的"字段变量",用于显示真实数据的准确位置
             </p>
-						
-						<h3>文本:</h3>
+
+            <h3>文本:</h3>
             <img
               src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/default%2F%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_202410090922471728436994846.png"
             />
 
-						<h3>选择题:</h3>
-						<div class="d_b_s_imgList">
-							<img src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/41728546186962.png">
-							<img src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/51728546189479.png">
-						</div>
-						<div class="foldMenu">
-							<span v-if="foldField" @click="foldField = false">折叠字段变量</span>
-							<span v-if="!foldField" @click="foldField = true">显示字段变量</span>
-						</div>
+            <h3>选择题:</h3>
+            <div class="d_b_s_imgList">
+              <img
+                src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/41728546186962.png"
+              />
+              <img
+                src="https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/51728546189479.png"
+              />
+            </div>
+            <div class="foldMenu">
+              <span v-if="foldField" @click="foldField = false"
+                >折叠字段变量</span
+              >
+              <span v-if="!foldField" @click="foldField = true"
+                >显示字段变量</span
+              >
+            </div>
             <div
               v-for="(item, index) in fieldList"
               :key="index"
               class="d_b_s_fieldListItem"
-							v-if="foldField"
+              v-if="foldField"
             >
               <span
                 >{{ item.name }}:{{
                   "{" + (item.type == "image" ? "%" : "") + item.field + "}"
                 }}</span
               >
-              <span @click="copyContent(`{${item.type == 'image' ? '%' : ''}${item.field}}`)">
+              <span
+                @click="
+                  copyContent(
+                    `{${item.type == 'image' ? '%' : ''}${item.field}}`
+                  )
+                "
+              >
                 <svg
                   width="14"
                   height="14"
@@ -80,7 +106,7 @@
             </div>
           </div>
 
-          <div class="d_b_step">
+          <!-- <div class="d_b_step">
             <h2>第三步:上传填入后的模板文档</h2>
             <div v-if="uploadTemplateDocxData" class="d_b_s_fileCard">
               <svg
@@ -115,16 +141,16 @@
               @click="uploadTemplateDocx()"
               >上传填入后的模板文档</el-button
             >
-          </div>
+          </div> -->
 
           <div class="d_b_step">
-            <h2>第步:点击导出</h2>
+            <h2>第步:点击导出</h2>
             <p></p>
             <el-button
               class="d_b_s_button"
               type="primary"
-              :disabled="!uploadTemplateDocxData"
-              @click="exportDocx()"
+              :disabled="!downFileData"
+              @click="exportDocx2()"
               >导出Word文档</el-button
             >
           </div>
@@ -138,8 +164,15 @@
 import PizZip from "pizzip";
 import Docxtemplater from "docxtemplater";
 import ImageModule from "docxtemplater-image-module-free";
-import { saveAs } from 'file-saver';
+import { saveAs } from "file-saver";
 import topicVue from "../../testStudent/view/component/topic.vue";
+// import { renderAsync } from 'docx-preview/dist/docx-preview.js'
+import VueOfficeDocx from "@vue-office/docx";
+import "@vue-office/docx/lib/index.css";
+// import { renderAsync } from 'docx-preview/dist/docx-preview.js'
+import htmlDocx from "html-docx-js/dist/html-docx";
+import txtHtmlView from "./txtHtmlView.vue"
+// import a from './docx-preview.js'
 const getFile = url => {
   return new Promise((resolve, reject) => {
     var credentials = {
@@ -181,9 +214,11 @@ const getFile = url => {
 
 export default {
   props: {},
-	components:{
-		topicVue
-	},
+  components: {
+    topicVue,
+    VueOfficeDocx,
+		txtHtmlView
+  },
   data() {
     return {
       show: false,
@@ -200,8 +235,11 @@ export default {
       ],
       uploadTemplateDocxData: null, //上传的模板文档
       downFileData: null, // 下载模板文档的url
-			checkJson:[],
-			foldField:false,
+      checkJson: [],
+      foldField: false,
+      wordContent: "",
+      wordContentLoading: true,
+			courseId:"",
     };
   },
   methods: {
@@ -210,46 +248,88 @@ export default {
       done();
     },
     open(data) {
-			this.init();
-			let _fileData = data.fileData;
-			this.downFileData = _fileData;
-			this.checkJson = data.formData.array
-			this.fieldList = this.getFieldData(data.formData.array)
+      this.init();
+      let _fileData = data.fileData;
+      this.downFileData = _fileData;
+			this.courseId = data.courseId
+      this.checkJson = data.formData.array;
+      this.fieldList = this.getFieldData(data.formData.array);
+      this.getWordContent(this.downFileData);
       this.show = true;
     },
     close() {
       this.show = false;
-			this.init();
+      this.init();
     },
-    init() { // 初始化
-			this.downFileData = null;
-			this.fieldList = [];
-			this.uploadTemplateDocxData = null;
-			this.foldField = false;
+    init() {
+      // 初始化
+      this.downFileData = null;
+      this.fieldList = [];
+      this.uploadTemplateDocxData = null;
+      this.foldField = false;
     },
 
-		getFieldData(array){
-			let _list = [];
-			let _index = 0;
-			for(let i=0;i<array.length;i++){
-				let _item = array[i];
-				if(_item.type == 3){
-					let _item2 = _item.json;
-					_list.push({name: _item2.title, field: `ti_${_index}`, type: "text", value: _item2.answer2})
-					_index++;
-				}else if(_item.type==1){
-					let _item2 = _item.json;
-					let choseTxt = ``
-					_item2.array.forEach((i,index2)=>{
-						choseTxt += `${(_item2.answer2===index2 || _item2.answer2.includes(index2)?'☑':'□')}${i.option}    `
-					})
-					_list.push({name:_item2.title,field: `ti_${_index}`, type: "text", value: choseTxt})
-					_index++;
-				}
-			}
-			return _list;
-		},
+    getFieldData(array) {
+      let _list = [];
+      let _index = 0;
+      for (let i = 0; i < array.length; i++) {
+        let _item = array[i];
+        if (_item.type == 3) {
+          let _item2 = _item.json;
+          _list.push({
+            name: _item2.title,
+            field: `ti_${_index}`,
+            type: "text",
+            value: _item2.answer2
+          });
+          _index++;
+        } else if (_item.type == 1) {
+          let _item2 = _item.json;
+          let choseTxt = ``;
+          _item2.array.forEach((i, index2) => {
+            choseTxt += `${
+              _item2.answer2 === index2 || _item2.answer2.includes(index2)
+                ? "☑"
+                : "□"
+            }${i.option}    `;
+          });
+          _list.push({
+            name: _item2.title,
+            field: `ti_${_index}`,
+            type: "text",
+            value: choseTxt
+          });
+          _index++;
+        }
+      }
+      return _list;
+    },
     downloadTemplateDocx() {
+      const officeViewer = this.$refs.vueOfficeDocxRef;
+      // console.log(this.$refs.docxTemplateDialogRef)
+      // console.log(officeViewer)
+      const blob = new Blob([officeViewer.$el.innerHTML], {
+        type:
+          "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+      });
+      const url = URL.createObjectURL(blob);
+      const a = document.createElement("a");
+      a.href = url;
+      a.download = this.downFileData.fileName;
+      a.click();
+      this.$message.success("下载成功");
+
+      // console.log(officeViewer.$data)
+      // officeViewer.exportDocx()
+      // officeViewer.getContent().then(content => {
+      // 	console.log(content)
+      // })
+      // console.log(this.$refs.vueOfficeDocxRef.$el);
+      // const el = this.$refs.vueOfficeDocxRef.$el;
+      // const body = el.querySelector(".docx");
+      // console.log("👉",body);
+      // this.generateDocx(this.downFileData.fileName,officeViewer.$el.innerHTML)
+      return;
       getFile(this.downFileData.url).then(data => {
         if (data.data != 1) {
           // 下载文件, 并存成ArrayBuffer对象
@@ -288,6 +368,170 @@ export default {
         // this.uploadWavFileAndGetText(file);
       };
     },
+    async exportDocx2() {
+      const el = this.$refs.vueOfficeDocxRef?this.$refs.vueOfficeDocxRef.$el:this.$refs.txtHtmlViewRef.$el;
+			console.log(el)
+      const body = el.querySelector(".docx-wrapper");
+
+			let _html = body.innerHTML;
+
+			for(let i = 0;i<this.fieldList.length;i++){
+				if(this.fieldList[i].type == 'image'){
+					const img = await this.convertImageUrlToBase64(this.fieldList[i].value)
+					_html = _html.replaceAll(`{%${this.fieldList[i].field}}`,`<img src="${img.url}" width="${img.width}" height="${img.height}" />`)
+				}else if(this.fieldList[i].type == 'text'){
+					_html = _html.replaceAll(`{${this.fieldList[i].field}}`,this.fieldList[i].value)
+				}
+			}
+			// this.fieldList.forEach(i => {
+				// _html = _html.replace(`{${i.field}}`,i.value)
+			// })
+			// 下载word文档
+			await this.generateDocx(this.downFileData.fileName,_html)
+
+			if(!this.downFileData.txtUrl || this.downFileData.txt !== el.innerHTML){
+				let txt = el.innerHTML;
+				// 创建Blob对象
+				const blob = new Blob([txt], { type: "text/plain;charset=utf-8" });
+				blob.lastModifiedDate = new Date();
+				blob.name = `${this.downFileData.fileName}_wordHtml.txt`;
+				let url = await this.uploadFile(blob)
+
+				if(url && this.courseId){
+					console.log("修改文件")
+					console.log(url)
+					console.log(this.courseId)
+					this.downFileData.txt = txt
+					this.downFileData.txtUrl = url
+					this.changeDownFileData(this.downFileData)
+					this.$forceUpdate();
+				}
+			}
+			// const uploadBlob = await this.getGenerateDocxHtml(body.out)
+
+			// let reader = new FileReader();
+      // reader.readAsArrayBuffer(uploadBlob);
+			// reader.onload = async e => {
+			// 	try {
+			// 		const binary = new Uint8Array(reader.result);
+			// 		//创建一个PizZip实例
+			// 		const zip = new PizZip(binary);
+			// 		// 将模板内容加载到 Docxtemplater 中
+			// 		const doc = new Docxtemplater().loadZip(zip);
+			// 		const output = doc.getZip().generate({
+      //       type: "blob",
+      //       mimeType:
+      //         "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+      //       compression: "DEFLATE"
+      //     });
+
+			// 		const file = new File([output],this.downFileData.fileName,{type:".docx",lastModified:new Date().getTime()})
+
+			// 		const url = await this.uploadFile(file)
+			// 		console.log(url)
+
+			// 	}catch(e){
+			// 		console.log(e)
+			// 	}
+			// }
+			// const file = new File([uploadBlob],this.downFileData.fileName,{type:".docx",lastModified:new Date().getTime()})
+			
+			// const url = await this.uploadFile(file)
+			// console.log(url)
+			// if(url){
+				
+			// }else{
+				
+			// }
+			return
+      // const blob = await this.getGenerateDocxHtml(body.innerHTML);
+      // if (!blob) return this.$message.error("导出失败");
+
+      // let reader = new FileReader();
+      // reader.readAsArrayBuffer(blob);
+      // reader.onload = async e => {
+      //   try {
+      //     this.loading = true;
+      //     const binary = new Uint8Array(reader.result);
+      //     //创建一个PizZip实例
+      //     const zip = new PizZip(binary);
+      //     // 将模板内容加载到 Docxtemplater 中
+      //     const doc = new Docxtemplater().loadZip(zip);
+
+      //     let _data = {};
+      //     let _image = {};
+      //     // 设置模板值
+      //     // this.fieldList.forEach(i => {
+      //     //   _data[i.field] = i.value;
+      //     // });
+      //     for (let i = 0; i < this.fieldList.length; i++) {
+      //       // console.log(this.fieldList[i])
+      //       if (this.fieldList[i].type == "text") {
+      //         //文本处理
+      //         _data[this.fieldList[i].field] = this.fieldList[i].value;
+      //       } else if (this.fieldList[i].type == "image") {
+      //         //图片处理
+      //         let _imageObj = await this.convertImageUrlToBase64(
+      //           this.fieldList[i].value
+      //         );
+      //         _data[this.fieldList[i].field] = _imageObj.url;
+      //         _image[this.fieldList[i].field] = {
+      //           width: _imageObj.width,
+      //           height: _imageObj.height
+      //         };
+      //       }
+      //     }
+      //     // return this.loading = false;
+
+      //     // 图片处理
+      //     const opts = {
+      //       centered: false,
+      //       fileType: "docx",
+      //       getImage: (value, value2, value3) => {
+      //         return this.base64DataURLToArrayBuffer(value);
+      //       },
+      //       getSize: (arrayValue, value, tagName) => {
+      //         // console.log(_image)
+      //         // console.log(tagName)
+      //         let newWidth = _image[tagName].width;
+      //         let newHeight = _image[tagName].height;
+
+      //         // let newWidth = 550;
+      //         // let newHeight = 100;
+      //         return [newWidth, newHeight];
+      //       }
+      //     };
+			// 		console.log()
+      //     doc.attachModule(new ImageModule(opts));
+      //     //渲染模板
+      //     doc.setData(_data);
+      //     doc.render();
+      //     //获取渲染后的文本
+      //     const output = doc.getZip().generate({
+      //       type: "blob",
+      //       mimeType:
+      //         "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+      //       compression: "DEFLATE"
+      //     });
+
+      //     saveAs(output, `${this.downFileData.fileName}`);
+      //     // let link = document.createElement("a");
+      //     // link.download = this.uploadTemplateDocxData.name;
+      //     // link.style.display = "none";
+      //     // let blob = new Blob([output]);
+      //     // link.href = URL.createObjectURL(blob);
+      //     // document.body.appendChild(link);
+      //     // link.click();
+      //     // document.body.removeChild(link);
+      //     this.loading = false;
+      //     this.$message.success("导出成功");
+      //   } catch (error) {
+      //     console.log(error);
+      //     this.loading = false;
+      //     return this.$message.error("导出失败");
+      //   }
+      // };
+    },
     async exportDocx() {
       if (!this.uploadTemplateDocxData)
         return this.$message.error("请先上传模板文档");
@@ -309,7 +553,7 @@ export default {
           //   _data[i.field] = i.value;
           // });
           for (let i = 0; i < this.fieldList.length; i++) {
-						// console.log(this.fieldList[i])
+            // console.log(this.fieldList[i])
             if (this.fieldList[i].type == "text") {
               //文本处理
               _data[this.fieldList[i].field] = this.fieldList[i].value;
@@ -325,7 +569,7 @@ export default {
               };
             }
           }
-					// return this.loading = false;
+          // return this.loading = false;
 
           // 图片处理
           const opts = {
@@ -335,17 +579,17 @@ export default {
               return this.base64DataURLToArrayBuffer(value);
             },
             getSize: (arrayValue, value, tagName) => {
-							// console.log(_image)
-							// console.log(tagName)
+              // console.log(_image)
+              // console.log(tagName)
               let newWidth = _image[tagName].width;
               let newHeight = _image[tagName].height;
 
-							// let newWidth = 550;
+              // let newWidth = 550;
               // let newHeight = 100;
               return [newWidth, newHeight];
             }
           };
-					doc.attachModule(new ImageModule(opts));
+          doc.attachModule(new ImageModule(opts));
           //渲染模板
           doc.setData(_data);
           doc.render();
@@ -357,7 +601,7 @@ export default {
             compression: "DEFLATE"
           });
 
-					saveAs(output,`${this.uploadTemplateDocxData.name}`)
+          saveAs(output, `${this.uploadTemplateDocxData.name}`);
           // let link = document.createElement("a");
           // link.download = this.uploadTemplateDocxData.name;
           // link.style.display = "none";
@@ -416,9 +660,9 @@ export default {
         };
 
         img.onerror = error => {
-					console.log("图片转base64失败")
-					console.log(error)
-          resolve({url:"",width:0,height:0});
+          console.log("图片转base64失败");
+          console.log(error);
+          resolve({ url: "", width: 0, height: 0 });
         };
       });
     },
@@ -441,7 +685,388 @@ export default {
         bytes[i] = ascii;
       }
       return bytes.buffer;
-    }
+    },
+    async getWordContent(fileData) {
+      console.log(fileData);
+      this.wordContentLoading = true;
+      return (this.wordContentLoading = false);
+      try {
+        // console.log(a)
+        // let response = await getFile(fileData.url);
+        // if (response.data == 1) {
+        //   this.wordContentLoading = false;
+        //   return this.$message.error("文件不存在");
+        // }
+
+        // await renderAsync(response.data,this.$refs.wordAreaRef);
+        this.wordContentLoading = false;
+      } catch (error) {
+        console.log(error);
+        this.wordContentLoading = false;
+        this.$message.error("加载文件失败");
+      }
+    },
+    // 导出docx
+    async generateDocx(name, html) {
+      // 将html文件中需要用到的数据挂载到store上
+      const content = `<!DOCTYPE html>
+      <html xmlns:v='urn:schemas-microsoft-com
+      :vml'xmlns:o='urn:schemas-microsoft-com:office
+      :office'xmlns:w='urn:schemas-microsoft-com:office
+      :word'xmlns:m='http://schemas.microsoft.com/office/2004/12/omml'
+      xmlns='http://www.w3.org/TR/REC-html40'
+      xmlns='http://www.w3.org/1999/xhtml'>
+      <head>
+          <meta charset="UTF-8">
+          <meta http-equiv="X-UA-Compatible" content="IE=edge">
+          <meta name="viewport" content="width=device-width, initial-scale=1.0">
+          <title>${name}</title>
+          <style>
+						*{
+							font-family: '宋体';
+							margin:0;
+							padding:0;
+							line-height:1;
+						}
+            table {
+              border-collapse: collapse; /* 折叠边框 */
+              width: 100%;
+							font-size:10.5pt;
+            }
+            th, td {
+              border: 1px solid black; /* 线条样式 */
+              padding: 8px;
+              text-align: left;
+							font-size:10.5pt;
+            }
+						ol,ul{
+							margin:0;
+							padding:0;
+							margin-right:-1in;
+						}
+						li{
+							margin-bottom:0.1in
+							margin-right:-1in;
+						}
+						p{
+							line-height:1;
+							margin:0;
+							padding:0
+						}
+						.vue-office-docx{height:100%;overflow-y:auto}
+						.vue-office-docx .docx-wrapper>section.docx{margin-bottom:5px}
+						@media screen and (max-width: 800px){
+							.vue-office-docx .docx-wrapper{padding:10px}
+							.vue-office-docx .docx-wrapper>section.docx{padding:10px!important;width:100%!important}
+						}
+
+.docx-wrapper { background: gray; padding: 30px; padding-bottom: 0px; display: flex; flex-flow: column; align-items: center; } 
+.docx-wrapper>section.docx { background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); margin-bottom: 30px; }
+.docx { color: black; hyphens: auto; text-underline-position: from-font; }
+section.docx { box-sizing: border-box; display: flex; flex-flow: column nowrap; position: relative; overflow: hidden; }
+section.docx>article { margin-bottom: auto; z-index: 1; }
+section.docx>footer { z-index: 1; }
+.docx table { border-collapse: collapse; }
+.docx table td, .docx table th { vertical-align: top; }
+.docx p { margin: 0pt; min-height: 1em; }
+.docx span { white-space: pre-wrap; overflow-wrap: break-word; }
+.docx a { color: inherit; text-decoration: inherit; }
+.docx svg { fill: transparent; }
+.docx {
+  --docx-majorHAnsi-font: Calibri Light;
+  --docx-minorHAnsi-font: Calibri;
+  --docx-dk1-color: #000000;
+  --docx-lt1-color: #FFFFFF;
+  --docx-dk2-color: #44546A;
+  --docx-lt2-color: #E7E6E6;
+  --docx-accent1-color: #5B9BD5;
+  --docx-accent2-color: #ED7D31;
+  --docx-accent3-color: #A5A5A5;
+  --docx-accent4-color: #FFC000;
+  --docx-accent5-color: #4472C4;
+  --docx-accent6-color: #70AD47;
+  --docx-hlink-color: #0563C1;
+  --docx-folHlink-color: #954F72;
+}
+.docx span {
+  font-family: Times New Roman;
+}
+.docx p, p.docx_1 {
+  text-align: justify;
+}
+.docx p, p.docx_1 span {
+  font-family: var(--docx-minorHAnsi-font);
+  min-height: 10.50pt;
+  font-size: 10.50pt;
+}
+.docx table, table.docx_2 td {
+  padding-top: 0.00pt;
+  padding-left: 5.40pt;
+  padding-bottom: 0.00pt;
+  padding-right: 5.40pt;
+}
+table.docx_3 p {
+  text-align: justify;
+}
+table.docx_3 td {
+  border-top: 0.50pt solid black;
+  border-left: 0.50pt solid black;
+  border-bottom: 0.50pt solid black;
+  border-right: 0.50pt solid black;
+  padding-top: 0.00pt;
+  padding-left: 5.40pt;
+  padding-bottom: 0.00pt;
+  padding-right: 5.40pt;
+}
+	p.docx-num-2-0:before {
+  content: ""counter(docx-num-2-0, decimal)"、";
+  counter-increment: docx-num-2-0;
+}
+p.docx-num-2-0 {
+  display: list-item;
+  list-style-position: inside;
+  list-style-type: none;
+}
+p.docx-num-1-0:before {
+  content: ""counter(docx-num-1-0, decimal)"、";
+  counter-increment: docx-num-1-0;
+}
+p.docx-num-1-0 {
+  display: list-item;
+  list-style-position: inside;
+  list-style-type: none;
+}
+.docx-wrapper {
+  counter-reset: docx-num-2-0 4 docx-num-1-0 0;
+}
+
+
+
+          </style>
+      </head>
+      <body>
+      ${html}
+      </body>
+      </html>`;
+      // console.log(content)
+      // return console.log(content)
+      // debugger
+      let blob = htmlDocx.asBlob(content);
+
+      // const uploadFile = new File([blob], `${name}.docx`, {
+      //   type:
+      //     "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
+      // });
+      saveAs(blob, `${name}.docx`);
+      return true;
+      // this.beforeUploadHtml(uploadFile);
+    },
+    async getGenerateDocxHtml(html) {
+      const content = `<!DOCTYPE html>
+      <html xmlns:v='urn:schemas-microsoft-com
+      :vml'xmlns:o='urn:schemas-microsoft-com:office
+      :office'xmlns:w='urn:schemas-microsoft-com:office
+      :word'xmlns:m='http://schemas.microsoft.com/office/2004/12/omml'
+      xmlns='http://www.w3.org/TR/REC-html40'
+      xmlns='http://www.w3.org/1999/xhtml'>
+      <head>
+          <meta charset="UTF-8">
+          <meta http-equiv="X-UA-Compatible" content="IE=edge">
+          <meta name="viewport" content="width=device-width, initial-scale=1.0">
+          <title>DOCX</title>
+          <style>
+						*{
+							font-family: '宋体';
+							margin:0;
+							padding:0;
+							line-height:1;
+						}
+            table {
+              border-collapse: collapse; /* 折叠边框 */
+              width: 100%;
+							font-size:10.5pt;
+            }
+            th, td {
+              border: 1px solid black; /* 线条样式 */
+              padding: 8px;
+              text-align: left;
+							font-size:10.5pt;
+            }
+						ol,ul{
+							margin:0;
+							padding:0;
+							margin-right:-1in;
+						}
+						li{
+							margin-bottom:0.1in
+							margin-right:-1in;
+						}
+						p{
+							line-height:1;
+							margin:0;
+							padding:0
+						}
+						.vue-office-docx{height:100%;overflow-y:auto}
+						.vue-office-docx .docx-wrapper>section.docx{margin-bottom:5px}
+						@media screen and (max-width: 800px){
+							.vue-office-docx .docx-wrapper{padding:10px}
+							.vue-office-docx .docx-wrapper>section.docx{padding:10px!important;width:100%!important}
+						}
+
+.docx-wrapper { background: gray; padding: 30px; padding-bottom: 0px; display: flex; flex-flow: column; align-items: center; } 
+.docx-wrapper>section.docx { background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); margin-bottom: 30px; }
+.docx { color: black; hyphens: auto; text-underline-position: from-font; }
+section.docx { box-sizing: border-box; display: flex; flex-flow: column nowrap; position: relative; overflow: hidden; }
+section.docx>article { margin-bottom: auto; z-index: 1; }
+section.docx>footer { z-index: 1; }
+.docx table { border-collapse: collapse; }
+.docx table td, .docx table th { vertical-align: top; }
+.docx p { margin: 0pt; min-height: 1em; }
+.docx span { white-space: pre-wrap; overflow-wrap: break-word; }
+.docx a { color: inherit; text-decoration: inherit; }
+.docx svg { fill: transparent; }
+.docx {
+  --docx-majorHAnsi-font: Calibri Light;
+  --docx-minorHAnsi-font: Calibri;
+  --docx-dk1-color: #000000;
+  --docx-lt1-color: #FFFFFF;
+  --docx-dk2-color: #44546A;
+  --docx-lt2-color: #E7E6E6;
+  --docx-accent1-color: #5B9BD5;
+  --docx-accent2-color: #ED7D31;
+  --docx-accent3-color: #A5A5A5;
+  --docx-accent4-color: #FFC000;
+  --docx-accent5-color: #4472C4;
+  --docx-accent6-color: #70AD47;
+  --docx-hlink-color: #0563C1;
+  --docx-folHlink-color: #954F72;
+}
+.docx span {
+  font-family: Times New Roman;
+}
+.docx p, p.docx_1 {
+  text-align: justify;
+}
+.docx p, p.docx_1 span {
+  font-family: var(--docx-minorHAnsi-font);
+  min-height: 10.50pt;
+  font-size: 10.50pt;
+}
+.docx table, table.docx_2 td {
+  padding-top: 0.00pt;
+  padding-left: 5.40pt;
+  padding-bottom: 0.00pt;
+  padding-right: 5.40pt;
+}
+table.docx_3 p {
+  text-align: justify;
+}
+table.docx_3 td {
+  border-top: 0.50pt solid black;
+  border-left: 0.50pt solid black;
+  border-bottom: 0.50pt solid black;
+  border-right: 0.50pt solid black;
+  padding-top: 0.00pt;
+  padding-left: 5.40pt;
+  padding-bottom: 0.00pt;
+  padding-right: 5.40pt;
+}
+	p.docx-num-2-0:before {
+  content: ""counter(docx-num-2-0, decimal)"、";
+  counter-increment: docx-num-2-0;
+}
+p.docx-num-2-0 {
+  display: list-item;
+  list-style-position: inside;
+  list-style-type: none;
+}
+p.docx-num-1-0:before {
+  content: ""counter(docx-num-1-0, decimal)"、";
+  counter-increment: docx-num-1-0;
+}
+p.docx-num-1-0 {
+  display: list-item;
+  list-style-position: inside;
+  list-style-type: none;
+}
+.docx-wrapper {
+  counter-reset: docx-num-2-0 4 docx-num-1-0 0;
+}
+</style>
+</head>
+<body>
+${html}
+</body>
+</html>`;
+// console.log(content)
+// return console.log(content)
+// debugger
+let blob = htmlDocx.asBlob(content);
+return blob;
+    },
+		uploadFile(file) {
+      return new Promise((resolve,reject) => {
+				var credentials = {
+        accessKeyId: "AKIATLPEDU37QV5CHLMH",
+        secretAccessKey: "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"
+      }; //秘钥形式的登录上传
+      window.AWS.config.update(credentials);
+      window.AWS.config.region = "cn-northwest-1"; //设置区域
+
+      var bucket = new window.AWS.S3({ params: { Bucket: "ccrb" } }); //选择桶
+      var _this = this;
+
+      if (file) {
+        // this.loading = true;
+        var params = {
+          Key:
+            file.name.split(".")[0] +
+            new Date().getTime() +
+            "." +
+            file.name.split(".")[file.name.split(".").length - 1],
+          ContentType: file.type,
+          Body: file,
+          "Access-Control-Allow-Credentials": "*",
+          ACL: "public-read"
+        }; //key可以设置为桶的相抵路径,Body为文件, ACL最好要设置
+        var options = {
+          partSize: 2048 * 1024 * 1024,
+          queueSize: 2,
+          leavePartsOnError: true
+        };
+        bucket
+          .upload(params, options)
+          .on("httpUploadProgress", function(evt) {
+            //这里可以写进度条
+            _this.progressData.value = parseInt((evt.loaded * 100) / evt.total);
+            // console.log("Uploaded : " + parseInt((evt.loaded * 80) / evt.total) + '%');
+          })
+          .send(function(err, data) {
+            if (err) {
+              _this.$message.error("上传失败");
+            } else {
+							resolve(data.Location)
+            }
+          });
+      }
+			})
+    },
+		changeDownFileData(data){
+			let _data = JSON.parse(JSON.stringify(data))
+			delete _data.txt;
+
+			let params = [{
+				cid:this.courseId,
+				ncover:JSON.stringify(_data),
+			}]
+			this.$emit("changeCover",JSON.stringify(_data))
+			this.ajax.post(this.$store.state.api+"update_testCourseCoverById",params).then(res=>{
+				console.log(res.data)
+			})
+		},
+		getTxtContent(txt){
+			this.downFileData.txt = txt
+		},
   }
 };
 </script>
@@ -493,13 +1118,16 @@ export default {
 }
 
 .b_left {
-	flex: 1;
-	height: 100%;
+  width: 630pt;
+  height: 100%;
+  border: none;
+  outline: none;
 }
 
 .b_right {
-	min-width: 700px;
-	max-width: 700px;
+  flex: 1;
+  /* min-width: 700px;
+  max-width: 700px; */
   height: 100%;
 }
 
@@ -522,8 +1150,8 @@ export default {
   margin-bottom: 10px;
 }
 
-.d_b_step>h3{
-	margin-top: 20px;
+.d_b_step > h3 {
+  margin-top: 20px;
 }
 
 .d_b_step > p {
@@ -603,25 +1231,24 @@ export default {
   color: #e60012;
 }
 
-.d_b_s_imgList{
-	margin-top: 10px;
+.d_b_s_imgList {
+  margin-top: 10px;
 }
 
-.d_b_s_imgList>img{
-	width: 100%;
+.d_b_s_imgList > img {
+  width: 100%;
 }
 
-.foldMenu{
-	width: 100%;
-	display: flex;
-	justify-content: flex-end;
-	margin: 10px 0;
-	
+.foldMenu {
+  width: 100%;
+  display: flex;
+  justify-content: flex-end;
+  margin: 10px 0;
 }
 
-.foldMenu>span{
-	cursor: pointer;
-	color: #409EFF;
-	font-size: 16px;
+.foldMenu > span {
+  cursor: pointer;
+  color: #409eff;
+  font-size: 16px;
 }
 </style>

+ 6 - 3
src/components/pages/test/check/index.vue

@@ -897,7 +897,7 @@
     <wVideo :dialogVisibleVideo.sync="dialogVisibleVideo" :url="wurl"></wVideo>
     <wOffice :dialogVisibleOffice.sync="dialogVisibleOffice" :url="wurl"></wOffice>
 
-		<docxTemplateDialog ref="docxTemplateDialogRef"/>
+		<docxTemplateDialog ref="docxTemplateDialogRef" @changeCover="changeCover"/>
   </div>
 </template>
 
@@ -2380,9 +2380,12 @@ export default {
         });
     },
 		setWordTemplate(item){
-			this.$refs.docxTemplateDialogRef.open({fileData:JSON.parse(this.testJson.cover),formData:item})//这里可以传数据
+			this.$refs.docxTemplateDialogRef.open({fileData:JSON.parse(this.testJson.cover),courseId:this.testJson.courseId,formData:item})//这里可以传数据
 			// console.log(item)
-		}
+		},
+		changeCover(data){
+			this.testJson.cover = data
+		},
   },
   beforeDestroy() {
     document.getElementsByTagName('html')[0].style.overflow = '';

+ 95 - 0
src/components/pages/test/check/txtHtmlView.vue

@@ -0,0 +1,95 @@
+<template>
+  <div class="txtView" ref="txtViewRef" v-html="content" v-loading="loading">
+		
+	</div>
+</template>
+
+<script>
+import "../../../../common/aws-sdk-2.235.1.min.js";
+
+const getFile = url => {
+  return new Promise((resolve, reject) => {
+    var credentials = {
+      accessKeyId: "AKIATLPEDU37QV5CHLMH",
+      secretAccessKey: "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"
+    }; //秘钥形式的登录上传
+    window.AWS.config.update(credentials);
+    window.AWS.config.region = "cn-northwest-1"; //设置区域
+    let url2 = url;
+    let _url2 = "";
+    if (
+      url2.indexOf("https://view.officeapps.live.com/op/view.aspx?src=") != -1
+    ) {
+      _url2 = url2.split(
+        "https://view.officeapps.live.com/op/view.aspx?src="
+      )[1];
+    } else {
+      _url2 = url2;
+    }
+    var s3 = new window.AWS.S3({ params: { Bucket: "ccrb" } });
+    let name = decodeURIComponent(
+      _url2.split("https://ccrb.s3.cn-northwest-1.amazonaws.com.cn/")[1]
+    );
+    var params = {
+      Bucket: "ccrb",
+      Key: name
+    };
+    s3.getObject(params, function(err, data) {
+      if (err) {
+        console.log(err, err.stack);
+        resolve({ data: 1 });
+      } else {
+        const fileContent = data.Body.toString("utf-8");
+        resolve({ data: fileContent });
+      } // sxuccessful response
+    });
+    // axios({
+  });
+};
+export default {
+  props: {
+    url: {
+      type: String,
+      default: ""
+    },
+  },
+	data(){
+		return{
+			content:"",
+			loading:""
+		}
+	},
+	methods: {
+		getTxtContent() {
+			if(!this.url)return;
+			this.loading = true;
+			getFile(this.url).then(res=>{
+				this.loading = false;
+				this.content = res.data;
+				this.$emit("getTxtContent",this.content)
+			})
+		},
+	},
+	watch:{
+		url(newVal,oldVal){
+			if(newVal!==oldVal){
+				this.getTxtContent();
+			}
+		}
+	},
+	mounted(){
+		this.getTxtContent();
+	}
+};
+</script>
+
+<style scoped>
+.txtView{
+	width: 100%;
+	height: 100%;
+	box-sizing: border-box;
+	padding: 0px 0px;
+	margin: 0;
+	overflow: auto;
+}
+</style>