|
|
|
@ -60,17 +60,82 @@ |
|
|
|
<el-button v-hasPermi="['system:tupupoint:lock']" v-if="userRemark=='解锁'" type="danger" plain style="float: left" size="mini" @click="lockall"> |
|
|
|
一键锁定 |
|
|
|
</el-button> |
|
|
|
<h3>选择并上传文件夹</h3> |
|
|
|
<input |
|
|
|
type="file" |
|
|
|
ref="folderInput" |
|
|
|
webkitdirectory |
|
|
|
directory |
|
|
|
multiple |
|
|
|
@change="handleFolderSelect" |
|
|
|
/> |
|
|
|
<button @click="uploadFolder">上传文件夹</button> |
|
|
|
<!-- <input--> |
|
|
|
<!-- type="file"--> |
|
|
|
<!-- ref="folderInput"--> |
|
|
|
<!-- webkitdirectory--> |
|
|
|
<!-- directory--> |
|
|
|
<!-- multiple--> |
|
|
|
<!-- @change="handleFolderSelect"--> |
|
|
|
<!-- />--> |
|
|
|
<!-- <button @click="uploadFolder">上传文件夹</button>--> |
|
|
|
<el-button type="primary" size="mini" @click="dialogVisible = true"> |
|
|
|
选择并上传文件夹 |
|
|
|
</el-button> |
|
|
|
|
|
|
|
<!-- 文件夹上传弹窗 --> |
|
|
|
<el-dialog |
|
|
|
title="选择文件夹" |
|
|
|
:visible.sync="dialogVisible" |
|
|
|
width="50%" |
|
|
|
:close-on-click-modal="false" |
|
|
|
:destroy-on-close="true" |
|
|
|
> |
|
|
|
<div class="folder-upload-container"> |
|
|
|
<!-- 隐藏的原生 input --> |
|
|
|
<input |
|
|
|
type="file" |
|
|
|
ref="folderInput" |
|
|
|
webkitdirectory |
|
|
|
directory |
|
|
|
multiple |
|
|
|
@change="handleFolderSelect" |
|
|
|
style="display: none" |
|
|
|
/> |
|
|
|
|
|
|
|
<!-- 美观的上传区域 --> |
|
|
|
<el-card shadow="hover" class="upload-card"> |
|
|
|
<div |
|
|
|
class="upload-area" |
|
|
|
@click="triggerFileInput" |
|
|
|
v-if="selectedFiles.length === 0" |
|
|
|
> |
|
|
|
<i class="el-icon-folder-opened upload-icon"></i> |
|
|
|
<p class="tip">点击选择文件夹,或拖拽文件夹到此处</p> |
|
|
|
<p class="sub-tip">支持文件夹上传(Chrome/Edge/Firefox)</p> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 已选择文件列表 --> |
|
|
|
<div v-else> |
|
|
|
<p class="selected-title">已选择 {{ selectedFiles.length }} 个文件</p> |
|
|
|
<el-scrollbar style="max-height: 300px"> |
|
|
|
<div class="file-list"> |
|
|
|
<div |
|
|
|
class="file-item" |
|
|
|
v-for="(file, index) in selectedFiles" |
|
|
|
:key="index" |
|
|
|
> |
|
|
|
<i class="el-icon-document"></i> |
|
|
|
<span class="file-name">{{ file.webkitRelativePath }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-scrollbar> |
|
|
|
</div> |
|
|
|
</el-card> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 操作按钮 --> |
|
|
|
<div slot="footer" class="dialog-footer"> |
|
|
|
<el-button @click="dialogVisible = false">取消</el-button> |
|
|
|
<el-button |
|
|
|
type="primary" |
|
|
|
@click="uploadFolder" |
|
|
|
:disabled="selectedFiles.length === 0" |
|
|
|
> |
|
|
|
开始上传 |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
</el-dialog> |
|
|
|
<!-- <el-button type="danger" plain style="float: left" size="mini" @click="opendeletOly=true">--> |
|
|
|
<!-- 删除指定实体--> |
|
|
|
<!-- </el-button>--> |
|
|
|
@ -315,7 +380,7 @@ |
|
|
|
<i class="el-icon-upload"></i> |
|
|
|
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> |
|
|
|
<div class="el-upload__tip text-center" slot="tip"> |
|
|
|
<span>仅允许导入doc、docx格式文件。</span> |
|
|
|
<span>仅允许导入docx格式文件。</span> |
|
|
|
<span>{{ upload.tip }}</span> |
|
|
|
</div> |
|
|
|
</el-upload> |
|
|
|
@ -509,7 +574,7 @@ import { |
|
|
|
getAllTxtListP, |
|
|
|
insertNode, |
|
|
|
reset, |
|
|
|
getAllTxtListByGroupAndLevel, lockAll, selectRemark |
|
|
|
getAllTxtListByGroupAndLevel, lockAll, selectRemark, uploadFolder |
|
|
|
} from "../../../api/system/file"; |
|
|
|
import {updateTemplate} from "../../../api/system/titleTemplate"; |
|
|
|
|
|
|
|
@ -882,43 +947,61 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
// 触发隐藏的文件输入框 |
|
|
|
triggerFileInput() { |
|
|
|
this.$refs.folderInput.click(); |
|
|
|
}, |
|
|
|
|
|
|
|
// 处理文件夹选择(变量名不变) |
|
|
|
handleFolderSelect(e) { |
|
|
|
const files = e.target.files; // FileList |
|
|
|
const files = e.target.files; |
|
|
|
this.selectedFiles = Array.from(files); |
|
|
|
console.log('选中的文件:', this.selectedFiles); |
|
|
|
this.$message({ |
|
|
|
message: `已选择 ${files.length} 个文件`, |
|
|
|
type: 'success' |
|
|
|
}); |
|
|
|
}, |
|
|
|
|
|
|
|
// 上传文件夹(变量名不变) |
|
|
|
async uploadFolder() { |
|
|
|
if (this.selectedFiles.length === 0) { |
|
|
|
alert("请先选择一个文件夹"); |
|
|
|
this.$message.warning('请先选择一个文件夹'); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const formData = new FormData(); |
|
|
|
this.selectedFiles.forEach(file => { |
|
|
|
// 使用 webkitRelativePath 保留文件夹结构 |
|
|
|
formData.append('files', file, file.webkitRelativePath); |
|
|
|
}); |
|
|
|
|
|
|
|
try { |
|
|
|
const response = await fetch('http://localhost:10031/api/upload-folder', { |
|
|
|
method: 'POST', |
|
|
|
body: formData |
|
|
|
}); |
|
|
|
const response = await uploadFolder(formData); |
|
|
|
|
|
|
|
if (response.ok) { |
|
|
|
const result = await response.json(); |
|
|
|
console.log('上传成功:', result); |
|
|
|
alert('文件夹上传成功!'); |
|
|
|
// ✅ 正确:检查后端返回的业务 code |
|
|
|
if (response.code === 200) { |
|
|
|
this.$message.success(response.data.message || '上传成功!'); |
|
|
|
this.dialogVisible = false; |
|
|
|
this.selectedFiles = []; |
|
|
|
} else { |
|
|
|
console.error('上传失败'); |
|
|
|
alert('上传失败'); |
|
|
|
this.$message.error(response.data.message || '上传失败'); |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('请求出错:', error); |
|
|
|
alert('网络错误'); |
|
|
|
console.error('上传出错:', error); |
|
|
|
|
|
|
|
// 更详细的错误提示 |
|
|
|
if (error.response) { |
|
|
|
// 请求发出去了,但返回非 2xx |
|
|
|
this.$message.error(`服务器错误: ${error.response.status}`); |
|
|
|
} else if (error.request) { |
|
|
|
// 请求发不出去(如网络问题、服务未启动) |
|
|
|
this.$message.error('网络错误'); |
|
|
|
} else { |
|
|
|
this.$message.error('请求异常'); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
lockall(){ |
|
|
|
lockAll().then((res)=>{ |
|
|
|
|
|
|
|
@ -1884,5 +1967,72 @@ export default { |
|
|
|
font-size: 1vw !important; |
|
|
|
color: #67C23A; |
|
|
|
} |
|
|
|
.upload-card { |
|
|
|
border: 1px dashed #d9d9d9; |
|
|
|
border-radius: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.upload-area { |
|
|
|
text-align: center; |
|
|
|
padding: 40px 20px; |
|
|
|
cursor: pointer; |
|
|
|
color: #606266; |
|
|
|
} |
|
|
|
|
|
|
|
.upload-area:hover { |
|
|
|
background: #f5f7fa; |
|
|
|
} |
|
|
|
|
|
|
|
.upload-icon { |
|
|
|
font-size: 48px; |
|
|
|
color: #409eff; |
|
|
|
margin-bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.tip { |
|
|
|
font-size: 16px; |
|
|
|
margin: 0; |
|
|
|
color: #303133; |
|
|
|
} |
|
|
|
|
|
|
|
.sub-tip { |
|
|
|
font-size: 13px; |
|
|
|
color: #909399; |
|
|
|
margin-top: 5px; |
|
|
|
} |
|
|
|
|
|
|
|
.selected-title { |
|
|
|
font-size: 14px; |
|
|
|
color: #303133; |
|
|
|
margin-bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.file-list { |
|
|
|
padding: 0; |
|
|
|
list-style: none; |
|
|
|
} |
|
|
|
|
|
|
|
.file-item { |
|
|
|
display: flex; |
|
|
|
align-items: center; |
|
|
|
padding: 6px 10px; |
|
|
|
font-size: 14px; |
|
|
|
color: #606266; |
|
|
|
border-bottom: 1px solid #eee; |
|
|
|
} |
|
|
|
|
|
|
|
.file-item i { |
|
|
|
color: #909399; |
|
|
|
margin-right: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
.file-name { |
|
|
|
font-size: 13px; |
|
|
|
color: #333; |
|
|
|
word-break: break-all; |
|
|
|
} |
|
|
|
|
|
|
|
.dialog-footer { |
|
|
|
text-align: right; |
|
|
|
} |
|
|
|
</style> |
|
|
|
|