|
|
@@ -43,9 +43,11 @@
|
|
|
<div class="image-upload-wrap">
|
|
|
<UploadImgs
|
|
|
v-model:file-list="imageFileList"
|
|
|
- :api="uploadImgStore"
|
|
|
+ :api="handleCustomImageUpload"
|
|
|
:limit="9"
|
|
|
:file-size="5"
|
|
|
+ :width="'100px'"
|
|
|
+ :height="'100px'"
|
|
|
:disabled="viewMode"
|
|
|
class="price-list-upload"
|
|
|
@update:file-list="onImageListChange"
|
|
|
@@ -241,6 +243,8 @@
|
|
|
:api="uploadImgStore"
|
|
|
:limit="9"
|
|
|
:file-size="5"
|
|
|
+ :width="'100px'"
|
|
|
+ :height="'100px'"
|
|
|
:disabled="viewMode"
|
|
|
class="price-list-upload"
|
|
|
@update:file-list="onDetailImageListChange"
|
|
|
@@ -355,7 +359,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts" name="priceListEdit">
|
|
|
-import { ref, reactive, computed, onMounted, watch } from "vue";
|
|
|
+import { ref, reactive, computed, onMounted, watch, nextTick } from "vue";
|
|
|
import { ElMessage } from "element-plus";
|
|
|
import { useRoute, useRouter } from "vue-router";
|
|
|
import type { FormInstance, UploadUserFile } from "element-plus";
|
|
|
@@ -545,9 +549,75 @@ function calcRecommendedPrice() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 自定义上传函数,正确处理响应格式(参考 personnelConfig/index.vue)
|
|
|
+const handleCustomImageUpload = async (formData: FormData): Promise<any> => {
|
|
|
+ try {
|
|
|
+ const response: any = await uploadImgStore(formData);
|
|
|
+
|
|
|
+ // API 返回格式: { code: 200, success: true, data: ["https://..."], msg: "操作成功" }
|
|
|
+ // 需要提取 response.data[0] 作为图片 URL
|
|
|
+ let imageUrl = "";
|
|
|
+
|
|
|
+ if (response && (response.code === 200 || response.code === "200")) {
|
|
|
+ if (Array.isArray(response.data) && response.data.length > 0) {
|
|
|
+ imageUrl = response.data[0];
|
|
|
+ } else if (typeof response.data === "string") {
|
|
|
+ imageUrl = response.data;
|
|
|
+ } else if (response.data?.fileUrl) {
|
|
|
+ imageUrl = response.data.fileUrl;
|
|
|
+ } else if (response.fileUrl) {
|
|
|
+ imageUrl = response.fileUrl;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!imageUrl) {
|
|
|
+ throw new Error("无法提取图片URL");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回格式需要兼容 Imgs.vue 组件的处理逻辑
|
|
|
+ // 返回一个对象,其中 fileUrl 是图片URL,这样 uploadSuccess 会使用 response.fileUrl
|
|
|
+ const result = {
|
|
|
+ fileUrl: imageUrl, // 供 uploadSuccess 使用(会设置 uploadFile.url = response.fileUrl)
|
|
|
+ data: [imageUrl], // 备用
|
|
|
+ code: response.code,
|
|
|
+ msg: response.msg,
|
|
|
+ success: response.success
|
|
|
+ };
|
|
|
+
|
|
|
+ return result;
|
|
|
+ } catch (error) {
|
|
|
+ console.error("自定义上传函数 - 上传失败:", error);
|
|
|
+ throw error;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 统一处理文件列表变化,更新 formModel.images(用逗号拼接)
|
|
|
+// 注意:这是多选,最后要用逗号拼接在一起
|
|
|
function onImageListChange(list: UploadUserFile[]) {
|
|
|
- const urls = list.map(f => (typeof f.url === "string" ? f.url : "")).filter(Boolean);
|
|
|
+ // 过滤掉 blob URL,只保留服务器 URL,然后用逗号拼接
|
|
|
+ const urls = list
|
|
|
+ .filter(f => {
|
|
|
+ const url = f.url;
|
|
|
+ if (!url || typeof url !== "string") return false;
|
|
|
+ // 排除 blob URL(临时预览 URL)
|
|
|
+ return !url.startsWith("blob:");
|
|
|
+ })
|
|
|
+ .map(f => {
|
|
|
+ const url = f.url;
|
|
|
+ if (url && typeof url === "string") {
|
|
|
+ return url.trim();
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ })
|
|
|
+ .filter(Boolean);
|
|
|
+
|
|
|
+ // 用逗号拼接所有 URL
|
|
|
formModel.images = urls.join(",");
|
|
|
+
|
|
|
+ // 触发表单验证
|
|
|
+ if (ruleFormRef.value) {
|
|
|
+ ruleFormRef.value.validateField("images");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function onDetailImageListChange(list: UploadUserFile[]) {
|
|
|
@@ -558,10 +628,20 @@ function onDetailImageListChange(list: UploadUserFile[]) {
|
|
|
function syncImageFileListFromModel() {
|
|
|
const str = formModel.images || "";
|
|
|
const urls = str ? str.split(",").filter(Boolean) : [];
|
|
|
- imageFileList.value = urls.map((url, i) => ({ uid: i, name: `img-${i}`, url }));
|
|
|
+ imageFileList.value = urls.map((url, i) => ({
|
|
|
+ uid: Date.now() + i,
|
|
|
+ name: `img-${i}`,
|
|
|
+ url: url.trim(),
|
|
|
+ status: "success" as const
|
|
|
+ }));
|
|
|
const detailStr = formModel.imageContent || "";
|
|
|
const detailUrls = detailStr ? detailStr.split(",").filter(Boolean) : [];
|
|
|
- detailImageFileList.value = detailUrls.map((url, i) => ({ uid: 1000 + i, name: `detail-${i}`, url }));
|
|
|
+ detailImageFileList.value = detailUrls.map((url, i) => ({
|
|
|
+ uid: Date.now() + 1000 + i,
|
|
|
+ name: `detail-${i}`,
|
|
|
+ url: url.trim(),
|
|
|
+ status: "success" as const
|
|
|
+ }));
|
|
|
}
|
|
|
|
|
|
// 详情接口返回转表单(美食接口返回 data.data.data 结构,cuisineType 1=菜品 2=套餐;非美食仅通用字段)
|