|
|
@@ -0,0 +1,725 @@
|
|
|
+<template>
|
|
|
+ <div class="p-2">
|
|
|
+ <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
|
|
+ <div v-show="showSearch" class="mb-[10px]">
|
|
|
+ <el-card shadow="hover">
|
|
|
+ <el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
|
|
+ <el-form-item label="图片名称" prop="imageName">
|
|
|
+ <el-input v-model="queryParams.imageName" placeholder="请输入图片名称" clearable @keyup.enter="handleQuery" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="图片类型" prop="imageType">
|
|
|
+ <el-select v-model="queryParams.imageType" placeholder="请选择图片类型" clearable style="width: 180px">
|
|
|
+ <el-option label="背景图" value="background" />
|
|
|
+ <el-option label="图标" value="icon" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="使用场景" prop="sceneType">
|
|
|
+ <el-select v-model="queryParams.sceneType" placeholder="请选择使用场景" clearable style="width: 180px">
|
|
|
+ <el-option label="线上" value="online" />
|
|
|
+ <el-option label="线下" value="offline" />
|
|
|
+ <el-option label="通用" value="both" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="状态" prop="status">
|
|
|
+ <el-select v-model="queryParams.status" placeholder="请选择状态" clearable style="width: 120px">
|
|
|
+ <el-option label="启用" value="enabled" />
|
|
|
+ <el-option label="禁用" value="disabled" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item>
|
|
|
+ <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
|
|
+ <el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </transition>
|
|
|
+
|
|
|
+ <el-card shadow="never">
|
|
|
+ <template #header>
|
|
|
+ <el-row :gutter="10" class="mb8">
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['physical:tournamentImage:add']">上传图片</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['physical:tournamentImage:edit']">修改</el-button>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="1.5">
|
|
|
+ <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['physical:tournamentImage:remove']">删除</el-button>
|
|
|
+ </el-col>
|
|
|
+ <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
|
|
+ </el-row>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <el-table v-loading="loading" border :data="tournamentImageList" @selection-change="handleSelectionChange">
|
|
|
+ <el-table-column type="selection" width="55" align="center" />
|
|
|
+ <el-table-column label="编号" align="center" prop="id" width="70" />
|
|
|
+ <el-table-column label="图片预览" align="center" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-image
|
|
|
+ v-if="scope.row.imageUrl"
|
|
|
+ :src="scope.row.imageUrl"
|
|
|
+ style="width: 50px; height: 50px; border-radius: 4px; cursor: zoom-in"
|
|
|
+ :preview-src-list="[scope.row.imageUrl]"
|
|
|
+ :preview-teleported="true"
|
|
|
+ fit="cover"
|
|
|
+ />
|
|
|
+ <span v-else></span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="图片名称" align="center" prop="imageName" min-width="150" show-overflow-tooltip />
|
|
|
+ <el-table-column label="图片类型" align="center" prop="imageType" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag v-if="scope.row.imageType === 'background'" type="warning">背景图</el-tag>
|
|
|
+ <el-tag v-else-if="scope.row.imageType === 'icon'" type="success">图标</el-tag>
|
|
|
+ <span v-else>{{ scope.row.imageType }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="使用场景" align="center" prop="sceneType" width="100">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tag v-if="scope.row.sceneType === 'online'" type="primary">线上</el-tag>
|
|
|
+ <el-tag v-else-if="scope.row.sceneType === 'offline'" type="info">线下</el-tag>
|
|
|
+ <el-tag v-else-if="scope.row.sceneType === 'both'" type="success">通用</el-tag>
|
|
|
+ <span v-else>{{ scope.row.sceneType }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="状态" align="center" prop="status" width="80">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-switch
|
|
|
+ v-model="scope.row.status"
|
|
|
+ active-value="enabled"
|
|
|
+ inactive-value="disabled"
|
|
|
+ @change="handleStatusChange(scope.row)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+
|
|
|
+ <el-table-column label="创建时间" align="center" prop="createTime" width="170">
|
|
|
+ <template #default="scope">
|
|
|
+ <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" align="center" width="120" class-name="small-padding fixed-width">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-tooltip content="修改" placement="top">
|
|
|
+ <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['physical:tournamentImage:edit']"></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ <el-tooltip content="删除" placement="top">
|
|
|
+ <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['physical:tournamentImage:remove']"></el-button>
|
|
|
+ </el-tooltip>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
|
|
+ </el-card>
|
|
|
+
|
|
|
+ <!-- 添加或修改赛事图片对话框 -->
|
|
|
+ <el-dialog :title="dialog.title" v-model="dialog.visible" width="600px" append-to-body @close="handleDialogClose">
|
|
|
+ <el-form ref="tournamentImageFormRef" :model="form" :rules="rules" label-width="100px">
|
|
|
+ <!-- 基本信息区域 -->
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="图片名称" prop="imageName">
|
|
|
+ <el-input
|
|
|
+ v-model="form.imageName"
|
|
|
+ placeholder="请输入自定义名称(如:篮球赛事图标)"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="图片类型" prop="imageType">
|
|
|
+ <el-select v-model="form.imageType" placeholder="请选择图片类型" style="width: 100%">
|
|
|
+ <el-option label="背景图" value="background" />
|
|
|
+ <el-option label="图标" value="icon" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="使用场景" prop="sceneType">
|
|
|
+ <el-select v-model="form.sceneType" placeholder="请选择使用场景" style="width: 100%">
|
|
|
+ <el-option label="线上赛事" value="online" />
|
|
|
+ <el-option label="线下赛事" value="offline" />
|
|
|
+ <el-option label="通用(线上线下均可)" value="both" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="状态" prop="status">
|
|
|
+ <el-radio-group v-model="form.status">
|
|
|
+ <el-radio value="enabled">启用</el-radio>
|
|
|
+ <el-radio value="disabled">禁用</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 图片预览和上传区域 -->
|
|
|
+ <el-form-item label="图片">
|
|
|
+ <div v-if="form.imageUrl || imagePreviewUrl" class="image-upload-wrapper">
|
|
|
+ <div class="image-preview-container">
|
|
|
+ <img :src="imagePreviewUrl || form.imageUrl" alt="预览图" class="preview-image" />
|
|
|
+ <div class="image-actions">
|
|
|
+ <el-button link type="primary" size="small" @click="handlePreviewClick(null)">查看大图</el-button>
|
|
|
+ <el-button link type="warning" size="small" @click="handleClearImage">更换图片</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-upload
|
|
|
+ ref="modifyUploadRef"
|
|
|
+ v-else
|
|
|
+ drag
|
|
|
+ :auto-upload="false"
|
|
|
+ :on-change="handleModifyFileChange"
|
|
|
+ :limit="1"
|
|
|
+ accept="image/*"
|
|
|
+ class="image-upload-area"
|
|
|
+ >
|
|
|
+ <el-icon class="upload-icon"><UploadFilled /></el-icon>
|
|
|
+ <div class="upload-text">
|
|
|
+ <p>将文件拖到此处,或<em>点击上传</em></p>
|
|
|
+ <p class="upload-tip">只能上传 jpg/png 文件,且不超过 5MB</p>
|
|
|
+ </div>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
|
|
+ <el-button @click="cancel">取 消</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 上传图片对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ v-model="uploadDialogVisible"
|
|
|
+ title="上传赛事图片"
|
|
|
+ width="500px"
|
|
|
+ append-to-body
|
|
|
+ @close="resetUploadForm"
|
|
|
+ >
|
|
|
+ <el-form ref="uploadFormRef" :model="uploadForm" :rules="uploadRules" label-width="80px">
|
|
|
+ <el-form-item label="图片名称" prop="imageName">
|
|
|
+ <el-input v-model="uploadForm.imageName" placeholder="请输入图片名称" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="图片类型" prop="imageType">
|
|
|
+ <el-select v-model="uploadForm.imageType" placeholder="请选择" style="width: 100%">
|
|
|
+ <el-option label="图标" value="icon" />
|
|
|
+ <el-option label="背景图" value="background" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="使用场景" prop="sceneType">
|
|
|
+ <el-select v-model="uploadForm.sceneType" placeholder="请选择" style="width: 100%">
|
|
|
+ <el-option label="线上" value="online" />
|
|
|
+ <el-option label="线下" value="offline" />
|
|
|
+ <el-option label="通用" value="both" />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="状态" prop="status">
|
|
|
+ <el-switch v-model="uploadForm.status" active-value="enabled" inactive-value="disabled" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="上传图片" prop="file">
|
|
|
+ <el-upload
|
|
|
+ ref="uploadRef"
|
|
|
+ drag
|
|
|
+ action="#"
|
|
|
+ :auto-upload="false"
|
|
|
+ :on-change="handleFileChange"
|
|
|
+ :limit="1"
|
|
|
+ accept="image/*"
|
|
|
+ >
|
|
|
+ <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
|
|
|
+ <div class="el-upload__text">
|
|
|
+ 将文件拖到此处,或<em>点击上传</em>
|
|
|
+ </div>
|
|
|
+ <template #tip>
|
|
|
+ <div class="el-upload__tip">只能上传jpg/png文件,且不超过5MB</div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button @click="uploadDialogVisible = false">取 消</el-button>
|
|
|
+ <el-button type="primary" :loading="uploadLoading" @click="submitUpload">确 定</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 图片预览弹窗 -->
|
|
|
+ <el-dialog v-model="previewDialog.visible" title="图片预览" width="50%" append-to-body>
|
|
|
+ <img :src="previewDialog.src" alt="预览图片" style="max-width: 100%; max-height: 70vh; display: block; margin: 0 auto" />
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup name="TournamentImage" lang="ts">
|
|
|
+import {
|
|
|
+ listTournamentImage,
|
|
|
+ getTournamentImage,
|
|
|
+ delTournamentImage,
|
|
|
+ addTournamentImage,
|
|
|
+ updateTournamentImage
|
|
|
+} from '@/api/system/physical/tournamentImage';
|
|
|
+import { TournamentImageVO, TournamentImageQuery, TournamentImageForm } from '@/api/system/physical/tournamentImage/types';
|
|
|
+import { UploadFilled, Picture } from '@element-plus/icons-vue';
|
|
|
+import request from '@/utils/request';
|
|
|
+import { uploadTournament } from '@/api/system/business/tournaments';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+
|
|
|
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
+
|
|
|
+const tournamentImageList = ref<TournamentImageVO[]>([]);
|
|
|
+const buttonLoading = ref(false);
|
|
|
+const loading = ref(true);
|
|
|
+const showSearch = ref(true);
|
|
|
+const ids = ref<Array<string | number>>([]);
|
|
|
+const single = ref(true);
|
|
|
+const multiple = ref(true);
|
|
|
+const total = ref(0);
|
|
|
+
|
|
|
+const queryFormRef = ref<ElFormInstance>();
|
|
|
+const tournamentImageFormRef = ref<ElFormInstance>();
|
|
|
+const modifyUploadRef = ref(); // 修改对话框的上传组件引用
|
|
|
+const imagePreviewUrl = ref('');
|
|
|
+
|
|
|
+// 上传相关
|
|
|
+const uploadDialogVisible = ref(false);
|
|
|
+const uploadLoading = ref(false);
|
|
|
+const uploadFormRef = ref();
|
|
|
+const uploadRef = ref();
|
|
|
+const uploadFile = ref<File | null>(null);
|
|
|
+const modifyUploadFile = ref<File | null>(null); // 修改对话框的文件
|
|
|
+const uploadForm = reactive<TournamentImageForm>({
|
|
|
+ imageName: '',
|
|
|
+ imageUrl: '',
|
|
|
+ imageType: 'icon',
|
|
|
+ sceneType: 'online',
|
|
|
+ status: 'enabled'
|
|
|
+});
|
|
|
+const uploadRules = {
|
|
|
+ imageName: [{ required: true, message: '请输入图片名称', trigger: 'blur' }],
|
|
|
+ imageType: [{ required: true, message: '请选择图片类型', trigger: 'change' }],
|
|
|
+ sceneType: [{ required: true, message: '请选择使用场景', trigger: 'change' }]
|
|
|
+};
|
|
|
+
|
|
|
+const previewDialog = reactive({
|
|
|
+ visible: false,
|
|
|
+ src: ''
|
|
|
+});
|
|
|
+
|
|
|
+const dialog = reactive<DialogOption>({
|
|
|
+ visible: false,
|
|
|
+ title: ''
|
|
|
+});
|
|
|
+
|
|
|
+const initFormData: TournamentImageForm = {
|
|
|
+ id: undefined,
|
|
|
+ imageName: undefined,
|
|
|
+ imageUrl: undefined,
|
|
|
+ imageType: undefined,
|
|
|
+ sceneType: undefined,
|
|
|
+ sortOrder: 0,
|
|
|
+ status: 'enabled',
|
|
|
+ remark: undefined,
|
|
|
+ createTime: undefined,
|
|
|
+ updateTime: undefined
|
|
|
+};
|
|
|
+
|
|
|
+const data = reactive<PageData<TournamentImageForm, TournamentImageQuery>>({
|
|
|
+ form: { ...initFormData },
|
|
|
+ queryParams: {
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ imageName: undefined,
|
|
|
+ imageType: undefined,
|
|
|
+ sceneType: undefined,
|
|
|
+ status: undefined,
|
|
|
+ params: {}
|
|
|
+ },
|
|
|
+ rules: {
|
|
|
+ imageName: [{ required: true, message: '图片名称不能为空', trigger: 'blur' }],
|
|
|
+ imageUrl: [{ required: true, message: '请上传图片', trigger: 'change' }],
|
|
|
+ imageType: [{ required: true, message: '请选择图片类型', trigger: 'change' }],
|
|
|
+ sceneType: [{ required: true, message: '请选择使用场景', trigger: 'change' }],
|
|
|
+ status: [{ required: true, message: '请选择状态', trigger: 'change' }]
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const { queryParams, form, rules } = toRefs(data);
|
|
|
+
|
|
|
+/** 查询赛事图片列表 */
|
|
|
+// TODO: 获取分页数据并更新列表
|
|
|
+const getList = async () => {
|
|
|
+ loading.value = true;
|
|
|
+ const res = await listTournamentImage(queryParams.value);
|
|
|
+ tournamentImageList.value = res.rows;
|
|
|
+ total.value = res.total;
|
|
|
+ loading.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+/** 取消按钮 */
|
|
|
+// TODO: 重置表单并关闭对话框
|
|
|
+const cancel = () => {
|
|
|
+ reset();
|
|
|
+ dialog.visible = false;
|
|
|
+};
|
|
|
+
|
|
|
+/** 表单重置 */
|
|
|
+const reset = () => {
|
|
|
+ form.value = { ...initFormData };
|
|
|
+ tournamentImageFormRef.value?.resetFields();
|
|
|
+ imagePreviewUrl.value = '';
|
|
|
+ modifyUploadFile.value = null; // 清空修改对话框的文件
|
|
|
+ if (modifyUploadRef.value) {
|
|
|
+ modifyUploadRef.value.clearFiles(); // 清空上传组件
|
|
|
+ }
|
|
|
+ // 恢复 imageUrl 的验证规则
|
|
|
+ rules.value.imageUrl = [{ required: true, message: '请上传图片', trigger: 'change' }];
|
|
|
+};
|
|
|
+
|
|
|
+/** 对话框关闭 */
|
|
|
+const handleDialogClose = () => {
|
|
|
+ reset();
|
|
|
+ // 清空表单验证错误
|
|
|
+ tournamentImageFormRef.value?.clearValidate();
|
|
|
+};
|
|
|
+
|
|
|
+/** 搜索按钮操作 */
|
|
|
+// TODO: 执行查询并重置页码为1
|
|
|
+const handleQuery = () => {
|
|
|
+ queryParams.value.pageNum = 1;
|
|
|
+ getList();
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置按钮操作 */
|
|
|
+const resetQuery = () => {
|
|
|
+ queryFormRef.value?.resetFields();
|
|
|
+ handleQuery();
|
|
|
+};
|
|
|
+
|
|
|
+/** 多选框选中数据 */
|
|
|
+const handleSelectionChange = (selection: TournamentImageVO[]) => {
|
|
|
+ ids.value = selection.map((item) => item.id);
|
|
|
+ single.value = selection.length != 1;
|
|
|
+ multiple.value = !selection.length;
|
|
|
+};
|
|
|
+
|
|
|
+/** 新增按钮操作 */
|
|
|
+// TODO: 打开上传图片对话框
|
|
|
+const handleAdd = () => {
|
|
|
+ reset();
|
|
|
+ // 打开上传对话框
|
|
|
+ openUploadDialog();
|
|
|
+};
|
|
|
+
|
|
|
+/** 打开上传对话框 */
|
|
|
+const openUploadDialog = () => {
|
|
|
+ uploadForm.imageType = 'icon'; // 默认图标类型
|
|
|
+ uploadForm.sceneType = 'online'; // 默认线上场景
|
|
|
+ uploadForm.status = 'enabled'; // 默认启用
|
|
|
+ uploadDialogVisible.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+/** 重置上传表单 */
|
|
|
+const resetUploadForm = () => {
|
|
|
+ uploadFormRef.value?.resetFields();
|
|
|
+ uploadForm.imageName = '';
|
|
|
+ uploadForm.imageUrl = '';
|
|
|
+ uploadForm.imageType = 'icon';
|
|
|
+ uploadForm.sceneType = 'online';
|
|
|
+ uploadForm.status = 'enabled';
|
|
|
+ uploadFile.value = null;
|
|
|
+ if (uploadRef.value) {
|
|
|
+ uploadRef.value.clearFiles();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 处理文件选择 */
|
|
|
+const handleFileChange = (file: any) => {
|
|
|
+ uploadFile.value = file.raw;
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交上传 */
|
|
|
+const submitUpload = async () => {
|
|
|
+ const valid = await uploadFormRef.value?.validate().catch(() => false);
|
|
|
+ if (!valid) return;
|
|
|
+
|
|
|
+ if (!uploadFile.value) {
|
|
|
+ ElMessage.warning('请选择要上传的图片');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ uploadLoading.value = true;
|
|
|
+ try {
|
|
|
+ // 先上传到 OSS
|
|
|
+ const ossRes = await uploadTournament(uploadFile.value);
|
|
|
+ if (ossRes.code !== 200) {
|
|
|
+ throw new Error(ossRes.msg || '上传失败');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置图片 URL
|
|
|
+ uploadForm.imageUrl = ossRes.data.url;
|
|
|
+
|
|
|
+ // 判断是从修改对话框还是新增按钮调用的
|
|
|
+ // 如果 form.id 存在,说明是从修改对话框调用的(更换图片)
|
|
|
+ if (form.value.id) {
|
|
|
+ // 从修改对话框调用:只更新当前表单的图片 URL
|
|
|
+ form.value.imageUrl = ossRes.data.url;
|
|
|
+ form.value.imageName = uploadForm.imageName;
|
|
|
+ form.value.imageType = uploadForm.imageType;
|
|
|
+ form.value.sceneType = uploadForm.sceneType;
|
|
|
+ form.value.status = uploadForm.status;
|
|
|
+
|
|
|
+ uploadDialogVisible.value = false;
|
|
|
+ ElMessage.success('图片更换成功');
|
|
|
+ } else {
|
|
|
+ // 从新增按钮调用:保存新图片
|
|
|
+ const res = await addTournamentImage(uploadForm);
|
|
|
+ if (res.code === 200) {
|
|
|
+ ElMessage.success('上传成功');
|
|
|
+ uploadDialogVisible.value = false;
|
|
|
+ // 重新加载列表
|
|
|
+ getList();
|
|
|
+ } else {
|
|
|
+ throw new Error(res.msg || '保存失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('上传失败', error);
|
|
|
+ ElMessage.error(error.message || '上传失败,请重试');
|
|
|
+ } finally {
|
|
|
+ uploadLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 修改按钮操作 */
|
|
|
+// TODO: 加载详情数据并打开编辑对话框
|
|
|
+const handleUpdate = async (row?: TournamentImageVO) => {
|
|
|
+ reset();
|
|
|
+ const _id = row?.id || ids.value[0];
|
|
|
+ const res = await getTournamentImage(_id);
|
|
|
+ Object.assign(form.value, res.data);
|
|
|
+ // 确保 imageUrl 被正确赋值
|
|
|
+ if (res.data.imageUrl) {
|
|
|
+ form.value.imageUrl = res.data.imageUrl;
|
|
|
+ imagePreviewUrl.value = res.data.imageUrl;
|
|
|
+ }
|
|
|
+ // 清空修改对话框的文件
|
|
|
+ modifyUploadFile.value = null;
|
|
|
+ dialog.visible = true;
|
|
|
+ dialog.title = '修改赛事图片';
|
|
|
+};
|
|
|
+
|
|
|
+/** 提交按钮 */
|
|
|
+const submitForm = () => {
|
|
|
+ // 如果是修改模式,临时移除 imageUrl 的必填验证
|
|
|
+ const isUpdateMode = !!form.value.id;
|
|
|
+ if (isUpdateMode) {
|
|
|
+ // 修改模式:不需要验证 imageUrl(因为图片已存在)
|
|
|
+ rules.value.imageUrl = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ tournamentImageFormRef.value?.validate(async (valid: boolean) => {
|
|
|
+ if (valid) {
|
|
|
+ buttonLoading.value = true;
|
|
|
+ try {
|
|
|
+ if (form.value.id) {
|
|
|
+ // 修改模式:如果有新图片,先上传
|
|
|
+ let imageUrl = form.value.imageUrl;
|
|
|
+
|
|
|
+ if (modifyUploadFile.value) {
|
|
|
+ // 先上传到 OSS
|
|
|
+ const ossRes = await uploadTournament(modifyUploadFile.value);
|
|
|
+ if (ossRes.code !== 200) {
|
|
|
+ throw new Error(ossRes.msg || '上传图片失败');
|
|
|
+ }
|
|
|
+ imageUrl = ossRes.data.url; // 使用新图片 URL
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新基本信息和新图片 URL
|
|
|
+ await updateTournamentImage({
|
|
|
+ id: form.value.id,
|
|
|
+ imageName: form.value.imageName, // 直接使用用户输入的名称
|
|
|
+ imageType: form.value.imageType,
|
|
|
+ sceneType: form.value.sceneType,
|
|
|
+ status: form.value.status,
|
|
|
+ imageUrl: imageUrl // 新图片 URL 或原图片 URL
|
|
|
+ }).finally(() => {
|
|
|
+ buttonLoading.value = false;
|
|
|
+ dialog.visible = false;
|
|
|
+ getList();
|
|
|
+ });
|
|
|
+ proxy?.$modal.msgSuccess('修改成功');
|
|
|
+ } else {
|
|
|
+ // 新增模式:需要包含所有字段
|
|
|
+ await addTournamentImage({
|
|
|
+ imageName: form.value.imageName,
|
|
|
+ imageUrl: form.value.imageUrl,
|
|
|
+ imageType: form.value.imageType,
|
|
|
+ sceneType: form.value.sceneType,
|
|
|
+ status: form.value.status
|
|
|
+ }).finally(() => {
|
|
|
+ buttonLoading.value = false;
|
|
|
+ dialog.visible = false;
|
|
|
+ getList();
|
|
|
+ });
|
|
|
+ proxy?.$modal.msgSuccess('添加成功');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('提交失败:', error);
|
|
|
+ proxy?.$modal.msgError('操作失败,请重试');
|
|
|
+ buttonLoading.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/** 删除按钮操作 */
|
|
|
+const handleDelete = async (row?: TournamentImageVO) => {
|
|
|
+ const _ids = row?.id || ids.value;
|
|
|
+ await proxy?.$modal.confirm('是否确认删除赛事图片编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
|
|
|
+ await delTournamentImage(_ids);
|
|
|
+ proxy?.$modal.msgSuccess('删除成功');
|
|
|
+ await getList();
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/** 状态变更 */
|
|
|
+const handleStatusChange = async (row: TournamentImageVO) => {
|
|
|
+ const statusText = row.status === 'enabled' ? '启用' : '禁用';
|
|
|
+ try {
|
|
|
+ await updateTournamentImage({
|
|
|
+ id: row.id,
|
|
|
+ status: row.status
|
|
|
+ } as TournamentImageForm);
|
|
|
+ proxy?.$modal.msgSuccess(`${statusText}成功`);
|
|
|
+ } catch {
|
|
|
+ proxy?.$modal.msgError(`${statusText}失败`);
|
|
|
+ await getList();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 清除图片(更换图片时调用) */
|
|
|
+const handleClearImage = () => {
|
|
|
+ // 清空 URL
|
|
|
+ form.value.imageUrl = undefined;
|
|
|
+ imagePreviewUrl.value = '';
|
|
|
+ modifyUploadFile.value = null;
|
|
|
+ if (modifyUploadRef.value) {
|
|
|
+ modifyUploadRef.value.clearFiles();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 处理修改对话框文件选择 */
|
|
|
+const handleModifyFileChange = (file: any) => {
|
|
|
+ modifyUploadFile.value = file.raw;
|
|
|
+ // 预览图片
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = (e: any) => {
|
|
|
+ imagePreviewUrl.value = e.target.result;
|
|
|
+ };
|
|
|
+ if (file.raw) {
|
|
|
+ reader.readAsDataURL(file.raw);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+/** 更换图片(删除旧方法,改为直接在下方上传区域操作) */
|
|
|
+// const handleReplaceImage = () => { ... }; // 已删除
|
|
|
+
|
|
|
+/** 图片预览 */
|
|
|
+const handlePreviewClick = (file?: any) => {
|
|
|
+ const currentSrc = imagePreviewUrl.value || form.value.imageUrl;
|
|
|
+ if (currentSrc) {
|
|
|
+ previewDialog.src = currentSrc;
|
|
|
+ previewDialog.visible = true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ getList();
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.image-upload-wrapper {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.image-preview-container {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ gap: 15px;
|
|
|
+ padding: 20px;
|
|
|
+ border: 1px dashed #dcdfe6;
|
|
|
+ border-radius: 8px;
|
|
|
+ background-color: #fafafa;
|
|
|
+}
|
|
|
+
|
|
|
+.preview-image {
|
|
|
+ max-width: 250px;
|
|
|
+ max-height: 200px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 8px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
+}
|
|
|
+
|
|
|
+.image-actions {
|
|
|
+ display: flex;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+
|
|
|
+.image-upload-area {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-icon {
|
|
|
+ font-size: 48px;
|
|
|
+ color: #c0c4cc;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-text {
|
|
|
+ margin-top: 15px;
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+
|
|
|
+ p {
|
|
|
+ margin: 5px 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .upload-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.upload-container {
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.upload-trigger {
|
|
|
+ padding: 30px 20px;
|
|
|
+ text-align: center;
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+.el-upload-tip {
|
|
|
+ margin-top: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.el-form-item__label) {
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+</style>
|