|
|
@@ -1,42 +1,13 @@
|
|
|
<template>
|
|
|
<div class="head-map-container">
|
|
|
<div class="content-wrapper">
|
|
|
- <!-- 顶部:模式选择预览 -->
|
|
|
+ <!-- 顶部:大图模式预览 -->
|
|
|
<div class="mode-preview-section">
|
|
|
- <!-- 单图模式预览 -->
|
|
|
- <div class="preview-box" :class="{ active: mode === 'single' }" @click="mode = 'single'">
|
|
|
- <div class="preview-card">
|
|
|
- <div class="preview-image-large">
|
|
|
- <img v-if="formData.singleImage" :src="formData.singleImage" alt="单图" />
|
|
|
- <div v-else class="preview-placeholder">示例图</div>
|
|
|
- <div class="overlay-button">
|
|
|
- <span>相册</span>
|
|
|
- <el-icon><ArrowRight /></el-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="preview-info">
|
|
|
- <div class="store-name">示例门店</div>
|
|
|
- <div class="store-rating">
|
|
|
- <el-rate v-model="previewData.rating" disabled show-score text-color="#ff9900" score-template="{value}" />
|
|
|
- </div>
|
|
|
- <div class="store-reviews">{{ previewData.reviews }} 条评价</div>
|
|
|
- <el-icon class="arrow-icon">
|
|
|
- <ArrowRight />
|
|
|
- </el-icon>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="mode-label">
|
|
|
- <span>单图模式</span>
|
|
|
- <el-tag v-if="mode === 'single'" type="success" size="small"> 生效中 </el-tag>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 多图模式预览 -->
|
|
|
- <div class="preview-box" :class="{ active: mode === 'multiple' }" @click="mode = 'multiple'">
|
|
|
+ <div class="preview-box">
|
|
|
<div class="preview-card">
|
|
|
<div class="preview-images-multiple">
|
|
|
<div v-for="(img, index) in displayImages" :key="index" class="preview-image-small">
|
|
|
- <img v-if="img" :src="img" alt="多图" />
|
|
|
+ <img v-if="img" :src="img" alt="头图" />
|
|
|
<div v-else class="preview-placeholder">示例图</div>
|
|
|
</div>
|
|
|
<div v-if="displayImages.length < 3" class="preview-image-small">
|
|
|
@@ -59,8 +30,7 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="mode-label">
|
|
|
- <span>多图模式</span>
|
|
|
- <el-tag v-if="mode === 'multiple'" type="success" size="small"> 生效中 </el-tag>
|
|
|
+ <span>大图模式</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -69,41 +39,15 @@
|
|
|
<div class="upload-section">
|
|
|
<h2 class="section-title">图片</h2>
|
|
|
|
|
|
- <!-- 说明文字 -->
|
|
|
<div class="instructions">
|
|
|
<ol class="instruction-list">
|
|
|
- <li v-if="mode === 'single'">入口图建议上传能够代表店铺的图片,如环境范围、菜品样式、本店特色等。</li>
|
|
|
- <li v-if="mode === 'single'">建议上传1:1尺寸的图片,避免图片出现显示不全问题。</li>
|
|
|
- <li v-if="mode === 'single'">建议尺寸900*900像素以内,不超过10MB。</li>
|
|
|
- <li v-if="mode === 'multiple'">图片会在店铺头图区域展示。</li>
|
|
|
- <li v-if="mode === 'multiple'">至少上传3张图片,可拖拽排序。</li>
|
|
|
- <li v-if="mode === 'multiple'">建议上传16:9尺寸的图片,大小不超过20MB 避免图片出现显示不全问题。</li>
|
|
|
+ <li>图片会在店铺头图区域展示。</li>
|
|
|
+ <li>至少上传3张图片,可拖拽排序。</li>
|
|
|
+ <li>建议上传16:9尺寸的图片,大小不超过20MB 避免图片出现显示不全问题。</li>
|
|
|
</ol>
|
|
|
</div>
|
|
|
|
|
|
- <!-- 单图模式上传 -->
|
|
|
- <el-form v-if="mode === 'single'" ref="singleFormRef" :model="formData" :rules="singleRules" label-width="0">
|
|
|
- <el-form-item prop="singleImage">
|
|
|
- <UploadImg
|
|
|
- v-model:image-url="formData.singleImage"
|
|
|
- :width="'400px'"
|
|
|
- :height="'400px'"
|
|
|
- :file-size="20"
|
|
|
- :file-type="['image/jpeg', 'image/png', 'image/gif', 'image/webp']"
|
|
|
- :border-radius="'8px'"
|
|
|
- :api="uploadImageResult"
|
|
|
- :on-success="handleStoreOcrAfterUpload"
|
|
|
- :show-success-notification="false"
|
|
|
- >
|
|
|
- <template #tip>
|
|
|
- <div class="upload-tip">({{ formData.singleImage ? "1" : "0" }}/1)</div>
|
|
|
- </template>
|
|
|
- </UploadImg>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
-
|
|
|
- <!-- 多图模式上传 -->
|
|
|
- <el-form v-if="mode === 'multiple'" ref="multipleFormRef" :model="formData" :rules="multipleRules" label-width="0">
|
|
|
+ <el-form ref="multipleFormRef" :model="formData" :rules="multipleRules" label-width="0">
|
|
|
<el-form-item prop="multipleImages">
|
|
|
<div class="multiple-upload-wrapper" :class="{ 'upload-full': formData.multipleImages.length >= 6 }">
|
|
|
<UploadImgs
|
|
|
@@ -144,7 +88,6 @@ import type { FormInstance, FormRules } from "element-plus";
|
|
|
import type { UploadUserFile } from "element-plus";
|
|
|
import { ArrowRight } from "@element-plus/icons-vue";
|
|
|
import Sortable from "sortablejs";
|
|
|
-import UploadImg from "@/components/Upload/Img.vue";
|
|
|
import UploadImgs from "@/components/Upload/Imgs.vue";
|
|
|
import { getStoreOcrData } from "@/api/modules/newLoginApi";
|
|
|
import { uploadFilesToOss } from "@/api/upload.js";
|
|
|
@@ -154,30 +97,19 @@ import { localGet } from "@/utils";
|
|
|
import { useRouter } from "vue-router";
|
|
|
|
|
|
const loading = ref(false);
|
|
|
-const singleFormRef = ref<FormInstance>();
|
|
|
const multipleFormRef = ref<FormInstance>();
|
|
|
const sortableInstance = ref<Sortable | null>(null);
|
|
|
const router = useRouter();
|
|
|
-const imgModeActive = ref(null);
|
|
|
const storeName = ref("");
|
|
|
+
|
|
|
const handleStoreOcrAfterUploadMore = async (imageUrl: string) => {
|
|
|
try {
|
|
|
await handleStoreOcr({ imageUrl });
|
|
|
} catch (error) {
|
|
|
- // OCR识别失败,移除已上传的图片
|
|
|
formData.multipleImages = formData.multipleImages.filter(item => item.url !== imageUrl);
|
|
|
throw error;
|
|
|
}
|
|
|
};
|
|
|
-const handleStoreOcrAfterUpload = async (imageUrl: string) => {
|
|
|
- try {
|
|
|
- await handleStoreOcr({ imageUrl });
|
|
|
- } catch (error) {
|
|
|
- // OCR识别失败,清除已上传的图片
|
|
|
- formData.singleImage = "";
|
|
|
- throw error;
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
const handleStoreOcr = async (params: { imageUrl: string }) => {
|
|
|
try {
|
|
|
@@ -197,52 +129,41 @@ const handleStoreOcr = async (params: { imageUrl: string }) => {
|
|
|
type: "error",
|
|
|
duration: 5000
|
|
|
});
|
|
|
- formData.singleImage = "";
|
|
|
formData.multipleImages = [];
|
|
|
}
|
|
|
} else {
|
|
|
- // 业务逻辑错误,只在这里显示错误消息
|
|
|
const errorMsg = res?.msg || "未查询到OCR识别数据";
|
|
|
ElMessage.error(errorMsg);
|
|
|
const error = new Error(errorMsg);
|
|
|
- formData.singleImage = "";
|
|
|
formData.multipleImages = [];
|
|
|
- (error as any).handled = true; // 标记错误已被处理
|
|
|
+ (error as any).handled = true;
|
|
|
throw error;
|
|
|
}
|
|
|
} catch (error: any) {
|
|
|
- // 网络错误或其他异常,只在这里显示错误消息
|
|
|
if (!error.handled) {
|
|
|
}
|
|
|
throw error;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 模式:single 单图模式,multiple 多图模式
|
|
|
-const mode = ref<"single" | "multiple">("single");
|
|
|
-
|
|
|
-// 表单数据
|
|
|
const formData = reactive({
|
|
|
- singleImage: "", // 单图模式图片URL
|
|
|
- multipleImages: [] as UploadUserFile[] // 多图模式图片列表
|
|
|
+ multipleImages: [] as UploadUserFile[]
|
|
|
});
|
|
|
|
|
|
-// 预览数据(示例数据)
|
|
|
const previewData = reactive({
|
|
|
rating: 5.0,
|
|
|
reviews: 1853
|
|
|
});
|
|
|
|
|
|
-// 显示的多图预览
|
|
|
const displayImages = computed(() => {
|
|
|
return formData.multipleImages.slice(0, 3).map(item => item.url || "");
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
- * OSS 直传:同时满足 UploadImg(解构 data)与 UploadImgs(读 response.fileUrl)
|
|
|
+ * OSS 直传:满足 UploadImgs(读 response.fileUrl)
|
|
|
*/
|
|
|
-const uploadImageResult = async (formData: FormData): Promise<any> => {
|
|
|
- const raw = formData.get("file");
|
|
|
+const uploadImageResult = async (payload: FormData): Promise<any> => {
|
|
|
+ const raw = payload.get("file");
|
|
|
const file = raw instanceof File ? raw : null;
|
|
|
if (!file) {
|
|
|
throw new Error("请选择文件");
|
|
|
@@ -259,24 +180,6 @@ const uploadImageResult = async (formData: FormData): Promise<any> => {
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-// 单图模式表单校验规则
|
|
|
-const singleRules = reactive<FormRules>({
|
|
|
- singleImage: [
|
|
|
- { required: true, message: "请上传入口图", trigger: "change" },
|
|
|
- {
|
|
|
- validator: (rule, value, callback) => {
|
|
|
- if (!value) {
|
|
|
- callback(new Error("请上传入口图"));
|
|
|
- } else {
|
|
|
- callback();
|
|
|
- }
|
|
|
- },
|
|
|
- trigger: "change"
|
|
|
- }
|
|
|
- ]
|
|
|
-});
|
|
|
-
|
|
|
-// 多图模式表单校验规则
|
|
|
const multipleRules = reactive<FormRules>({
|
|
|
multipleImages: [
|
|
|
{
|
|
|
@@ -292,38 +195,16 @@ const multipleRules = reactive<FormRules>({
|
|
|
]
|
|
|
});
|
|
|
|
|
|
-// 标记是否正在初始化,防止初始化时触发查询
|
|
|
-const isInitializing = ref(true);
|
|
|
-
|
|
|
-// 监听模式切换,查询对应模式的数据
|
|
|
-watch(
|
|
|
- () => mode.value,
|
|
|
- async (newMode, oldMode) => {
|
|
|
- // 初始化时不触发查询(因为初始化时已经查询过了)
|
|
|
- if (isInitializing.value) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 切换模式时,查询对应模式的数据
|
|
|
- await loadHeadImgByMode(newMode);
|
|
|
- }
|
|
|
-);
|
|
|
-
|
|
|
-// 监听多图列表变化,重新初始化拖拽排序
|
|
|
watch(
|
|
|
() => formData.multipleImages.length,
|
|
|
() => {
|
|
|
- if (mode.value === "multiple") {
|
|
|
- nextTick(() => {
|
|
|
- initDragSort();
|
|
|
- });
|
|
|
- }
|
|
|
+ nextTick(() => {
|
|
|
+ initDragSort();
|
|
|
+ });
|
|
|
}
|
|
|
);
|
|
|
|
|
|
-// 初始化拖拽排序
|
|
|
const initDragSort = () => {
|
|
|
- // 如果已存在实例,先销毁
|
|
|
if (sortableInstance.value) {
|
|
|
sortableInstance.value.destroy();
|
|
|
sortableInstance.value = null;
|
|
|
@@ -344,67 +225,6 @@ const initDragSort = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-// 根据模式查询对应的头图数据
|
|
|
-const loadHeadImgByMode = async (targetMode: "single" | "multiple") => {
|
|
|
- try {
|
|
|
- const userInfo: any = localGet("geeker-user")?.userInfo || {};
|
|
|
- const storeId = userInfo.storeId;
|
|
|
- if (!storeId) {
|
|
|
- console.warn("未找到店铺ID");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- const imgType = targetMode === "single" ? 20 : 21;
|
|
|
- const res: any = await getStoreHeadImg(storeId, imgType);
|
|
|
-
|
|
|
- if (res.code == 200) {
|
|
|
- const dataAny = res.data as any;
|
|
|
- const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
|
|
|
-
|
|
|
- if (targetMode === "single") {
|
|
|
- // 单图模式
|
|
|
- if (imgList.length > 0 && imgList[0].imgUrl) {
|
|
|
- formData.singleImage = imgList[0].imgUrl;
|
|
|
- } else {
|
|
|
- formData.singleImage = "";
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 多图模式
|
|
|
- if (imgList.length > 0) {
|
|
|
- formData.multipleImages = imgList.map((item: any, index: number) => ({
|
|
|
- uid: item.id || index,
|
|
|
- name: `image-${index + 1}`,
|
|
|
- url: item.imgUrl,
|
|
|
- status: "success"
|
|
|
- }));
|
|
|
- // 初始化拖拽排序
|
|
|
- nextTick(() => {
|
|
|
- initDragSort();
|
|
|
- });
|
|
|
- } else {
|
|
|
- formData.multipleImages = [];
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 如果没有数据,清空对应模式的数据
|
|
|
- if (targetMode === "single") {
|
|
|
- formData.singleImage = "";
|
|
|
- } else {
|
|
|
- formData.multipleImages = [];
|
|
|
- }
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.error(`获取${targetMode === "single" ? "单图" : "多图"}模式头图失败:`, error);
|
|
|
- // 查询失败时清空数据
|
|
|
- if (targetMode === "single") {
|
|
|
- formData.singleImage = "";
|
|
|
- } else {
|
|
|
- formData.multipleImages = [];
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 获取头图数据(初始化时同时加载单图和多图数据,用于示例图展示)
|
|
|
const getStoreHeadImgData = async () => {
|
|
|
try {
|
|
|
const userInfo: any = localGet("geeker-user")?.userInfo || {};
|
|
|
@@ -414,23 +234,9 @@ const getStoreHeadImgData = async () => {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // 同时查询单图模式(imgType: 20)和多图模式(imgType: 21)
|
|
|
- const [singleRes, multipleRes] = await Promise.all([getStoreHeadImg(storeId, 20), getStoreHeadImg(storeId, 21)]);
|
|
|
-
|
|
|
- // 处理单图数据
|
|
|
- const singleResAny: any = singleRes;
|
|
|
- if (singleResAny && (singleResAny.code === 200 || singleResAny.code === "200") && singleResAny.data) {
|
|
|
- const dataAny = singleResAny.data as any;
|
|
|
- const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
|
|
|
- if (imgList.length > 0 && imgList[0].imgUrl) {
|
|
|
- formData.singleImage = imgList[0].imgUrl;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 处理多图数据
|
|
|
- const multipleResAny: any = multipleRes;
|
|
|
- if (multipleResAny && (multipleResAny.code === 200 || multipleResAny.code === "200") && multipleResAny.data) {
|
|
|
- const dataAny = multipleResAny.data as any;
|
|
|
+ const res: any = await getStoreHeadImg(storeId, 21);
|
|
|
+ if (res && (res.code === 200 || res.code === "200") && res.data) {
|
|
|
+ const dataAny = res.data as any;
|
|
|
const imgList = Array.isArray(dataAny) ? dataAny : dataAny.storeImgList || [];
|
|
|
if (imgList.length > 0) {
|
|
|
formData.multipleImages = imgList.map((item: any, index: number) => ({
|
|
|
@@ -439,86 +245,47 @@ const getStoreHeadImgData = async () => {
|
|
|
url: item.imgUrl,
|
|
|
status: "success"
|
|
|
}));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 根据数据情况设置默认模式:优先根据imgModeActive,如果有多图则使用多图模式
|
|
|
- if (imgModeActive.value !== null && imgModeActive.value !== undefined) {
|
|
|
- // 如果后端返回了imgMode,优先使用后端返回的值
|
|
|
- // 0表示单图模式,1表示多图模式
|
|
|
- mode.value = imgModeActive.value === 0 ? "single" : "multiple";
|
|
|
- // 如果是多图模式,初始化拖拽排序
|
|
|
- if (mode.value === "multiple") {
|
|
|
nextTick(() => {
|
|
|
initDragSort();
|
|
|
});
|
|
|
}
|
|
|
- } else if (formData.multipleImages.length > 0) {
|
|
|
- // 如果有多图数据,优先显示多图模式
|
|
|
- mode.value = "multiple";
|
|
|
- // 初始化拖拽排序
|
|
|
- nextTick(() => {
|
|
|
- initDragSort();
|
|
|
- });
|
|
|
- } else if (formData.singleImage) {
|
|
|
- // 如果没有多图但有单图,显示单图模式
|
|
|
- mode.value = "single";
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("获取头图失败:", error);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
const handleDetail = async () => {
|
|
|
try {
|
|
|
- let param = {
|
|
|
+ const param = {
|
|
|
id: localGet("geeker-user")?.userInfo.storeId
|
|
|
};
|
|
|
const res: any = await getDetail(param as any);
|
|
|
if (res.code == 200) {
|
|
|
- imgModeActive.value = res.data.imgMode;
|
|
|
storeName.value = res.data.storeName;
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error("未找到用户信息:", error);
|
|
|
}
|
|
|
};
|
|
|
-// 页面初始化时获取数据
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
await handleDetail();
|
|
|
await getStoreHeadImgData();
|
|
|
-
|
|
|
- // 标记初始化完成
|
|
|
- isInitializing.value = false;
|
|
|
-
|
|
|
- // 如果默认是多图模式,初始化拖拽排序
|
|
|
- if (mode.value === "multiple") {
|
|
|
- nextTick(() => {
|
|
|
- initDragSort();
|
|
|
- });
|
|
|
- }
|
|
|
+ nextTick(() => {
|
|
|
+ initDragSort();
|
|
|
+ });
|
|
|
});
|
|
|
|
|
|
-// 保存
|
|
|
const handleSave = async () => {
|
|
|
- if (mode.value === "single") {
|
|
|
- if (!singleFormRef.value) return;
|
|
|
- try {
|
|
|
- await singleFormRef.value.validate();
|
|
|
- } catch (error) {
|
|
|
- ElMessage.warning("请完成必填项");
|
|
|
- return;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (!multipleFormRef.value) return;
|
|
|
- try {
|
|
|
- await multipleFormRef.value.validate();
|
|
|
- } catch (error) {
|
|
|
- ElMessage.warning("至少上传3张图片");
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (!multipleFormRef.value) return;
|
|
|
+ try {
|
|
|
+ await multipleFormRef.value.validate();
|
|
|
+ } catch {
|
|
|
+ ElMessage.warning("至少上传3张图片");
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- // 获取店铺ID
|
|
|
const userInfo: any = localGet("geeker-user")?.userInfo || {};
|
|
|
const storeId = userInfo.storeId;
|
|
|
if (!storeId) {
|
|
|
@@ -528,36 +295,18 @@ const handleSave = async () => {
|
|
|
|
|
|
loading.value = true;
|
|
|
try {
|
|
|
- const imgType = mode.value === "single" ? 20 : 21;
|
|
|
- let storeImgList: any[] = [];
|
|
|
-
|
|
|
- if (mode.value === "single") {
|
|
|
- // 单图模式
|
|
|
- if (formData.singleImage) {
|
|
|
- storeImgList = [
|
|
|
- {
|
|
|
- imgType: 20,
|
|
|
- imgUrl: formData.singleImage,
|
|
|
- imgSort: 1,
|
|
|
- storeId: Number(storeId)
|
|
|
- }
|
|
|
- ];
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 多图模式
|
|
|
- storeImgList = formData.multipleImages.map((item, index) => ({
|
|
|
- imgType: 21,
|
|
|
- imgUrl: item.url || "",
|
|
|
- imgSort: index + 1,
|
|
|
- storeId: Number(storeId)
|
|
|
- }));
|
|
|
- }
|
|
|
+ const storeImgList = formData.multipleImages.map((item, index) => ({
|
|
|
+ imgType: 21,
|
|
|
+ imgUrl: item.url || "",
|
|
|
+ imgSort: index + 1,
|
|
|
+ storeId: Number(storeId)
|
|
|
+ }));
|
|
|
|
|
|
const params = {
|
|
|
- imgMode: mode.value === "single" ? 0 : 1,
|
|
|
- imgType: imgType,
|
|
|
+ imgMode: 1,
|
|
|
+ imgType: 21,
|
|
|
storeId: Number(storeId),
|
|
|
- storeImgList: storeImgList
|
|
|
+ storeImgList
|
|
|
};
|
|
|
|
|
|
const result: any = await saveStoreHeadImg(params);
|
|
|
@@ -568,14 +317,6 @@ const handleSave = async () => {
|
|
|
duration: 3000
|
|
|
});
|
|
|
router.push("/home/index");
|
|
|
-
|
|
|
- // 根据返回的imgModeActive值设置当前模式
|
|
|
- // 0表示单图模式,其他值表示多图模式
|
|
|
- if (result.data && result.data.imgMode !== undefined) {
|
|
|
- mode.value = result.data.imgMode === 0 ? "single" : "multiple";
|
|
|
- } else if (imgModeActive.value !== null) {
|
|
|
- mode.value = imgModeActive.value === 0 ? "single" : "multiple";
|
|
|
- }
|
|
|
} else {
|
|
|
ElMessage.error(result?.msg || "保存失败");
|
|
|
}
|
|
|
@@ -598,59 +339,17 @@ const handleSave = async () => {
|
|
|
margin: 0 auto;
|
|
|
}
|
|
|
.mode-preview-section {
|
|
|
- display: flex;
|
|
|
- gap: 24px;
|
|
|
margin-bottom: 40px;
|
|
|
.preview-box {
|
|
|
- flex: 1;
|
|
|
- cursor: pointer;
|
|
|
- transition: all 0.3s;
|
|
|
- &.active {
|
|
|
- .preview-card {
|
|
|
- border: 2px solid #409eff;
|
|
|
- }
|
|
|
- }
|
|
|
+ width: 100%;
|
|
|
+ max-width: 560px;
|
|
|
.preview-card {
|
|
|
padding: 16px;
|
|
|
background-color: white;
|
|
|
- border: 2px solid transparent;
|
|
|
+ border: 2px solid #409eff;
|
|
|
border-radius: 8px;
|
|
|
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
|
|
transition: all 0.3s;
|
|
|
- .preview-image-large {
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- width: 100%;
|
|
|
- height: 200px;
|
|
|
- margin-bottom: 16px;
|
|
|
- overflow: hidden;
|
|
|
- background-color: #f0f0f0;
|
|
|
- border-radius: 8px;
|
|
|
- img {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- object-fit: cover;
|
|
|
- }
|
|
|
- .preview-placeholder {
|
|
|
- font-size: 14px;
|
|
|
- color: #909399;
|
|
|
- }
|
|
|
- .overlay-button {
|
|
|
- position: absolute;
|
|
|
- right: 12px;
|
|
|
- bottom: 12px;
|
|
|
- display: flex;
|
|
|
- gap: 4px;
|
|
|
- align-items: center;
|
|
|
- padding: 6px 12px;
|
|
|
- font-size: 12px;
|
|
|
- color: white;
|
|
|
- background-color: rgb(0 0 0 / 60%);
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
- }
|
|
|
.preview-images-multiple {
|
|
|
position: relative;
|
|
|
display: flex;
|