|
|
@@ -0,0 +1,1086 @@
|
|
|
+<template>
|
|
|
+ <!-- 运营活动管理 - 新增/编辑页面 -->
|
|
|
+ <div class="table-box" style="width: 100%; min-height: 100%; background-color: white">
|
|
|
+ <div class="header">
|
|
|
+ <el-button @click="goBack"> 返回 </el-button>
|
|
|
+ <h2 class="title">{{ type == "add" ? "新建" : "编辑" }}运营活动</h2>
|
|
|
+ </div>
|
|
|
+ <div class="form-wrapper">
|
|
|
+ <div class="form-wrapper-main">
|
|
|
+ <el-form ref="ruleFormRef" :model="activityModel" :rules="rules" class="formBox" label-width="140px">
|
|
|
+ <div class="form-content">
|
|
|
+ <!-- 活动名称 -->
|
|
|
+ <el-form-item label="活动名称" prop="activityName">
|
|
|
+ <el-input v-model="activityModel.activityName" class="form-input" clearable maxlength="50" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 活动时间 -->
|
|
|
+ <el-form-item class="activity-time-item" label="活动时间" prop="activityTimeRange">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="activityModel.activityTimeRange"
|
|
|
+ :disabled-date="disabledDate"
|
|
|
+ class="form-input"
|
|
|
+ end-placeholder="结束日期"
|
|
|
+ format="YYYY/MM/DD"
|
|
|
+ range-separator="-"
|
|
|
+ start-placeholder="开始日期"
|
|
|
+ type="daterange"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 用户可参与次数 -->
|
|
|
+ <el-form-item label="用户可参与次数" prop="participationLimit">
|
|
|
+ <el-input v-model="activityModel.participationLimit" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 活动规则 -->
|
|
|
+ <el-form-item label="活动规则" prop="activityRule">
|
|
|
+ <el-cascader
|
|
|
+ v-model="activityModel.activityRule"
|
|
|
+ :options="ruleCascaderOptions"
|
|
|
+ :props="cascaderProps"
|
|
|
+ class="form-input"
|
|
|
+ clearable
|
|
|
+ placeholder="请选择"
|
|
|
+ style="width: 100%"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 优惠券 -->
|
|
|
+ <el-form-item label="优惠券" prop="couponId">
|
|
|
+ <el-select v-model="activityModel.couponId" class="form-input" clearable filterable placeholder="请选择">
|
|
|
+ <el-option v-for="item in couponList" :key="item.id" :label="item.name" :value="item.id" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 优惠券发放数量 -->
|
|
|
+ <el-form-item label="优惠券发放数量" prop="couponQuantity">
|
|
|
+ <el-input v-model="activityModel.couponQuantity" placeholder="请输入" />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 活动标题图 -->
|
|
|
+ <el-form-item label="活动标题图" prop="activityTitleImage">
|
|
|
+ <div class="upload-item-wrapper">
|
|
|
+ <div class="upload-area upload-area-horizontal-21-9" :class="{ 'upload-full': titleFileList.length >= 1 }">
|
|
|
+ <el-upload
|
|
|
+ v-model:file-list="titleFileList"
|
|
|
+ :accept="'.jpg,.jpeg,.png'"
|
|
|
+ :auto-upload="false"
|
|
|
+ :before-remove="handleBeforeRemove"
|
|
|
+ :disabled="hasUnuploadedImages"
|
|
|
+ :limit="1"
|
|
|
+ :on-change="handleTitleUploadChange"
|
|
|
+ :on-exceed="handleUploadExceed"
|
|
|
+ :on-preview="handlePictureCardPreview"
|
|
|
+ :on-remove="handleTitleRemove"
|
|
|
+ :show-file-list="true"
|
|
|
+ list-type="picture-card"
|
|
|
+ >
|
|
|
+ <template #trigger>
|
|
|
+ <div v-if="titleFileList.length < 1" class="upload-trigger-card el-upload--picture-card">
|
|
|
+ <el-icon>
|
|
|
+ <Plus />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <div class="upload-hint">请上传21:9尺寸图片效果更佳,支持jpg、jpeg、png格式,上传图片不得超过20M</div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 活动详情图 -->
|
|
|
+ <el-form-item label="活动详情图" prop="activityDetailImage">
|
|
|
+ <div class="upload-item-wrapper">
|
|
|
+ <div class="upload-area upload-area-vertical" :class="{ 'upload-full': detailFileList.length >= 1 }">
|
|
|
+ <el-upload
|
|
|
+ v-model:file-list="detailFileList"
|
|
|
+ :accept="'.jpg,.jpeg,.png'"
|
|
|
+ :auto-upload="false"
|
|
|
+ :before-remove="handleBeforeRemove"
|
|
|
+ :disabled="hasUnuploadedImages"
|
|
|
+ :limit="1"
|
|
|
+ :on-change="handleDetailUploadChange"
|
|
|
+ :on-exceed="handleUploadExceed"
|
|
|
+ :on-preview="handlePictureCardPreview"
|
|
|
+ :on-remove="handleDetailRemove"
|
|
|
+ :show-file-list="true"
|
|
|
+ list-type="picture-card"
|
|
|
+ >
|
|
|
+ <template #trigger>
|
|
|
+ <div v-if="detailFileList.length < 1" class="upload-trigger-card el-upload--picture-card">
|
|
|
+ <el-icon>
|
|
|
+ <Plus />
|
|
|
+ </el-icon>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </div>
|
|
|
+ <div class="upload-hint">请上传竖版图片,支持jpg、jpeg、png格式,上传图片不得超过20M</div>
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 底部按钮区域 -->
|
|
|
+ <div class="button-container">
|
|
|
+ <el-button @click="goBack"> 取消 </el-button>
|
|
|
+ <el-button type="primary" @click="handleSubmit()"> 提交审核 </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 图片预览 -->
|
|
|
+ <el-image-viewer
|
|
|
+ v-if="imageViewerVisible"
|
|
|
+ :initial-index="imageViewerInitialIndex"
|
|
|
+ :url-list="imageViewerUrlList"
|
|
|
+ @close="imageViewerVisible = false"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="tsx" name="newActivity" setup>
|
|
|
+/**
|
|
|
+ * 运营活动管理 - 新增/编辑页面
|
|
|
+ * 功能:支持运营活动的新增和编辑操作
|
|
|
+ */
|
|
|
+import { computed, nextTick, onMounted, reactive, ref } from "vue";
|
|
|
+import type { FormInstance, UploadFile, UploadProps } from "element-plus";
|
|
|
+import { ElMessage, ElMessageBox } from "element-plus";
|
|
|
+import { Plus } from "@element-plus/icons-vue";
|
|
|
+import { useRoute, useRouter } from "vue-router";
|
|
|
+import {
|
|
|
+ addActivity,
|
|
|
+ getActivityDetail,
|
|
|
+ getActivityRuleOptions,
|
|
|
+ getCouponList,
|
|
|
+ updateActivity
|
|
|
+} from "@/api/modules/operationManagement";
|
|
|
+import { uploadContractImage } from "@/api/modules/licenseManagement";
|
|
|
+import { localGet } from "@/utils";
|
|
|
+
|
|
|
+// ==================== 响应式数据定义 ====================
|
|
|
+
|
|
|
+// 路由相关
|
|
|
+const router = useRouter();
|
|
|
+const route = useRoute();
|
|
|
+
|
|
|
+// 页面状态
|
|
|
+const type = ref<string>(""); // 页面类型:add-新增, edit-编辑
|
|
|
+const id = ref<string>(""); // 页面ID参数
|
|
|
+
|
|
|
+// 表单引用
|
|
|
+const ruleFormRef = ref<FormInstance>();
|
|
|
+
|
|
|
+// 优惠券列表
|
|
|
+const couponList = ref<any[]>([]);
|
|
|
+
|
|
|
+// 文件上传相关
|
|
|
+const titleFileList = ref<UploadFile[]>([]);
|
|
|
+const detailFileList = ref<UploadFile[]>([]);
|
|
|
+const titleImageUrl = ref<string>("");
|
|
|
+const detailImageUrl = ref<string>("");
|
|
|
+const pendingUploadFiles = ref<UploadFile[]>([]);
|
|
|
+const uploading = ref(false);
|
|
|
+const imageViewerVisible = ref(false);
|
|
|
+const imageViewerUrlList = ref<string[]>([]);
|
|
|
+const imageViewerInitialIndex = ref(0);
|
|
|
+
|
|
|
+// 活动规则级联选择器选项
|
|
|
+const ruleCascaderOptions = ref<any[]>([]);
|
|
|
+
|
|
|
+// 级联选择器配置
|
|
|
+const cascaderProps = {
|
|
|
+ expandTrigger: "hover" as const,
|
|
|
+ emitPath: true,
|
|
|
+ disabled: (data: any) => {
|
|
|
+ // 除了 "当用户 > 核销并评论 > 优惠券" 这个路径,其余选项不可选择
|
|
|
+ if (data.disabled !== undefined) {
|
|
|
+ return data.disabled;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 是否有未上传的图片
|
|
|
+const hasUnuploadedImages = computed(() => {
|
|
|
+ return (
|
|
|
+ titleFileList.value.some(file => file.status === "ready" || file.status === "uploading") ||
|
|
|
+ detailFileList.value.some(file => file.status === "ready" || file.status === "uploading")
|
|
|
+ );
|
|
|
+});
|
|
|
+
|
|
|
+// ==================== 表单验证规则 ====================
|
|
|
+const rules = reactive({
|
|
|
+ activityName: [{ required: true, message: "请输入活动名称", trigger: "blur" }],
|
|
|
+ activityTimeRange: [
|
|
|
+ { required: true, message: "请选择活动时间", trigger: "change" },
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (!value || !Array.isArray(value) || value.length !== 2) {
|
|
|
+ callback(new Error("请选择活动时间"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const [startTime, endTime] = value;
|
|
|
+ if (!startTime || !endTime) {
|
|
|
+ callback(new Error("请选择完整的活动时间"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const start = new Date(startTime);
|
|
|
+ const end = new Date(endTime);
|
|
|
+ const today = new Date();
|
|
|
+ today.setHours(0, 0, 0, 0);
|
|
|
+ if (start < today) {
|
|
|
+ callback(new Error("活动开始时间不能早于当前时间"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (start >= end) {
|
|
|
+ callback(new Error("活动开始时间必须早于活动结束时间"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: "change"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ participationLimit: [
|
|
|
+ { required: true, message: "请输入用户可参与次数", trigger: "blur" },
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ const numValue = Number(value);
|
|
|
+ if (isNaN(numValue) || !Number.isInteger(numValue) || numValue <= 0) {
|
|
|
+ callback(new Error("用户可参与次数必须为正整数"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (numValue >= 10000) {
|
|
|
+ callback(new Error("用户可参与次数必须小于10000"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: "blur"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ activityRule: [
|
|
|
+ { required: true, message: "请选择活动规则", trigger: "change" },
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (!value || !Array.isArray(value) || value.length < 2) {
|
|
|
+ callback(new Error("请选择完整的活动规则(至少选择角色和行为)"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: "change"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ couponId: [{ required: true, message: "请选择优惠券", trigger: "change" }],
|
|
|
+ couponQuantity: [
|
|
|
+ { required: true, message: "请输入优惠券发放数量", trigger: "blur" },
|
|
|
+ {
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ const numValue = Number(value);
|
|
|
+ if (isNaN(numValue) || !Number.isInteger(numValue) || numValue <= 0) {
|
|
|
+ callback(new Error("优惠券发放数量必须为正整数"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (numValue >= 10000) {
|
|
|
+ callback(new Error("优惠券发放数量必须小于10000"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: "blur"
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ activityTitleImage: [
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (!titleImageUrl.value) {
|
|
|
+ callback(new Error("请上传活动标题图"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: ["change", "blur"]
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ activityDetailImage: [
|
|
|
+ {
|
|
|
+ required: true,
|
|
|
+ validator: (rule: any, value: any, callback: any) => {
|
|
|
+ if (!detailImageUrl.value) {
|
|
|
+ callback(new Error("请上传活动详情图"));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ callback();
|
|
|
+ },
|
|
|
+ trigger: ["change", "blur"]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+});
|
|
|
+
|
|
|
+// ==================== 活动信息数据模型 ====================
|
|
|
+const activityModel = ref<any>({
|
|
|
+ // 活动宣传图(包含标题和详情)
|
|
|
+ promotionImages: null,
|
|
|
+ // 活动标题图片
|
|
|
+ activityTitleImg: null,
|
|
|
+ // 活动详情图片
|
|
|
+ activityDetailImg: null,
|
|
|
+ // 活动标题图(用于表单验证)
|
|
|
+ activityTitleImage: null,
|
|
|
+ // 活动详情图(用于表单验证)
|
|
|
+ activityDetailImage: null,
|
|
|
+ // 活动名称
|
|
|
+ activityName: "",
|
|
|
+ // 活动时间范围
|
|
|
+ activityTimeRange: [],
|
|
|
+ // 用户可参与次数
|
|
|
+ participationLimit: "",
|
|
|
+ // 活动规则(级联选择器的值数组)
|
|
|
+ activityRule: [],
|
|
|
+ // 优惠券ID
|
|
|
+ couponId: "",
|
|
|
+ // 优惠券发放数量
|
|
|
+ couponQuantity: ""
|
|
|
+});
|
|
|
+
|
|
|
+// ==================== 日期选择器禁用规则 ====================
|
|
|
+
|
|
|
+// 禁用日期(不能早于今天)
|
|
|
+const disabledDate = (time: Date) => {
|
|
|
+ const today = new Date();
|
|
|
+ today.setHours(0, 0, 0, 0);
|
|
|
+ return time.getTime() < today.getTime();
|
|
|
+};
|
|
|
+
|
|
|
+// ==================== 图片参数转换函数 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 图片URL转换为upload组件的参数
|
|
|
+ * @param imageUrl 图片URL
|
|
|
+ * @returns UploadFile对象
|
|
|
+ */
|
|
|
+const handleImageParam = (imageUrl: string): UploadFile => {
|
|
|
+ // 使用split方法以'/'为分隔符将URL拆分成数组
|
|
|
+ const parts = imageUrl.split("/");
|
|
|
+ // 取数组的最后一项,即图片名称
|
|
|
+ const imageName = parts[parts.length - 1];
|
|
|
+ return {
|
|
|
+ uid: Date.now() + Math.random(),
|
|
|
+ name: imageName,
|
|
|
+ status: "success",
|
|
|
+ percentage: 100,
|
|
|
+ url: imageUrl
|
|
|
+ } as unknown as UploadFile;
|
|
|
+};
|
|
|
+
|
|
|
+// ==================== 文件上传相关函数 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 检查文件是否在排队中(未上传)
|
|
|
+ */
|
|
|
+const isFilePending = (file: any): boolean => {
|
|
|
+ if (file.status === "ready") {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (pendingUploadFiles.value.some(item => item.uid === file.uid)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 图片上传 - 删除前确认
|
|
|
+ */
|
|
|
+const handleBeforeRemove = async (uploadFile: any, uploadFiles: any[]): Promise<boolean> => {
|
|
|
+ if (isFilePending(uploadFile)) {
|
|
|
+ ElMessage.warning("图片尚未上传,请等待上传完成后再删除");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm("确定要删除这张图片吗?", "提示", {
|
|
|
+ confirmButtonText: "确定",
|
|
|
+ cancelButtonText: "取消",
|
|
|
+ type: "warning"
|
|
|
+ });
|
|
|
+ return true;
|
|
|
+ } catch {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动标题图片上传 - 移除图片回调
|
|
|
+ */
|
|
|
+const handleTitleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
|
|
|
+ const file = uploadFile as any;
|
|
|
+ const imageUrl = file.url;
|
|
|
+
|
|
|
+ if (imageUrl) {
|
|
|
+ titleImageUrl.value = "";
|
|
|
+ activityModel.value.activityTitleImg = null;
|
|
|
+ activityModel.value.activityTitleImage = null;
|
|
|
+ // 触发表单验证
|
|
|
+ nextTick(() => {
|
|
|
+ ruleFormRef.value?.validateField("activityTitleImage");
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (file.url && file.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(file.url);
|
|
|
+ }
|
|
|
+ titleFileList.value = [...uploadFiles];
|
|
|
+ ElMessage.success("图片已删除");
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动详情图片上传 - 移除图片回调
|
|
|
+ */
|
|
|
+const handleDetailRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
|
|
|
+ const file = uploadFile as any;
|
|
|
+ const imageUrl = file.url;
|
|
|
+
|
|
|
+ if (imageUrl) {
|
|
|
+ detailImageUrl.value = "";
|
|
|
+ activityModel.value.activityDetailImg = null;
|
|
|
+ activityModel.value.activityDetailImage = null;
|
|
|
+ // 触发表单验证
|
|
|
+ nextTick(() => {
|
|
|
+ ruleFormRef.value?.validateField("activityDetailImage");
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (file.url && file.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(file.url);
|
|
|
+ }
|
|
|
+ detailFileList.value = [...uploadFiles];
|
|
|
+ ElMessage.success("图片已删除");
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 上传文件超出限制提示
|
|
|
+ */
|
|
|
+const handleUploadExceed: UploadProps["onExceed"] = () => {
|
|
|
+ ElMessage.warning("最多只能上传1张图片");
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动标题图片上传 - 文件变更
|
|
|
+ */
|
|
|
+const handleTitleUploadChange: UploadProps["onChange"] = async (uploadFile, uploadFiles) => {
|
|
|
+ if (uploadFile.raw) {
|
|
|
+ const fileType = uploadFile.raw.type.toLowerCase();
|
|
|
+ const fileName = uploadFile.name.toLowerCase();
|
|
|
+ const validTypes = ["image/jpeg", "image/jpg", "image/png"];
|
|
|
+ const validExtensions = [".jpg", ".jpeg", ".png"];
|
|
|
+
|
|
|
+ const isValidType = validTypes.includes(fileType) || validExtensions.some(ext => fileName.endsWith(ext));
|
|
|
+
|
|
|
+ if (!isValidType) {
|
|
|
+ // 从文件列表中移除不符合类型的文件
|
|
|
+ const index = titleFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ titleFileList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+ // 从 uploadFiles 中移除
|
|
|
+ const uploadIndex = uploadFiles.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (uploadIndex > -1) {
|
|
|
+ uploadFiles.splice(uploadIndex, 1);
|
|
|
+ }
|
|
|
+ // 如果文件有 blob URL,释放它
|
|
|
+ if (uploadFile.url && uploadFile.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(uploadFile.url);
|
|
|
+ }
|
|
|
+ ElMessage.warning("只支持上传 JPG、JPEG 和 PNG 格式的图片");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查文件大小,不得超过20M
|
|
|
+ const maxSize = 20 * 1024 * 1024; // 20MB
|
|
|
+ if (uploadFile.raw.size > maxSize) {
|
|
|
+ // 从文件列表中移除超过大小的文件
|
|
|
+ const index = titleFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ titleFileList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+ // 从 uploadFiles 中移除
|
|
|
+ const uploadIndex = uploadFiles.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (uploadIndex > -1) {
|
|
|
+ uploadFiles.splice(uploadIndex, 1);
|
|
|
+ }
|
|
|
+ // 如果文件有 blob URL,释放它
|
|
|
+ if (uploadFile.url && uploadFile.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(uploadFile.url);
|
|
|
+ }
|
|
|
+ ElMessage.warning("上传图片不得超过20M");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const existingIndex = titleFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (existingIndex === -1) {
|
|
|
+ titleFileList.value.push(uploadFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ const readyFiles = titleFileList.value.filter(file => file.status === "ready");
|
|
|
+ if (readyFiles.length) {
|
|
|
+ readyFiles.forEach(file => {
|
|
|
+ if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
|
|
|
+ pendingUploadFiles.value.push(file);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ processUploadQueue("title");
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 活动详情图片上传 - 文件变更
|
|
|
+ */
|
|
|
+const handleDetailUploadChange: UploadProps["onChange"] = async (uploadFile, uploadFiles) => {
|
|
|
+ if (uploadFile.raw) {
|
|
|
+ const fileType = uploadFile.raw.type.toLowerCase();
|
|
|
+ const fileName = uploadFile.name.toLowerCase();
|
|
|
+ const validTypes = ["image/jpeg", "image/jpg", "image/png"];
|
|
|
+ const validExtensions = [".jpg", ".jpeg", ".png"];
|
|
|
+
|
|
|
+ const isValidType = validTypes.includes(fileType) || validExtensions.some(ext => fileName.endsWith(ext));
|
|
|
+
|
|
|
+ if (!isValidType) {
|
|
|
+ // 从文件列表中移除不符合类型的文件
|
|
|
+ const index = detailFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ detailFileList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+ // 从 uploadFiles 中移除
|
|
|
+ const uploadIndex = uploadFiles.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (uploadIndex > -1) {
|
|
|
+ uploadFiles.splice(uploadIndex, 1);
|
|
|
+ }
|
|
|
+ // 如果文件有 blob URL,释放它
|
|
|
+ if (uploadFile.url && uploadFile.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(uploadFile.url);
|
|
|
+ }
|
|
|
+ ElMessage.warning("只支持上传 JPG、JPEG 和 PNG 格式的图片");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查文件大小,不得超过20M
|
|
|
+ const maxSize = 20 * 1024 * 1024; // 20MB
|
|
|
+ if (uploadFile.raw.size > maxSize) {
|
|
|
+ // 从文件列表中移除超过大小的文件
|
|
|
+ const index = detailFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ detailFileList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+ // 从 uploadFiles 中移除
|
|
|
+ const uploadIndex = uploadFiles.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (uploadIndex > -1) {
|
|
|
+ uploadFiles.splice(uploadIndex, 1);
|
|
|
+ }
|
|
|
+ // 如果文件有 blob URL,释放它
|
|
|
+ if (uploadFile.url && uploadFile.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(uploadFile.url);
|
|
|
+ }
|
|
|
+ ElMessage.warning("上传图片不得超过20M");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const existingIndex = detailFileList.value.findIndex((f: any) => f.uid === uploadFile.uid);
|
|
|
+ if (existingIndex === -1) {
|
|
|
+ detailFileList.value.push(uploadFile);
|
|
|
+ }
|
|
|
+
|
|
|
+ const readyFiles = detailFileList.value.filter(file => file.status === "ready");
|
|
|
+ if (readyFiles.length) {
|
|
|
+ readyFiles.forEach(file => {
|
|
|
+ if (!pendingUploadFiles.value.some(item => item.uid === file.uid)) {
|
|
|
+ pendingUploadFiles.value.push(file);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ processUploadQueue("detail");
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 处理上传队列 - 逐个上传文件
|
|
|
+ */
|
|
|
+const processUploadQueue = async (type: string) => {
|
|
|
+ if (uploading.value || pendingUploadFiles.value.length === 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const file = pendingUploadFiles.value.shift();
|
|
|
+ if (file) {
|
|
|
+ await uploadSingleFile(file, type);
|
|
|
+ processUploadQueue(type);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 单文件上传图片
|
|
|
+ */
|
|
|
+const uploadSingleFile = async (file: UploadFile, uploadType: string) => {
|
|
|
+ if (!file.raw) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const rawFile = file.raw as File;
|
|
|
+ const formData = new FormData();
|
|
|
+ formData.append("file", rawFile);
|
|
|
+ formData.append("user", "text");
|
|
|
+ file.status = "uploading";
|
|
|
+ file.percentage = 0;
|
|
|
+ uploading.value = true;
|
|
|
+
|
|
|
+ try {
|
|
|
+ const result: any = await uploadContractImage(formData);
|
|
|
+ if (result?.code === 200 && result.data) {
|
|
|
+ let imageUrl = result.data[0];
|
|
|
+ if (!imageUrl) {
|
|
|
+ throw new Error("上传成功但未获取到图片URL");
|
|
|
+ }
|
|
|
+
|
|
|
+ file.status = "success";
|
|
|
+ file.percentage = 100;
|
|
|
+ file.url = imageUrl;
|
|
|
+ file.response = { url: imageUrl };
|
|
|
+
|
|
|
+ if (uploadType === "title") {
|
|
|
+ titleImageUrl.value = imageUrl;
|
|
|
+ activityModel.value.activityTitleImg = { url: imageUrl };
|
|
|
+ activityModel.value.activityTitleImage = imageUrl;
|
|
|
+ // 触发表单验证
|
|
|
+ nextTick(() => {
|
|
|
+ ruleFormRef.value?.validateField("activityTitleImage");
|
|
|
+ });
|
|
|
+ } else if (uploadType === "detail") {
|
|
|
+ detailImageUrl.value = imageUrl;
|
|
|
+ activityModel.value.activityDetailImg = { url: imageUrl };
|
|
|
+ activityModel.value.activityDetailImage = imageUrl;
|
|
|
+ // 触发表单验证
|
|
|
+ nextTick(() => {
|
|
|
+ ruleFormRef.value?.validateField("activityDetailImage");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new Error(result?.msg || "图片上传失败");
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ // 上传失败时保持进度条为 0
|
|
|
+ file.percentage = 0;
|
|
|
+ // 不要设置 file.status = "fail",直接移除文件,避免显示错误占位图
|
|
|
+ if (file.url && file.url.startsWith("blob:")) {
|
|
|
+ URL.revokeObjectURL(file.url);
|
|
|
+ }
|
|
|
+ // 从文件列表中移除失败的文件
|
|
|
+ const index =
|
|
|
+ uploadType === "title"
|
|
|
+ ? titleFileList.value.findIndex((f: any) => f.uid === file.uid)
|
|
|
+ : detailFileList.value.findIndex((f: any) => f.uid === file.uid);
|
|
|
+ if (index > -1) {
|
|
|
+ if (uploadType === "title") {
|
|
|
+ titleFileList.value.splice(index, 1);
|
|
|
+ } else {
|
|
|
+ detailFileList.value.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Error message handled by global upload method, except for specific business logic errors
|
|
|
+ if (error?.message && error.message.includes("未获取到图片URL")) {
|
|
|
+ ElMessage.error(error.message);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ uploading.value = false;
|
|
|
+ // 触发视图更新
|
|
|
+ if (uploadType === "title") {
|
|
|
+ titleFileList.value = [...titleFileList.value];
|
|
|
+ } else {
|
|
|
+ detailFileList.value = [...detailFileList.value];
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 图片预览
|
|
|
+ */
|
|
|
+const handlePictureCardPreview = (file: any) => {
|
|
|
+ if (isFilePending(file)) {
|
|
|
+ ElMessage.warning("图片尚未上传,请等待上传完成后再预览");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (file.status === "uploading" && file.url) {
|
|
|
+ imageViewerUrlList.value = [file.url];
|
|
|
+ imageViewerInitialIndex.value = 0;
|
|
|
+ imageViewerVisible.value = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const allFiles = [...titleFileList.value, ...detailFileList.value];
|
|
|
+ const urlList = allFiles
|
|
|
+ .filter((item: any) => item.status === "success" && (item.url || item.response?.data))
|
|
|
+ .map((item: any) => item.url || item.response?.data);
|
|
|
+ const currentIndex = urlList.findIndex((url: string) => url === (file.url || file.response?.data));
|
|
|
+ if (currentIndex < 0) {
|
|
|
+ ElMessage.warning("图片尚未上传完成,无法预览");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ imageViewerUrlList.value = urlList;
|
|
|
+ imageViewerInitialIndex.value = currentIndex;
|
|
|
+ imageViewerVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+// ==================== 生命周期钩子 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 组件挂载时初始化
|
|
|
+ */
|
|
|
+onMounted(async () => {
|
|
|
+ id.value = (route.query.id as string) || "";
|
|
|
+ type.value = (route.query.type as string) || "";
|
|
|
+
|
|
|
+ // 加载优惠券列表
|
|
|
+ try {
|
|
|
+ const params = {
|
|
|
+ storeId: localGet("createdId"),
|
|
|
+ groupType: localGet("businessSection"),
|
|
|
+ couponType: "2",
|
|
|
+ couponStatus: "1",
|
|
|
+ couponsFromType: 1,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 99999
|
|
|
+ };
|
|
|
+ const res: any = await getCouponList(params);
|
|
|
+ if (res && res.code == 200) {
|
|
|
+ couponList.value = res.data?.discountList?.records || [];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("加载优惠券列表失败:", error);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加载活动规则级联选择器选项
|
|
|
+ try {
|
|
|
+ const res: any = await getActivityRuleOptions();
|
|
|
+ console.log("ruleCascaderOptions:", res.data);
|
|
|
+ if (res && res.code == 200) {
|
|
|
+ ruleCascaderOptions.value = res.data || [];
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("加载活动规则选项失败:", error);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 编辑模式下加载数据
|
|
|
+ if (type.value != "add" && id.value) {
|
|
|
+ try {
|
|
|
+ const res: any = await getActivityDetail({ id: id.value });
|
|
|
+ if (res && res.code == 200) {
|
|
|
+ activityModel.value = { ...activityModel.value, ...res.data };
|
|
|
+ // 处理活动时间范围
|
|
|
+ if (res.data.startTime && res.data.endTime) {
|
|
|
+ activityModel.value.activityTimeRange = [res.data.startTime, res.data.endTime];
|
|
|
+ }
|
|
|
+ // 如果有标题图片,添加到文件列表
|
|
|
+ if (res.data.activityTitleImgUrl) {
|
|
|
+ const titleImgUrl = res.data.activityTitleImgUrl;
|
|
|
+ if (titleImgUrl) {
|
|
|
+ titleImageUrl.value = titleImgUrl;
|
|
|
+ activityModel.value.activityTitleImg = res.data.activityTitleImgUrl;
|
|
|
+ activityModel.value.activityTitleImage = titleImgUrl;
|
|
|
+ const titleFile = handleImageParam(titleImgUrl);
|
|
|
+ titleFileList.value = [titleFile];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 如果有详情图片,添加到文件列表
|
|
|
+ if (res.data.activityDetailImgUrl) {
|
|
|
+ const detailImgUrl = res.data.activityDetailImgUrl;
|
|
|
+ if (detailImgUrl) {
|
|
|
+ detailImageUrl.value = detailImgUrl;
|
|
|
+ activityModel.value.activityDetailImg = res.data.activityDetailImgUrl;
|
|
|
+ activityModel.value.activityDetailImage = detailImgUrl;
|
|
|
+ const detailFile = handleImageParam(detailImgUrl);
|
|
|
+ detailFileList.value = [detailFile];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 加载活动规则
|
|
|
+ if (res.data.activityRule) {
|
|
|
+ activityModel.value.activityRule = res.data.activityRule.split(",");
|
|
|
+ } else {
|
|
|
+ activityModel.value.activityRule = [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("加载活动详情失败:", error);
|
|
|
+ ElMessage.error("加载活动详情失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ await nextTick();
|
|
|
+ ruleFormRef.value?.clearValidate();
|
|
|
+});
|
|
|
+
|
|
|
+// ==================== 事件处理函数 ====================
|
|
|
+
|
|
|
+/**
|
|
|
+ * 返回上一页
|
|
|
+ */
|
|
|
+const goBack = () => {
|
|
|
+ router.go(-1);
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 提交表单
|
|
|
+ */
|
|
|
+const handleSubmit = async () => {
|
|
|
+ if (!ruleFormRef.value) return;
|
|
|
+
|
|
|
+ // 如果有未上传的图片,阻止提交
|
|
|
+ if (hasUnuploadedImages.value) {
|
|
|
+ ElMessage.warning("请等待图片上传完成后再提交");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ await ruleFormRef.value.validate(async valid => {
|
|
|
+ if (valid) {
|
|
|
+ const [startTime, endTime] = activityModel.value.activityTimeRange || [];
|
|
|
+ const params: any = {
|
|
|
+ activityName: activityModel.value.activityName,
|
|
|
+ startTime: startTime,
|
|
|
+ endTime: endTime,
|
|
|
+ participationLimit: activityModel.value.participationLimit,
|
|
|
+ activityRule: activityModel.value.activityRule.join(","),
|
|
|
+ couponId: activityModel.value.couponId,
|
|
|
+ couponQuantity: activityModel.value.couponQuantity,
|
|
|
+ activityTitleImg: {
|
|
|
+ imgUrl: titleImageUrl.value,
|
|
|
+ imgSort: 0,
|
|
|
+ storeId: localGet("createdId")
|
|
|
+ },
|
|
|
+ activityDetailImg: {
|
|
|
+ imgUrl: detailImageUrl.value,
|
|
|
+ imgSort: 0,
|
|
|
+ storeId: localGet("createdId")
|
|
|
+ },
|
|
|
+ storeId: localGet("createdId"),
|
|
|
+ groupType: localGet("businessSection"),
|
|
|
+ status: 1 // 1-待审核
|
|
|
+ };
|
|
|
+
|
|
|
+ try {
|
|
|
+ let res: any;
|
|
|
+ if (type.value == "add") {
|
|
|
+ res = await addActivity(params);
|
|
|
+ } else {
|
|
|
+ params.id = id.value;
|
|
|
+ res = await updateActivity(params);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res && res.code == 200) {
|
|
|
+ ElMessage.success(type.value == "add" ? "新增成功" : "编辑成功");
|
|
|
+ goBack();
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res?.msg || "操作失败");
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error("提交失败:", error);
|
|
|
+ ElMessage.error("操作失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+/* 页面容器 */
|
|
|
+.table-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: auto !important;
|
|
|
+ min-height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+/* 头部区域 */
|
|
|
+.header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 20px 24px;
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
+ box-shadow: 0 2px 4px rgb(0 0 0 / 2%);
|
|
|
+}
|
|
|
+.title {
|
|
|
+ flex: 1;
|
|
|
+ margin: 0;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单内容区域 */
|
|
|
+.form-content {
|
|
|
+ padding: 24px;
|
|
|
+ background-color: #ffffff;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表单包装器 */
|
|
|
+.form-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ background-color: #ffffff;
|
|
|
+ .form-wrapper-main {
|
|
|
+ width: 100%;
|
|
|
+ max-width: 800px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 上传项容器 */
|
|
|
+.upload-item-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 12px;
|
|
|
+ align-items: flex-start;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+.upload-hint {
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 1.5;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+/* 规则表格容器 */
|
|
|
+.rule-table-container {
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+/* 底部按钮区域 */
|
|
|
+.button-container {
|
|
|
+ display: flex;
|
|
|
+ gap: 20px;
|
|
|
+ justify-content: center;
|
|
|
+ padding-bottom: 15px;
|
|
|
+ background-color: #ffffff;
|
|
|
+}
|
|
|
+.upload-area {
|
|
|
+ width: 100%;
|
|
|
+ :deep(.el-upload--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ height: 180px;
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ .el-upload-list__item {
|
|
|
+ width: 100%;
|
|
|
+ height: 180px;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label) {
|
|
|
+ display: inline-flex !important;
|
|
|
+ opacity: 1 !important;
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list__item.is-success:focus .el-upload-list__item-status-label) {
|
|
|
+ display: inline-flex !important;
|
|
|
+ opacity: 1 !important;
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list--picture-card .el-icon--close-tip) {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+ &.upload-full {
|
|
|
+ :deep(.el-upload--picture-card) {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 21:9横向图片样式
|
|
|
+ &.upload-area-horizontal-21-9 {
|
|
|
+ :deep(.el-upload--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ aspect-ratio: 21 / 9;
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ .el-upload-list__item {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ aspect-ratio: 21 / 9;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 竖版图片样式
|
|
|
+ &.upload-area-vertical {
|
|
|
+ max-width: 300px;
|
|
|
+ :deep(.el-upload--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ height: 400px;
|
|
|
+ aspect-ratio: 3 / 4;
|
|
|
+ }
|
|
|
+ :deep(.el-upload-list--picture-card) {
|
|
|
+ width: 100%;
|
|
|
+ .el-upload-list__item {
|
|
|
+ width: 100%;
|
|
|
+ height: 400px;
|
|
|
+ aspect-ratio: 3 / 4;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.upload-trigger-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ font-size: 28px;
|
|
|
+ color: #8c939d;
|
|
|
+}
|
|
|
+
|
|
|
+/* el-upload 图片预览铺满容器 */
|
|
|
+:deep(.el-upload-list--picture-card) {
|
|
|
+ .el-upload-list__item {
|
|
|
+ margin: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ .el-upload-list__item-thumbnail {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ object-fit: fill;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-upload-list__item[data-status="ready"],
|
|
|
+ .el-upload-list__item.is-ready {
|
|
|
+ position: relative;
|
|
|
+ pointer-events: none;
|
|
|
+ cursor: not-allowed;
|
|
|
+ opacity: 0.6;
|
|
|
+ &::after {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
+ z-index: 1;
|
|
|
+ content: "";
|
|
|
+ background-color: rgb(0 0 0 / 30%);
|
|
|
+ }
|
|
|
+ .el-upload-list__item-actions {
|
|
|
+ pointer-events: none;
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .el-upload-list__item:hover .el-upload-list__item-status-label {
|
|
|
+ display: inline-flex !important;
|
|
|
+ opacity: 1 !important;
|
|
|
+ }
|
|
|
+ .el-upload-list__item.is-success:focus .el-upload-list__item-status-label {
|
|
|
+ display: inline-flex !important;
|
|
|
+ opacity: 1 !important;
|
|
|
+ }
|
|
|
+ .el-icon--close-tip {
|
|
|
+ display: none !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|