Commit e3c503d5 authored by lijin's avatar lijin

修复图片上传

parent ef53e082
...@@ -107,7 +107,7 @@ export const constantRouterMap = [ ...@@ -107,7 +107,7 @@ export const constantRouterMap = [
{ {
path: "/tools/Youtube", path: "/tools/Youtube",
name: "tools.Youtube", name: "tools.Youtube",
component: () => import("@/views/tools/YouTubeAuth"), component: () => import("@/views/createMaterial/AdMaterialManager"),
meta: { title: "Youtube管理", icon: "chart" } meta: { title: "Youtube管理", icon: "chart" }
} }
] ]
......
<template>
<div class="el-image-uploader">
图片上传组件
<el-upload
ref="upload"
action
:headers="headers"
list-type="picture-card"
:multiple="true"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-error="handleError"
:before-upload="beforeUpload"
:http-request="uploadMulFile"
:file-list="fileList"
:data="uploadData"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过5MB</div>
</el-upload>
<!-- 图片预览对话框 -->
<el-dialog :visible.sync="dialogVisible" append-to-body>
<img width="100%" :src="dialogImageUrl" alt="Preview">
</el-dialog>
</div>
</template>
<script>
import ossClient from "@/utils/ossClient";
import md5 from "md5";
export default {
name: 'ImageUploader',
props: {
// 上传时附带的额外参数
uploadData: {
type: Object,
default: () => ({})
},
// 上传的请求头
headers: {
type: Object,
default: () => ({})
},
// 最大文件大小(MB)
maxSize: {
type: Number,
default: 5
}
},
data() {
return {
fileList: [], // 文件列表
dialogImageUrl: '', // 预览图片URL
dialogVisible: false, // 预览对话框显示状态
uploadConf: {
region: null,
accessKeyId: null,
accessKeySecret: null,
bucket: null,
// stsToken: null,
},
}
},
created() {
this.initOssInfo();
},
methods: {
// 处理图片预览
handlePreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
//初始化从后端获取到 TST账户对OSS进行操作 在created初始化
initOssInfo() {
//获取阿里云token 这里是后台返回来的数据 暂时使用死数据
const aliyun = {
// "你的Region 注意 这个只要 空间名 不要 http:// 和 .aliyunoss.com !!",
Region: "oss-cn-beijing",
AccessKeyId: "LTAI5tJzo2DiQxQqh9EipDNh",
AccessKeySecret: "JnduhWY5Tr5VfuFHgDOv9XjqYx1mDg",
Bucket: "zx-material-new",
//"你的SecurityToken"
// SecurityToken: null,
};
const {
Region,
AccessKeyId,
AccessKeySecret,
Bucket,
// SecurityToken,
} = aliyun;
//初始化连接oss参数
this.uploadConf.region = Region;
this.uploadConf.accessKeyId = AccessKeyId;
this.uploadConf.accessKeySecret = AccessKeySecret;
this.uploadConf.bucket = Bucket;
// this.uploadConf.stsToken = SecurityToken;
},
// 处理图片删除
handleRemove(file, fileList) {
this.fileList = fileList
this.$emit('change', this.getFiles())
},
// 处理上传失败
handleError(err, file) {
this.$message.error('上传失败:' + (err.message || '未知错误'))
},
// 上传前的验证
beforeUpload(file) {
// 验证文件类型
const isImage = file.type.startsWith('image/')
if (!isImage) {
this.$message.error('只能上传图片文件!')
return false
}
// 验证文件大小
const isLtMaxSize = file.size / 1024 / 1024 < this.maxSize
if (!isLtMaxSize) {
this.$message.error(`图片大小不能超过 ${this.maxSize}MB!`)
return false
}
return true
},
// 获取文件列表
getFiles() {
return this.fileList.map(file => ({
name: file.name,
url: file.url,
size: file.size,
raw: file.raw
}))
},
// 清空上传列表
clearFiles() {
this.$refs.upload.clearFiles()
this.fileList = []
this.$emit('change', [])
},
// 手动上传
submit() {
this.$refs.upload.submit()
},
//上传到阿里云OSS
uploadMulFile(uploader) {
console.log("文件信息", uploader);
//获取到文件的信息内容
let file = uploader.file;
//获取文件类型 和 上传文件的日期
let fileType = file.name.split(".").pop();
if (file.name.split(".").length === 1) {
fileType = "jpg";
}
let curTime = new Date();
//定义上传到云端的路径和文件名字
let fileName = md5(file.name + Date.now()) +
"." +
fileType;
let upFilePath =
"ad_putin_materials" +
"/" +
curTime.getFullYear() +
"/" +
(curTime.getMonth() + 1) +
"/" +
curTime.getDate() +
"/" + fileName
//分片上传配置,回显进度以及上传总进度重置,分片大小,超时设置
let optionsFile = {
progress: function (p) {
uploader.onProgress({ percent: Math.floor(p * 10000) / 100 });
},
partSize: 1000 * 1024, //设置分片大小 小于1m 1024*1024
timeout: 36000000, //设置超时时间 - 10小时
};
//实例化上传对象
let client = ossClient(this.uploadConf);
/* 分片上传 显示上传进度 */
const that = this;
//测试地址替换为 "test/" +upFilePath
client
.multipartUpload(upFilePath, file, optionsFile)
.then((res) => {
//解析url并替换前缀可访问
let strUrl = res.res.requestUrls[0].split("?")[0];
strUrl = strUrl.replace(
"http://zx-material-new.oss-cn-beijing.aliyuncs.com",
"https://cdn.zhangxingames.com"
);
that.fileList = [...that.fileList, { uid: file.uid, url: strUrl, name: fileName }];
uploader.onSuccess(); //上传成功(打钩的小图标)
client = null;
this.$emit('change', this.getFiles())
})
.catch((err) => {
that.$message.warning(`上传终止,提示:${err}`);
console.log(err);
if (client.isCancel()) {
uploader.onError();
}
});
},
}
}
</script>
<style>
.el-image-uploader {
padding: 20px;
}
.el-upload__tip {
margin-top: 10px;
color: #909399;
}
</style>
...@@ -615,21 +615,8 @@ ...@@ -615,21 +615,8 @@
<div class="drawer-item-title">制作创意</div> <div class="drawer-item-title">制作创意</div>
<div class="drawer-item-con"> <div class="drawer-item-con">
<el-form ref="form"> <el-form ref="form">
<el-form-item label="选择素材组"> <ImageUploader @change="handleUploadChange"/>
<el-select
v-model="makeCreative.materialGroupId"
placeholder="选择素材组"
style="width: 200px"
>
<el-option
v-for="item in materialList"
:key="item.id"
:label="item.materialGroupName"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-form> </el-form>
</div> </div>
</div> </div>
...@@ -721,6 +708,7 @@ import TextTextarea from "./childComponents/TextTextarea"; ...@@ -721,6 +708,7 @@ import TextTextarea from "./childComponents/TextTextarea";
import CountrySelector from "./childComponents/CountrySelector"; import CountrySelector from "./childComponents/CountrySelector";
import LanguageSelector from "./childComponents/LanguageSelector"; import LanguageSelector from "./childComponents/LanguageSelector";
import TextInputList from "./childComponents/TextInputList"; import TextInputList from "./childComponents/TextInputList";
import ImageUploader from "./childComponents/ImageUploader.vue";
import { stepList } from "./childComponents/util"; import { stepList } from "./childComponents/util";
...@@ -736,6 +724,7 @@ export default { ...@@ -736,6 +724,7 @@ export default {
TextTextarea, TextTextarea,
CountrySelector, CountrySelector,
TextInputList, TextInputList,
ImageUploader
}, // 注册 }, // 注册
data() { data() {
...@@ -2019,6 +2008,10 @@ export default { ...@@ -2019,6 +2008,10 @@ export default {
filterAccount(query, item){ filterAccount(query, item){
query = query.toLowerCase() query = query.toLowerCase()
return item.key.toString().toLowerCase().includes(query)||item.label.toString().toLowerCase().includes(query) return item.key.toString().toLowerCase().includes(query)||item.label.toString().toLowerCase().includes(query)
},
handleUploadChange(files){
console.log("aabbccddeeff", files)
this.putinTask.imageAssets = files
} }
}, },
}; };
......
This diff is collapsed.
...@@ -10,9 +10,6 @@ ...@@ -10,9 +10,6 @@
<el-tab-pane label="文案素材" name="copywriting"> <el-tab-pane label="文案素材" name="copywriting">
<copywritinglibrary v-if="isCopywriting"></copywritinglibrary> <copywritinglibrary v-if="isCopywriting"></copywritinglibrary>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="素材推荐" name="materialRecommend">
<material-recommend v-if="isRecommend" />
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</template> </template>
...@@ -30,7 +27,6 @@ export default { ...@@ -30,7 +27,6 @@ export default {
materialGroup, materialGroup,
copywritinglibrary, copywritinglibrary,
materiallibrary, materiallibrary,
MaterialRecommend,
}, },
data() { data() {
return { return {
......
// 生成唯一ID
const generateId = () => Math.random().toString(36).substr(2, 9);
// 初始化本地存储数据
const initLocalStorage = () => {
if (!localStorage.getItem('directories')) {
localStorage.setItem('directories', JSON.stringify([
{
id: 'root',
name: '根目录',
parentId: null,
children: [
{
id: 'dir1',
name: '2024投放素材',
parentId: 'root',
children: [
{
id: 'dir1-1',
name: '春节活动',
parentId: 'dir1',
children: []
}
]
},
{
id: 'dir2',
name: '产品图库',
parentId: 'root',
children: []
}
]
}
]));
}
if (!localStorage.getItem('materials')) {
localStorage.setItem('materials', JSON.stringify([
{
id: generateId(),
name: '示例图片1.jpg',
type: 'image',
size: 1024 * 1024 * 2, // 2MB
url: 'https://picsum.photos/400/300',
directoryId: 'dir1-1',
createTime: new Date().toISOString()
},
{
id: generateId(),
name: '示例视频1.mp4',
type: 'video',
size: 1024 * 1024 * 10, // 10MB
url: 'https://www.w3schools.com/html/mov_bbb.mp4',
directoryId: 'dir2',
createTime: new Date().toISOString()
}
]));
}
};
// Mock Service 类
export class MockService {
constructor() {
initLocalStorage();
}
// 获取目录树
async getDirectories() {
return new Promise((resolve) => {
setTimeout(() => {
const directories = JSON.parse(localStorage.getItem('directories'));
resolve(directories);
}, 300);
});
}
// 创建目录
async createDirectory({ name, parentId }) {
return new Promise((resolve) => {
setTimeout(() => {
const directories = JSON.parse(localStorage.getItem('directories'));
const newDir = {
id: generateId(),
name,
parentId,
children: []
};
const addToParent = (dirs) => {
for (let dir of dirs) {
if (dir.id === parentId) {
dir.children.push(newDir);
return true;
}
if (dir.children && dir.children.length) {
if (addToParent(dir.children)) return true;
}
}
return false;
};
if (parentId) {
addToParent(directories);
} else {
directories.push(newDir);
}
localStorage.setItem('directories', JSON.stringify(directories));
resolve(newDir);
}, 300);
});
}
// 删除目录
async deleteDirectory(id) {
return new Promise((resolve) => {
setTimeout(() => {
const directories = JSON.parse(localStorage.getItem('directories'));
const materials = JSON.parse(localStorage.getItem('materials'));
const removeDir = (dirs) => {
for (let i = 0; i < dirs.length; i++) {
if (dirs[i].id === id) {
dirs.splice(i, 1);
return true;
}
if (dirs[i].children && dirs[i].children.length) {
if (removeDir(dirs[i].children)) return true;
}
}
return false;
};
// 将目录下的文件移动到根目录
const updatedMaterials = materials.map(material => {
if (material.directoryId === id) {
return { ...material, directoryId: 'root' };
}
return material;
});
removeDir(directories);
localStorage.setItem('directories', JSON.stringify(directories));
localStorage.setItem('materials', JSON.stringify(updatedMaterials));
resolve({ success: true });
}, 300);
});
}
// 获取文件列表
async getMaterials(directoryId) {
return new Promise((resolve) => {
setTimeout(() => {
const materials = JSON.parse(localStorage.getItem('materials'));
const filtered = materials.filter(m => m.directoryId === directoryId);
resolve(filtered);
}, 300);
});
}
// 上传文件
async uploadFile(file, directoryId) {
return new Promise((resolve) => {
setTimeout(() => {
const reader = new FileReader();
reader.onload = (e) => {
const materials = JSON.parse(localStorage.getItem('materials'));
const newMaterial = {
id: generateId(),
name: file.name,
type: file.type.startsWith('image/') ? 'image' : 'video',
size: file.size,
url: file.type.startsWith('image/')
? 'https://picsum.photos/400/300?' + new Date().getTime() // 模拟新的图片URL
: 'https://www.w3schools.com/html/mov_bbb.mp4', // 模拟视频URL
directoryId,
createTime: new Date().toISOString()
};
materials.push(newMaterial);
localStorage.setItem('materials', JSON.stringify(materials));
resolve({ code: 0, message: 'success', url: newMaterial.url });
};
reader.readAsDataURL(file);
}, 1000); // 模拟上传耗时
});
}
// 移动文件
async moveFile(fileId, targetDirectoryId) {
return new Promise((resolve) => {
setTimeout(() => {
const materials = JSON.parse(localStorage.getItem('materials'));
const updatedMaterials = materials.map(material => {
if (material.id === fileId) {
return { ...material, directoryId: targetDirectoryId };
}
return material;
});
localStorage.setItem('materials', JSON.stringify(updatedMaterials));
resolve({ success: true });
}, 300);
});
}
// 删除文件
async deleteFile(fileId) {
return new Promise((resolve) => {
setTimeout(() => {
const materials = JSON.parse(localStorage.getItem('materials'));
const index = materials.findIndex(m => m.id === fileId);
if (index > -1) {
materials.splice(index, 1);
localStorage.setItem('materials', JSON.stringify(materials));
}
resolve({ success: true });
}, 300);
});
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment