|
@@ -471,6 +471,11 @@
|
|
|
|
|
|
<div v-if="item1.type == 15" class="chapter_upload_l_i15" style="margin-left: 1px">
|
|
|
</div>
|
|
|
+ <div
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ class="chapter_upload_l_i8"
|
|
|
+ style="margin-left: 1px"
|
|
|
+ ></div>
|
|
|
</div>
|
|
|
<div class="chapter_upload_n" :class="{dataTips: !item1.fileid}">
|
|
|
|
|
@@ -498,6 +503,9 @@
|
|
|
<div v-if="item1.type == 14" class="chapter_upload_box" @click="
|
|
|
openUpdateSource(0, index1)
|
|
|
" >{{ item1.title ? item1.title : '链接' }}</div>
|
|
|
+ <div v-if="item1.type == 17" class="chapter_upload_box" @click="
|
|
|
+ changeHTmlPage(0, index1)
|
|
|
+ " >{{ item1.title ? item1.title : '代码上传' }}</div>
|
|
|
<div v-if="item1.type == 15" class="chapter_upload_box" @click="
|
|
|
openUpdateSource(0, index1)
|
|
|
" >{{ item1.title ? item1.title : 'Ai应用' }}</div>
|
|
@@ -564,6 +572,13 @@
|
|
|
">
|
|
|
<div></div>
|
|
|
</div>
|
|
|
+ <div
|
|
|
+ class="chapter_upload_ic_edit"
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ @click="changeHTmlPage(0, index1)"
|
|
|
+ >
|
|
|
+ <div></div>
|
|
|
+ </div>
|
|
|
<div class="chapter_upload_ic_r" @click.stop="
|
|
|
deleteChapterData(
|
|
|
$event,
|
|
@@ -625,6 +640,12 @@
|
|
|
>
|
|
|
代码编辑器
|
|
|
</button>
|
|
|
+ <button
|
|
|
+ class="c_pub_button_add pub_btn_add_img"
|
|
|
+ @click="uploadZIPFile(0)"
|
|
|
+ >
|
|
|
+ 代码上传
|
|
|
+ </button>
|
|
|
</div>
|
|
|
<div v-if="
|
|
|
unitJson[unitIndex].chapterInfo[0].taskJson[
|
|
@@ -1118,6 +1139,22 @@
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
" readonly="true" @click="selectLine(index1)" />
|
|
|
+ <input
|
|
|
+ :placeholder="
|
|
|
+ item1.title ? item1.title : '代码上传'
|
|
|
+ "
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ style="
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ width: 80%;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ "
|
|
|
+ readonly="true"
|
|
|
+ @click="changeHTmlPage(0, index1)"
|
|
|
+ />
|
|
|
<input :placeholder="item1.title ? item1.title : '链接'
|
|
|
" v-if="item1.type == 14" style="
|
|
|
border: none;
|
|
@@ -2964,6 +3001,11 @@
|
|
|
class="chapter_upload_l_i15"
|
|
|
style="margin-left: 1px"
|
|
|
></div>
|
|
|
+ <div
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ class="chapter_upload_l_i8"
|
|
|
+ style="margin-left: 1px"
|
|
|
+ ></div>
|
|
|
</div>
|
|
|
<div class="chapter_upload_n">
|
|
|
<input
|
|
@@ -3062,6 +3104,23 @@
|
|
|
readonly="true"
|
|
|
@click="selectLine(0, index1)"
|
|
|
/>
|
|
|
+ <input
|
|
|
+ :placeholder="
|
|
|
+ item1.title ? item1.title : '代码上传'
|
|
|
+ "
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ style="
|
|
|
+ border: none;
|
|
|
+ outline: none;
|
|
|
+ width: 80%;
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ "
|
|
|
+ readonly="true"
|
|
|
+ @click="changeHTmlPage(0, index1)"
|
|
|
+ />
|
|
|
+
|
|
|
</div>
|
|
|
<div class="chapter_upload_ic">
|
|
|
<div
|
|
@@ -3147,6 +3206,13 @@
|
|
|
>
|
|
|
<div></div>
|
|
|
</div>
|
|
|
+ <div
|
|
|
+ class="chapter_upload_ic_edit"
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ @click="changeHTmlPage(0, index1)"
|
|
|
+ >
|
|
|
+ <div></div>
|
|
|
+ </div>
|
|
|
<div
|
|
|
class="chapter_upload_ic_r"
|
|
|
@click.stop="
|
|
@@ -3460,6 +3526,13 @@
|
|
|
">
|
|
|
<div></div>
|
|
|
</div>
|
|
|
+ <div
|
|
|
+ class="chapter_upload_ic_edit"
|
|
|
+ v-if="item1.type == 17"
|
|
|
+ @click="changeHTmlPage(0, index1)"
|
|
|
+ >
|
|
|
+ <div></div>
|
|
|
+ </div>
|
|
|
<div class="chapter_upload_ic_r" @click.stop="
|
|
|
deleteChapterData(
|
|
|
$event,
|
|
@@ -7057,6 +7130,7 @@
|
|
|
<wOffice :dialogVisibleOffice.sync="dialogVisibleOffice" :url="wurl" ></wOffice>
|
|
|
<appDialog ref="appDialog" @success="selectAppSuccess"></appDialog>
|
|
|
<CodeEditor ref="CodeEditorRef" @success="addHtmlSuccess"></CodeEditor>
|
|
|
+ <selectHtmlPageDialog ref="selectHtmlPageDialogRef" @success="selectHtmlPageSuccess"/>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -7100,6 +7174,7 @@ let convertApi = ConvertApi.auth('secret_U1EO5rhgMCnoBnBT')
|
|
|
import appDialog from '../components/appDialog.vue'
|
|
|
import { myMixin } from "@/mixins/mixin.js"
|
|
|
import CodeEditor from "../components/CodeEditor";
|
|
|
+import { uploadFileMixin } from "../../tools/uploadFileMixin.js";
|
|
|
|
|
|
var OpenCC = require("opencc-js");
|
|
|
let converter = OpenCC.Converter({
|
|
@@ -7112,6 +7187,9 @@ let converter2 = OpenCC.Converter({
|
|
|
to:'hk'
|
|
|
})
|
|
|
|
|
|
+
|
|
|
+import selectHtmlPageDialog from '../dialog/selectHtmlPageDialog.vue'
|
|
|
+
|
|
|
const getFile = (url) => {
|
|
|
return new Promise((resolve, reject) => {
|
|
|
var credentials = {
|
|
@@ -7151,7 +7229,7 @@ const getFile = (url) => {
|
|
|
};
|
|
|
|
|
|
export default {
|
|
|
- mixins: [ myMixin ],
|
|
|
+ mixins: [ myMixin,uploadFileMixin],
|
|
|
components: {
|
|
|
CodeEditor,
|
|
|
EditorBar,
|
|
@@ -7179,6 +7257,7 @@ export default {
|
|
|
MindTask,
|
|
|
recordV,
|
|
|
appDialog,
|
|
|
+ selectHtmlPageDialog
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
@@ -7658,7 +7737,8 @@ export default {
|
|
|
heightPx: '100%',
|
|
|
newWidth: 350,
|
|
|
unitLoading: false,
|
|
|
- optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
|
|
+ optionTypeList:['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'],
|
|
|
+ changeId:""
|
|
|
|
|
|
};
|
|
|
},
|
|
@@ -25527,7 +25607,195 @@ ${msg}
|
|
|
}
|
|
|
this.imgChange1(null, null, 8, this.lineCount);
|
|
|
this.dialogVisible7 = false;
|
|
|
- }
|
|
|
+ },
|
|
|
+ // zip压缩文件上传
|
|
|
+ uploadZIPFile(i){
|
|
|
+ this.lineCount = i;
|
|
|
+ // 只支持上传zip文件
|
|
|
+ let input = document.createElement('input');
|
|
|
+ input.type = 'file';
|
|
|
+ input.accept = '.zip';
|
|
|
+ input.style.display = 'none';
|
|
|
+ // 只允许上传一个文件
|
|
|
+ input.multiple = false;
|
|
|
+ input.onchange = async (e) => {
|
|
|
+ let file = e.target.files[0];
|
|
|
+ if (!file) return;
|
|
|
+ if (file.type !== 'application/zip' && !file.name.endsWith('.zip')) {
|
|
|
+ this.$message.error('只支持上传zip文件');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ const zip = new JSZip();
|
|
|
+ const content = await zip.loadAsync(file);
|
|
|
+ let _fileStructure = this.buildFileStructure(file,content);
|
|
|
+ let _time = new Date().getTime();
|
|
|
+ let _resultList = await this.uploadZipFileFn(_fileStructure.files,`${_time}_${_fileStructure.folderName}`);
|
|
|
+ this.changeId = "";
|
|
|
+ this.$refs.selectHtmlPageDialogRef.open(_resultList);
|
|
|
+
|
|
|
+ }catch(e){
|
|
|
+ console.log(e)
|
|
|
+ this.$message.error("解析zip文件失败")
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+ document.body.appendChild(input);
|
|
|
+ input.click();
|
|
|
+ setTimeout(() => {
|
|
|
+ document.body.removeChild(input);
|
|
|
+ }, 1000);
|
|
|
+ },
|
|
|
+ // 构建文件结构树
|
|
|
+ buildFileStructure(file,zip) {
|
|
|
+ const root = {
|
|
|
+ folderName: file.name.replace(/\.[^/.]+$/, ""), // 移除扩展名
|
|
|
+ files: []
|
|
|
+ };
|
|
|
+
|
|
|
+ // 遍历ZIP文件中的所有文件/文件夹
|
|
|
+ zip.forEach((relativePath, file) => {
|
|
|
+ if (file.dir) return; // 跳过目录
|
|
|
+
|
|
|
+ const parts = relativePath.split('/');
|
|
|
+ let currentLevel = root.files;
|
|
|
+
|
|
|
+ for (let i = 0; i < parts.length; i++) {
|
|
|
+ const part = parts[i];
|
|
|
+ const isLast = i === parts.length - 1;
|
|
|
+
|
|
|
+ if (isLast) {
|
|
|
+ // 添加文件
|
|
|
+ currentLevel.push({fileName:part,file:file});
|
|
|
+ } else {
|
|
|
+ // 查找或创建文件夹
|
|
|
+ let folder = currentLevel.find(item =>
|
|
|
+ typeof item === 'object' && item.folderName === part
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!folder) {
|
|
|
+ folder = {
|
|
|
+ folderName: part,
|
|
|
+ files: []
|
|
|
+ };
|
|
|
+ currentLevel.push(folder);
|
|
|
+ }
|
|
|
+
|
|
|
+ currentLevel = folder.files;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return root;
|
|
|
+ },
|
|
|
+ //按路径上传文件
|
|
|
+ async uploadZipFileFn(fileList,path){
|
|
|
+ return new Promise(async (resolve)=>{
|
|
|
+ let _copyFileList = fileList;
|
|
|
+
|
|
|
+ let promise = [];
|
|
|
+ for(let i = 0; i < _copyFileList.length; i++){
|
|
|
+ if(_copyFileList[i].folderName){
|
|
|
+ let _path = `${path}/${_copyFileList[i].folderName}`;
|
|
|
+ promise.push(this.uploadZipFileFn(_copyFileList[i].files,_path).then(res=>{
|
|
|
+ _copyFileList[i].files = res;
|
|
|
+ }))
|
|
|
+ }else if(_copyFileList[i].fileName){
|
|
|
+ // 将 ZIP 条目转换为文件对象
|
|
|
+ const blob = await _copyFileList[i].file.async('blob');
|
|
|
+ // 根据文件名设置type
|
|
|
+ let type = 'text/html';
|
|
|
+ if (_copyFileList[i].fileName.endsWith('.js')) {
|
|
|
+ type = 'application/javascript';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.css')) {
|
|
|
+ type = 'text/css';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.json')) {
|
|
|
+ type = 'application/json';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.png')) {
|
|
|
+ type = 'image/png';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.jpg') || _copyFileList[i].fileName.endsWith('.jpeg')) {
|
|
|
+ type = 'image/jpeg';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.gif')) {
|
|
|
+ type = 'image/gif';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.svg')) {
|
|
|
+ type = 'image/svg+xml';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.html') || _copyFileList[i].fileName.endsWith('.htm')) {
|
|
|
+ type = 'text/html';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.txt')) {
|
|
|
+ type = 'text/plain';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.pdf')) {
|
|
|
+ type = 'application/pdf';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.mp3')) {
|
|
|
+ type = 'audio/mpeg';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.mp4')) {
|
|
|
+ type = 'video/mp4';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.zip')) {
|
|
|
+ type = 'application/zip';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.xml')) {
|
|
|
+ type = 'application/xml';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.csv')) {
|
|
|
+ type = 'text/csv';
|
|
|
+ } else if (_copyFileList[i].fileName.endsWith('.md')) {
|
|
|
+ type = 'text/markdown';
|
|
|
+ }
|
|
|
+ let _file = new File([blob], _copyFileList[i].fileName, {type: type, lastModified: new Date().getTime()});
|
|
|
+ promise.push(this.awsupload({file:_file,path:`${path}/${_copyFileList[i].fileName}`}).then(res=>{
|
|
|
+ delete _copyFileList[i].file;
|
|
|
+ _copyFileList[i].url = decodeURIComponent(res.Location);
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Promise.all(promise).then(res=>{
|
|
|
+ resolve(_copyFileList);
|
|
|
+ })
|
|
|
+ })
|
|
|
+ },
|
|
|
+ selectHtmlPageSuccess(data){
|
|
|
+ let _selectFile = data.find(i=>i.isSelect==="1");
|
|
|
+ if(!_selectFile){
|
|
|
+ this.changeId = "";
|
|
|
+ return this.$message.info("未选择主页面")
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("_selectFile",_selectFile)
|
|
|
+ let _index = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
|
|
|
+ 0
|
|
|
+ ].chapterData.findIndex(i => i.type == 17 && i.id == this.changeId);
|
|
|
+ if (_index != -1) {
|
|
|
+ console.log("_index",_index)
|
|
|
+ this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
|
|
|
+ 0
|
|
|
+ ].chapterData[_index] = {
|
|
|
+ name: _selectFile.fileName,
|
|
|
+ title: _selectFile.fileName,
|
|
|
+ id:this.changeId,
|
|
|
+ url: _selectFile.url,
|
|
|
+ fileList:data,
|
|
|
+ type: 17
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
|
|
|
+ 0
|
|
|
+ ].chapterData.push({
|
|
|
+ name: _selectFile.fileName,
|
|
|
+ title: _selectFile.fileName,
|
|
|
+ id:new Date().getTime(),
|
|
|
+ url: _selectFile.url,
|
|
|
+ fileList:data,
|
|
|
+ type: 17
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.changeId = "";
|
|
|
+ this.$forceUpdate();
|
|
|
+ this.$refs.selectHtmlPageDialogRef.close();
|
|
|
+ },
|
|
|
+ changeHTmlPage(itemTaskIndex,i){
|
|
|
+ let _data = this.unitJson[this.unitIndex].chapterInfo[0].taskJson[
|
|
|
+ itemTaskIndex
|
|
|
+ ].chapterData[i];
|
|
|
+ this.changeId = _data.id;
|
|
|
+ this.$refs.selectHtmlPageDialogRef.open(_data.fileList);
|
|
|
+ }
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
// clearTimeout(this.timer);
|