Merge branch 'dev' of https://gitee.com/red-future---jilin-g/admin-ui into dev
This commit is contained in:
@@ -76,7 +76,7 @@ export function uploadAssetImage(file: File) {
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
return newService({
|
return newService({
|
||||||
url: '/assets/asset/Uploadimage',
|
url: '/oss/file/uploadFile',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: formData,
|
data: formData,
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -135,9 +135,9 @@
|
|||||||
<el-upload
|
<el-upload
|
||||||
class="attr-image-uploader"
|
class="attr-image-uploader"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:auto-upload="false"
|
:auto-upload="true"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
:on-change="onAttrImageChange(attr)"
|
:http-request="onAttrImageUpload(attr)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="ruleForm.metadata[getAttrKey(attr)]"
|
v-if="ruleForm.metadata[getAttrKey(attr)]"
|
||||||
@@ -172,8 +172,8 @@
|
|||||||
<el-upload
|
<el-upload
|
||||||
class="avatar-uploader"
|
class="avatar-uploader"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:auto-upload="false"
|
:auto-upload="true"
|
||||||
:on-change="handleMainImageChange"
|
:http-request="handleMainImageUpload"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
>
|
>
|
||||||
<img v-if="mainImagePreview" :src="mainImagePreview" class="avatar" />
|
<img v-if="mainImagePreview" :src="mainImagePreview" class="avatar" />
|
||||||
@@ -191,7 +191,8 @@
|
|||||||
<el-upload
|
<el-upload
|
||||||
v-model:file-list="imageFileList"
|
v-model:file-list="imageFileList"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:auto-upload="false"
|
:auto-upload="true"
|
||||||
|
:http-request="handleImageListUpload"
|
||||||
:on-preview="handlePictureCardPreview"
|
:on-preview="handlePictureCardPreview"
|
||||||
:on-remove="handleRemove"
|
:on-remove="handleRemove"
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
@@ -445,7 +446,7 @@ import { Plus, Delete } from '@element-plus/icons-vue';
|
|||||||
import { getAsset, createAsset, updateAsset, uploadAssetImage } from '/@/api/assets/asset';
|
import { getAsset, createAsset, updateAsset, uploadAssetImage } from '/@/api/assets/asset';
|
||||||
import { getCategoryTree, getCategory } from '/@/api/assets/category';
|
import { getCategoryTree, getCategory } from '/@/api/assets/category';
|
||||||
import Editor from '/@/components/editor/index.vue';
|
import Editor from '/@/components/editor/index.vue';
|
||||||
import type { UploadFile, UploadUserFile } from 'element-plus';
|
import type { UploadFile, UploadUserFile, UploadRequestOptions } from 'element-plus';
|
||||||
|
|
||||||
// 类型定义
|
// 类型定义
|
||||||
interface TimeSlot {
|
interface TimeSlot {
|
||||||
@@ -547,20 +548,18 @@ const getAttrLabel = (attr: CategoryAttr): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 图片相关
|
// 图片相关
|
||||||
const mainImageFile = ref<File | null>(null);
|
|
||||||
const mainImagePreview = ref('');
|
const mainImagePreview = ref('');
|
||||||
const imageFileList = ref<UploadUserFile[]>([]);
|
const imageFileList = ref<UploadUserFile[]>([]);
|
||||||
const attrImageFiles = ref<Record<string, File>>({}); // 暂存属性图片文件
|
|
||||||
const dialogVisible = ref(false);
|
const dialogVisible = ref(false);
|
||||||
const dialogImageUrl = ref('');
|
const dialogImageUrl = ref('');
|
||||||
// 图片拼接
|
// 图片拼接
|
||||||
const imgAddressPrefix = ref('');
|
const fileAddressPrefix = ref('');
|
||||||
|
|
||||||
const formatImageUrl = (url?: string) => {
|
const formatImageUrl = (url?: string) => {
|
||||||
if (!url) return '';
|
if (!url) return '';
|
||||||
if (/^https?:\/\//i.test(url)) return url;
|
if (/^https?:\/\//i.test(url)) return url;
|
||||||
if (/^blob:/i.test(url)) return url; // 支持本地预览地址
|
if (/^blob:/i.test(url)) return url; // 支持本地预览地址
|
||||||
return `${imgAddressPrefix.value || ''}${url}`;
|
return `${fileAddressPrefix.value || ''}${url}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createDefaultTimeSlots = (): TimeSlot[] => {
|
const createDefaultTimeSlots = (): TimeSlot[] => {
|
||||||
@@ -674,15 +673,56 @@ const rules: FormRules = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 主图上传处理
|
// 主图上传处理
|
||||||
const handleMainImageChange = (file: UploadFile) => {
|
const handleMainImageUpload = async (options: UploadRequestOptions) => {
|
||||||
if (file.raw) {
|
try {
|
||||||
mainImageFile.value = file.raw;
|
const url = await uploadImage(options.file);
|
||||||
mainImagePreview.value = URL.createObjectURL(file.raw);
|
if (url) {
|
||||||
ruleForm.mainImage = 'set'; // 标记已上传
|
ruleForm.mainImage = url;
|
||||||
formRef.value?.validateField('mainImage');
|
mainImagePreview.value = formatImageUrl(url);
|
||||||
|
formRef.value?.validateField('mainImage');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('主图上传失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 图片列表上传处理
|
||||||
|
const handleImageListUpload = async (options: UploadRequestOptions) => {
|
||||||
|
try {
|
||||||
|
const url = await uploadImage(options.file);
|
||||||
|
if (url) {
|
||||||
|
const fileItem = imageFileList.value.find((f) => f.uid === options.file.uid);
|
||||||
|
if (fileItem) {
|
||||||
|
fileItem.url = formatImageUrl(url);
|
||||||
|
fileItem.status = 'success';
|
||||||
|
fileItem.response = url; // 存储原始 URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('上传失败');
|
||||||
|
const index = imageFileList.value.findIndex((f) => f.uid === options.file.uid);
|
||||||
|
if (index !== -1) {
|
||||||
|
imageFileList.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 属性图片上传处理
|
||||||
|
const onAttrImageUpload = (attr: CategoryAttr) => {
|
||||||
|
return async (options: UploadRequestOptions) => {
|
||||||
|
try {
|
||||||
|
const url = await uploadImage(options.file);
|
||||||
|
if (url) {
|
||||||
|
const key = getAttrKey(attr);
|
||||||
|
ruleForm.metadata[key] = url;
|
||||||
|
formRef.value?.validateField(`metadata.${key}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('图片上传失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// 主图预览
|
// 主图预览
|
||||||
const previewMainImage = () => {
|
const previewMainImage = () => {
|
||||||
if (mainImagePreview.value) {
|
if (mainImagePreview.value) {
|
||||||
@@ -693,7 +733,6 @@ const previewMainImage = () => {
|
|||||||
|
|
||||||
// 主图删除
|
// 主图删除
|
||||||
const removeMainImage = () => {
|
const removeMainImage = () => {
|
||||||
mainImageFile.value = null;
|
|
||||||
mainImagePreview.value = '';
|
mainImagePreview.value = '';
|
||||||
ruleForm.mainImage = '';
|
ruleForm.mainImage = '';
|
||||||
formRef.value?.validateField('mainImage');
|
formRef.value?.validateField('mainImage');
|
||||||
@@ -701,8 +740,6 @@ const removeMainImage = () => {
|
|||||||
|
|
||||||
// 图片列表预览
|
// 图片列表预览
|
||||||
const handlePictureCardPreview = (file: UploadFile) => {
|
const handlePictureCardPreview = (file: UploadFile) => {
|
||||||
console.log(file,'111');
|
|
||||||
|
|
||||||
dialogImageUrl.value = file.url || '';
|
dialogImageUrl.value = file.url || '';
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
};
|
};
|
||||||
@@ -715,29 +752,10 @@ const handleRemove = (file: UploadFile) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 属性图片上传处理
|
|
||||||
const handleAttrImageChange = (file: UploadFile, attr: CategoryAttr) => {
|
|
||||||
if (file.raw) {
|
|
||||||
const key = getAttrKey(attr);
|
|
||||||
const url = URL.createObjectURL(file.raw);
|
|
||||||
ruleForm.metadata[key] = url;
|
|
||||||
attrImageFiles.value[key] = file.raw;
|
|
||||||
formRef.value?.validateField(`metadata.${key}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 生成属性图片上传回调
|
|
||||||
const onAttrImageChange = (attr: CategoryAttr) => {
|
|
||||||
return (file: UploadFile) => handleAttrImageChange(file, attr);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 移除属性图片
|
// 移除属性图片
|
||||||
const removeAttrImage = (attr: CategoryAttr) => {
|
const removeAttrImage = (attr: CategoryAttr) => {
|
||||||
const key = getAttrKey(attr);
|
const key = getAttrKey(attr);
|
||||||
ruleForm.metadata[key] = '';
|
ruleForm.metadata[key] = '';
|
||||||
if (attrImageFiles.value[key]) {
|
|
||||||
delete attrImageFiles.value[key];
|
|
||||||
}
|
|
||||||
formRef.value?.validateField(`metadata.${key}`);
|
formRef.value?.validateField(`metadata.${key}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -806,12 +824,10 @@ const removeKeyValuePair = (list: KeyValuePair[], index: number) => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
const initial = getInitialForm();
|
const initial = getInitialForm();
|
||||||
Object.assign(ruleForm, initial);
|
Object.assign(ruleForm, initial);
|
||||||
mainImageFile.value = null;
|
|
||||||
mainImagePreview.value = '';
|
mainImagePreview.value = '';
|
||||||
imageFileList.value = [];
|
imageFileList.value = [];
|
||||||
attrImageFiles.value = {};
|
|
||||||
categoryAttrs.value = [];
|
categoryAttrs.value = [];
|
||||||
imgAddressPrefix.value = '';
|
fileAddressPrefix.value = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取分类数据
|
// 获取分类数据
|
||||||
@@ -863,7 +879,8 @@ const openDialog = (row?: any, edit?: boolean) => {
|
|||||||
getAsset(row.id)
|
getAsset(row.id)
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
const data = res.data;
|
const data = res.data;
|
||||||
imgAddressPrefix.value = data.imgAddressPrefix || '';
|
// 支持 fileAddressPrefix 和 imgAddressPrefix
|
||||||
|
fileAddressPrefix.value = data.fileAddressPrefix || data.imgAddressPrefix || '';
|
||||||
ruleForm.id = data.id || '';
|
ruleForm.id = data.id || '';
|
||||||
ruleForm.name = data.name || '';
|
ruleForm.name = data.name || '';
|
||||||
ruleForm.type = data.type || 'physical';
|
ruleForm.type = data.type || 'physical';
|
||||||
@@ -872,10 +889,11 @@ const openDialog = (row?: any, edit?: boolean) => {
|
|||||||
ruleForm.onlineTime = data.onlineTime || '';
|
ruleForm.onlineTime = data.onlineTime || '';
|
||||||
ruleForm.offlineTime = data.offlineTime || '';
|
ruleForm.offlineTime = data.offlineTime || '';
|
||||||
|
|
||||||
// 主图预览
|
// 主图预览 (支持 imageUrl 和 fileURL)
|
||||||
if (data.imageUrl) {
|
const mainImg = data.imageUrl || data.fileURL;
|
||||||
mainImagePreview.value = formatImageUrl(data.imageUrl);
|
if (mainImg) {
|
||||||
ruleForm.mainImage = data.imageUrl;
|
mainImagePreview.value = formatImageUrl(mainImg);
|
||||||
|
ruleForm.mainImage = mainImg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片列表
|
// 图片列表
|
||||||
@@ -883,6 +901,7 @@ const openDialog = (row?: any, edit?: boolean) => {
|
|||||||
imageFileList.value = data.images.map((url: string, index: number) => ({
|
imageFileList.value = data.images.map((url: string, index: number) => ({
|
||||||
name: `image-${index}`,
|
name: `image-${index}`,
|
||||||
url: formatImageUrl(url),
|
url: formatImageUrl(url),
|
||||||
|
response: url, // 存储原始相对路径,供提交时使用
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,7 +1042,29 @@ const onCancel = () => {
|
|||||||
// 上传图片并返回URL
|
// 上传图片并返回URL
|
||||||
const uploadImage = async (file: File): Promise<string> => {
|
const uploadImage = async (file: File): Promise<string> => {
|
||||||
const res: any = await uploadAssetImage(file);
|
const res: any = await uploadAssetImage(file);
|
||||||
return res.data?.url || res.data || '';
|
|
||||||
|
// 1. 尝试获取并设置 fileAddressPrefix
|
||||||
|
// 优先检查顶层,再检查 data 内部
|
||||||
|
if (res.fileAddressPrefix) {
|
||||||
|
fileAddressPrefix.value = res.fileAddressPrefix;
|
||||||
|
} else if (res.data && typeof res.data === 'object' && res.data.fileAddressPrefix) {
|
||||||
|
fileAddressPrefix.value = res.data.fileAddressPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 尝试获取 fileURL / url
|
||||||
|
// 优先检查顶层 fileURL
|
||||||
|
if (res.fileURL) return res.fileURL;
|
||||||
|
|
||||||
|
// 检查 data 对象中的 fileURL 或 url
|
||||||
|
if (res.data && typeof res.data === 'object') {
|
||||||
|
if (res.data.fileURL) return res.data.fileURL;
|
||||||
|
if (res.data.url) return res.data.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 兼容旧逻辑 (data 直接是 url 字符串)
|
||||||
|
if (typeof res.data === 'string') return res.data;
|
||||||
|
|
||||||
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
// 构建请求体
|
// 构建请求体
|
||||||
@@ -1048,21 +1089,19 @@ const buildRequestBody = async (): Promise<any> => {
|
|||||||
body.offlineTime = ruleForm.offlineTime;
|
body.offlineTime = ruleForm.offlineTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主图上传
|
// 主图 (已在上传时直接赋值给 ruleForm.mainImage)
|
||||||
if (mainImageFile.value) {
|
if (ruleForm.mainImage) {
|
||||||
body.imageUrl = await uploadImage(mainImageFile.value);
|
body.fileURL = ruleForm.mainImage;
|
||||||
} else if (ruleForm.mainImage && !ruleForm.mainImage.startsWith('blob:')) {
|
|
||||||
body.imageUrl = ruleForm.mainImage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 图片列表上传
|
// 图片列表
|
||||||
const imageUrls: string[] = [];
|
const imageUrls: string[] = [];
|
||||||
for (const file of imageFileList.value) {
|
for (const file of imageFileList.value) {
|
||||||
if (file.raw) {
|
if (file.response) {
|
||||||
const url = await uploadImage(file.raw);
|
// 新上传的图片使用原始 URL
|
||||||
if (url) imageUrls.push(url);
|
imageUrls.push(file.response as string);
|
||||||
} else if (file.url && !file.url.startsWith('blob:')) {
|
} else if (file.url && !file.url.startsWith('blob:')) {
|
||||||
// 已有图片保留原URL
|
// 已有图片保留原 URL
|
||||||
imageUrls.push(file.url);
|
imageUrls.push(file.url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1108,10 +1147,8 @@ const buildRequestBody = async (): Promise<any> => {
|
|||||||
const key = getAttrKey(attr);
|
const key = getAttrKey(attr);
|
||||||
let value = ruleForm.metadata[key];
|
let value = ruleForm.metadata[key];
|
||||||
|
|
||||||
// 如果是图片类型且有文件需要上传
|
// 如果是图片类型,且值是 blob 开头(未上传成功的情况),置为空
|
||||||
if (attr.type === 'image' && attrImageFiles.value[key]) {
|
if (attr.type === 'image' && typeof value === 'string' && value.startsWith('blob:')) {
|
||||||
value = await uploadImage(attrImageFiles.value[key]);
|
|
||||||
} else if (typeof value === 'string' && value.startsWith('blob:')) {
|
|
||||||
value = '';
|
value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user