|
@@ -178,6 +178,8 @@
|
|
|
</el-card>
|
|
|
<!-- 注册 RefereeForm 组件 -->
|
|
|
<RefereeForm ref="refereeFormRef" />
|
|
|
+ <!-- 注册 BibViewerDialog 组件 -->
|
|
|
+ <BibViewerDialog ref="bibViewerDialogRef" />
|
|
|
<!-- 排行榜对话框 -->
|
|
|
<!-- <el-dialog :title="`赛事 ${currentEventId} 排行榜`" v-model="rankingBoardVisible" width="800px" append-to-body>
|
|
|
<RankingBoard :eventId="currentEventId" v-if="rankingBoardVisible" />
|
|
@@ -342,136 +344,6 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
-
|
|
|
- <!-- 生成参赛证对话框 -->
|
|
|
- <el-dialog v-model="bibDialog.visible" title="生成参赛证" width="800px" append-to-body @close="handleCloseBibDialog">
|
|
|
- <div class="bib-generator">
|
|
|
- <el-row :gutter="20">
|
|
|
- <!-- 左侧配置面板 -->
|
|
|
- <el-col :span="12">
|
|
|
- <el-form :model="bibForm" label-width="100px">
|
|
|
- <el-form-item label="背景图片">
|
|
|
- <el-upload ref="bgUploadRef" :limit="1" :auto-upload="false" :on-change="handleBgImageChange" accept="image/*" drag>
|
|
|
- <el-icon class="el-icon--upload">
|
|
|
- <i-ep-upload-filled />
|
|
|
- </el-icon>
|
|
|
- <div class="el-upload__text">拖拽背景图片到此处,或<em>点击上传</em></div>
|
|
|
- <div class="el-upload__tip">建议尺寸:842×595px (横向A4比例)</div>
|
|
|
- </el-upload>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="Logo图片">
|
|
|
- <el-upload ref="logoUploadRef" :limit="1" :auto-upload="false" :on-change="handleLogoImageChange" accept="image/*" drag>
|
|
|
- <el-icon class="el-icon--upload">
|
|
|
- <i-ep-upload-filled />
|
|
|
- </el-icon>
|
|
|
- <div class="el-upload__text">拖拽Logo图片到此处,或<em>点击上传</em></div>
|
|
|
- <div class="el-upload__tip">建议尺寸:80×80px</div>
|
|
|
- </el-upload>
|
|
|
- </el-form-item>
|
|
|
-
|
|
|
- <el-form-item label="字体设置">
|
|
|
- <div style="display: flex; gap: 15px; align-items: center">
|
|
|
- <el-select v-model="bibForm.fontName" placeholder="字体" style="width: 100px">
|
|
|
- <el-option label="黑体" value="simhei"></el-option>
|
|
|
- <el-option label="宋体" value="simsun"></el-option>
|
|
|
- <el-option label="微软雅黑" value="microsoft-yahei"></el-option>
|
|
|
- </el-select>
|
|
|
- <el-input-number v-model="bibForm.fontSize" :min="38" :max="198" placeholder="字体大小" style="width: 140px"></el-input-number>
|
|
|
- <el-color-picker v-model="bibForm.fontColor" @change="handleFontColorChange"></el-color-picker>
|
|
|
- </div>
|
|
|
- </el-form-item>
|
|
|
- </el-form>
|
|
|
- </el-col>
|
|
|
-
|
|
|
- <!-- 右侧预览面板 -->
|
|
|
- <el-col :span="12">
|
|
|
- <div class="preview-container" ref="previewContainer">
|
|
|
- <div class="preview-canvas" :style="{ backgroundImage: bgImageUrl ? `url(${bgImageUrl})` : 'none' }">
|
|
|
- <!-- Logo元素 -->
|
|
|
- <div
|
|
|
- v-if="logoImageUrl"
|
|
|
- class="draggable-element logo-element"
|
|
|
- :style="{
|
|
|
- left: bibForm.logoX + 'px',
|
|
|
- top: bibForm.logoY + 'px'
|
|
|
- }"
|
|
|
- @mousedown="startDrag($event, 'logo')"
|
|
|
- >
|
|
|
- <img :src="logoImageUrl" alt="Logo" style="max-width: 80px; max-height: 80px" />
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 示例条形码 -->
|
|
|
- <div
|
|
|
- class="draggable-element barcode-element"
|
|
|
- :style="{
|
|
|
- left: bibForm.qRCodeX + 'px',
|
|
|
- top: bibForm.qRCodeY + 'px'
|
|
|
- }"
|
|
|
- @mousedown="startDrag($event, 'barcode')"
|
|
|
- >
|
|
|
- <svg width="100" height="30" viewBox="0 0 100 30">
|
|
|
- <rect x="0" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="4" y="0" width="1" height="30" fill="black" />
|
|
|
- <rect x="7" y="0" width="3" height="30" fill="black" />
|
|
|
- <rect x="12" y="0" width="1" height="30" fill="black" />
|
|
|
- <rect x="15" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="19" y="0" width="1" height="30" fill="black" />
|
|
|
- <rect x="22" y="0" width="3" height="30" fill="black" />
|
|
|
- <rect x="27" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="31" y="0" width="1" height="30" fill="black" />
|
|
|
- <rect x="34" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="37" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="42" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="46" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="49" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="50" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="52" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="54" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="58" y="0" width="2" height="30" fill="black" />
|
|
|
- <rect x="60" y="0" width="2" height="30" fill="black" />
|
|
|
- </svg>
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 赛事名称预览 -->
|
|
|
- <div
|
|
|
- class="event-name-preview"
|
|
|
- :style="{
|
|
|
- fontSize: Math.round(bibForm.fontSize * 0.8) + 'px',
|
|
|
- color: bibForm.fontColorHex,
|
|
|
- fontFamily: bibForm.fontName
|
|
|
- }"
|
|
|
- >
|
|
|
- 赛事名称
|
|
|
- </div>
|
|
|
-
|
|
|
- <!-- 示例数字 1234 -->
|
|
|
- <div
|
|
|
- class="draggable-element number-element"
|
|
|
- :style="{
|
|
|
- left: '50%',
|
|
|
- top: '50%',
|
|
|
- transform: 'translate(-50%, -50%)',
|
|
|
- fontSize: bibForm.fontSize + 'px',
|
|
|
- color: bibForm.fontColorHex,
|
|
|
- fontFamily: bibForm.fontName
|
|
|
- }"
|
|
|
- >
|
|
|
- 1234
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </div>
|
|
|
-
|
|
|
- <template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
- <el-button @click="handleCloseBibDialog">取 消</el-button>
|
|
|
- <el-button type="primary" @click="handleGenerateBibFile" :loading="bibDialog.loading">生成参赛证</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -482,16 +354,15 @@ import {
|
|
|
delGameEvent,
|
|
|
addGameEvent,
|
|
|
updateGameEvent,
|
|
|
- generateNumberTable,
|
|
|
- generateBib,
|
|
|
- type GenerateBibBo
|
|
|
+ generateNumberTable
|
|
|
} from '@/api/system/gameEvent';
|
|
|
import { GameEventVO, GameEventQuery, GameEventForm } from '@/api/system/gameEvent/types';
|
|
|
import { getEventMdByEventAndType, editEventMd } from '@/api/system/eventMd';
|
|
|
import { EventMdVO, EventMdForm } from '@/api/system/eventMd/types';
|
|
|
import { useRouter } from 'vue-router';
|
|
|
-import { ref, nextTick } from 'vue';
|
|
|
+import { ref } from 'vue';
|
|
|
import RefereeForm from '@/views/system/gameEvent/RefereeForm.vue';
|
|
|
+import BibViewerDialog from '@/views/system/gameEvent/components/bibViewerDialog.vue';
|
|
|
import RankingBoard from './RankingBoard.vue';
|
|
|
import Editor from '@/components/Editor/index.vue';
|
|
|
import { useTagsViewStore } from '@/store/modules/tagsView';
|
|
@@ -510,6 +381,7 @@ interface RefereeFormInstance {
|
|
|
}
|
|
|
|
|
|
const refereeFormRef = ref<(InstanceType<typeof RefereeForm> & RefereeFormInstance) | null>(null);
|
|
|
+const bibViewerDialogRef = ref<InstanceType<typeof BibViewerDialog> | null>(null);
|
|
|
|
|
|
const gameEventList = ref<GameEventVO[]>([]);
|
|
|
const buttonLoading = ref(false);
|
|
@@ -1089,321 +961,15 @@ const handleExportNumberTableDefault = async () => {
|
|
|
await proxy?.download('system/number/export', {}, `号码对照表_${new Date().getTime()}.xlsx`);
|
|
|
};
|
|
|
|
|
|
-// 生成参赛证相关
|
|
|
-const bibDialog = reactive({
|
|
|
- visible: false,
|
|
|
- loading: false
|
|
|
-});
|
|
|
-
|
|
|
-const bibForm = reactive({
|
|
|
- logoX: 50,
|
|
|
- logoY: 50,
|
|
|
- qRCodeX: 100,
|
|
|
- qRCodeY: 200,
|
|
|
- fontName: 'simhei',
|
|
|
- fontSize: 36,
|
|
|
- fontColor: '#000000',
|
|
|
- fontColorHex: '#000000'
|
|
|
-});
|
|
|
-
|
|
|
-const bgImageFile = ref<File | null>(null);
|
|
|
-const logoImageFile = ref<File | null>(null);
|
|
|
-const bgImageUrl = ref<string>('');
|
|
|
-const logoImageUrl = ref<string>('');
|
|
|
-const previewContainer = ref<HTMLElement>();
|
|
|
-const bgImageDimensions = ref<{ width: number; height: number } | null>(null);
|
|
|
-const bgUploadRef = ref<ElUploadInstance>();
|
|
|
-const logoUploadRef = ref<ElUploadInstance>();
|
|
|
-
|
|
|
-// 拖拽相关
|
|
|
-const dragState = reactive({
|
|
|
- isDragging: false,
|
|
|
- dragTarget: '',
|
|
|
- startX: 0,
|
|
|
- startY: 0,
|
|
|
- startLeft: 0,
|
|
|
- startTop: 0
|
|
|
-});
|
|
|
+// 生成参赛证相关 - 已移动到 BibViewerDialog 组件中
|
|
|
|
|
|
// 生成参赛证按钮处理
|
|
|
const handleGenerateBib = () => {
|
|
|
- // 强制设置默认值,不使用条件判断(像素单位)
|
|
|
- bibForm.logoX = bibForm.logoX || 50;
|
|
|
- bibForm.logoY = bibForm.logoY || 50;
|
|
|
- bibForm.qRCodeX = bibForm.qRCodeX || 100; // 修正:使用独立的默认值
|
|
|
- bibForm.qRCodeY = bibForm.qRCodeY || 200; // 修正:使用独立的默认值
|
|
|
- bibForm.fontName = bibForm.fontName || 'simhei';
|
|
|
- bibForm.fontSize = bibForm.fontSize || 36;
|
|
|
- bibForm.fontColor = bibForm.fontColor || '#000000';
|
|
|
- bibForm.fontColorHex = bibForm.fontColorHex || '#000000';
|
|
|
- bibDialog.visible = true;
|
|
|
-};
|
|
|
-
|
|
|
-// 关闭对话框
|
|
|
-const handleCloseBibDialog = () => {
|
|
|
- bibDialog.visible = false;
|
|
|
- resetBibForm();
|
|
|
-
|
|
|
- // 清除上传的文件
|
|
|
- if (bgUploadRef.value) {
|
|
|
- bgUploadRef.value.clearFiles();
|
|
|
- }
|
|
|
- if (logoUploadRef.value) {
|
|
|
- logoUploadRef.value.clearFiles();
|
|
|
+ if (bibViewerDialogRef.value) {
|
|
|
+ bibViewerDialogRef.value.bibDialog.visible = true;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 重置表单
|
|
|
-const resetBibForm = () => {
|
|
|
- // 设置默认值(像素单位)
|
|
|
- bibForm.logoX = 50;
|
|
|
- bibForm.logoY = 50;
|
|
|
- bibForm.qRCodeX = 100;
|
|
|
- bibForm.qRCodeY = 200;
|
|
|
- bibForm.fontName = 'simhei';
|
|
|
- bibForm.fontSize = 36;
|
|
|
- bibForm.fontColor = '#000000';
|
|
|
- bibForm.fontColorHex = '#000000';
|
|
|
- bgImageFile.value = null;
|
|
|
- logoImageFile.value = null;
|
|
|
- bgImageUrl.value = '';
|
|
|
- logoImageUrl.value = '';
|
|
|
-
|
|
|
- // 清除上传的文件
|
|
|
- if (bgUploadRef.value) {
|
|
|
- bgUploadRef.value.clearFiles();
|
|
|
- }
|
|
|
- if (logoUploadRef.value) {
|
|
|
- logoUploadRef.value.clearFiles();
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 背景图片改变处理
|
|
|
-const handleBgImageChange = async (file: any) => {
|
|
|
- if (file.raw) {
|
|
|
- bgImageFile.value = file.raw;
|
|
|
- const reader = new FileReader();
|
|
|
- reader.onload = (e) => {
|
|
|
- bgImageUrl.value = e.target?.result as string;
|
|
|
- };
|
|
|
- reader.readAsDataURL(file.raw);
|
|
|
-
|
|
|
- // 获取背景图片的实际尺寸
|
|
|
- try {
|
|
|
- const dimensions = await getImageDimensions(file.raw);
|
|
|
- bgImageDimensions.value = dimensions;
|
|
|
- } catch (error) {
|
|
|
- console.error('获取图片尺寸失败:', error);
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// Logo图片改变处理
|
|
|
-const handleLogoImageChange = (file: any) => {
|
|
|
- if (file.raw) {
|
|
|
- logoImageFile.value = file.raw;
|
|
|
- const reader = new FileReader();
|
|
|
- reader.onload = (e) => {
|
|
|
- logoImageUrl.value = e.target?.result as string;
|
|
|
- };
|
|
|
- reader.readAsDataURL(file.raw);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 字体颜色改变处理
|
|
|
-const handleFontColorChange = (color: string) => {
|
|
|
- bibForm.fontColor = color;
|
|
|
- bibForm.fontColorHex = color;
|
|
|
-};
|
|
|
-
|
|
|
-// 开始拖拽
|
|
|
-const startDrag = (event: MouseEvent, target: string) => {
|
|
|
- event.preventDefault();
|
|
|
- dragState.isDragging = true;
|
|
|
- dragState.dragTarget = target;
|
|
|
- dragState.startX = event.clientX;
|
|
|
- dragState.startY = event.clientY;
|
|
|
-
|
|
|
- if (target === 'logo') {
|
|
|
- dragState.startLeft = bibForm.logoX;
|
|
|
- dragState.startTop = bibForm.logoY;
|
|
|
- } else if (target === 'barcode') {
|
|
|
- dragState.startLeft = bibForm.qRCodeX;
|
|
|
- dragState.startTop = bibForm.qRCodeY;
|
|
|
- }
|
|
|
-
|
|
|
- document.addEventListener('mousemove', handleDrag);
|
|
|
- document.addEventListener('mouseup', stopDrag);
|
|
|
-};
|
|
|
-
|
|
|
-// 处理拖拽
|
|
|
-const handleDrag = (event: MouseEvent) => {
|
|
|
- if (!dragState.isDragging) return;
|
|
|
-
|
|
|
- const deltaX = event.clientX - dragState.startX;
|
|
|
- const deltaY = event.clientY - dragState.startY;
|
|
|
-
|
|
|
- if (dragState.dragTarget === 'logo') {
|
|
|
- bibForm.logoX = Math.max(0, dragState.startLeft + deltaX);
|
|
|
- bibForm.logoY = Math.max(0, dragState.startTop + deltaY);
|
|
|
- } else if (dragState.dragTarget === 'barcode') {
|
|
|
- bibForm.qRCodeX = Math.max(0, dragState.startLeft + deltaX);
|
|
|
- bibForm.qRCodeY = Math.max(0, dragState.startTop + deltaY);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 停止拖拽
|
|
|
-const stopDrag = () => {
|
|
|
- dragState.isDragging = false;
|
|
|
- dragState.dragTarget = '';
|
|
|
- document.removeEventListener('mousemove', handleDrag);
|
|
|
- document.removeEventListener('mouseup', stopDrag);
|
|
|
-};
|
|
|
-
|
|
|
-// 坐标转换函数:根据实际背景图片尺寸调整坐标
|
|
|
-const convertCoordinatesWithScale = (x: number, y: number): { x: number; y: number } => {
|
|
|
- // 获取预览容器尺寸,使用更精确的方法
|
|
|
- const container = previewContainer.value;
|
|
|
- const previewWidth = container?.clientWidth || container?.offsetWidth || 400;
|
|
|
- const previewHeight = container?.clientHeight || container?.offsetHeight || 400;
|
|
|
-
|
|
|
- // 使用实际背景图片尺寸,如果没有则使用默认A4尺寸
|
|
|
- const actualWidth = bgImageDimensions.value?.width || 595;
|
|
|
- const actualHeight = bgImageDimensions.value?.height || 842;
|
|
|
-
|
|
|
- // 计算实际比例
|
|
|
- const scaleX = actualWidth / previewWidth;
|
|
|
- const scaleY = actualHeight / previewHeight;
|
|
|
-
|
|
|
- // 微调系数,用于补偿微小偏差
|
|
|
- const fineTuneX = 1.15; // 进一步缩小X坐标,让元素向左移动
|
|
|
- const fineTuneY = 0.9; // 进一步放大Y坐标,让元素向下移动
|
|
|
-
|
|
|
- // 根据实际效果图,需要调整坐标系统
|
|
|
- // 实际效果显示Logo在左上角,二维码在左下角
|
|
|
- const adjustedX = x * scaleX * fineTuneX;
|
|
|
- const adjustedY = (previewHeight - y) * scaleY * fineTuneY;
|
|
|
-
|
|
|
- // 添加额外的偏移量调整
|
|
|
- const offsetX = 8; // 向右偏移8pt(进一步减少向右偏移)
|
|
|
- const offsetY = 65; // 向下偏移65pt(进一步增加向下偏移)
|
|
|
-
|
|
|
- // 根据元素类型进行特殊调整
|
|
|
- let finalX = adjustedX + offsetX;
|
|
|
- let finalY = adjustedY + offsetY;
|
|
|
-
|
|
|
- // 如果是Logo,进行特殊调整
|
|
|
- if (x < 100 && y < 100) {
|
|
|
- // 假设Logo在左上角区域
|
|
|
- finalX += 5; // Logo额外向右偏移
|
|
|
- finalY -= 10; // Logo额外向下偏移
|
|
|
- }
|
|
|
-
|
|
|
- // 如果是二维码,进行特殊调整
|
|
|
- if (x > 200 && y > 200) {
|
|
|
- // 假设二维码在右下角区域
|
|
|
- finalX -= 3; // 二维码额外向左偏移
|
|
|
- finalY += 5; // 二维码额外向下偏移
|
|
|
- }
|
|
|
-
|
|
|
- return {
|
|
|
- x: finalX,
|
|
|
- y: finalY
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-// 新增:获取背景图片实际尺寸的函数
|
|
|
-const getImageDimensions = (file: File): Promise<{ width: number; height: number }> => {
|
|
|
- return new Promise((resolve) => {
|
|
|
- const img = new Image();
|
|
|
- img.onload = () => {
|
|
|
- resolve({ width: img.width, height: img.height });
|
|
|
- };
|
|
|
- img.src = URL.createObjectURL(file);
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-// 生成参赛证文件
|
|
|
-const handleGenerateBibFile = async () => {
|
|
|
- if (!bgImageFile.value) {
|
|
|
- proxy?.$modal.msgError('请上传背景图片');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- bibDialog.loading = true;
|
|
|
- try {
|
|
|
- let qRCodeX = bibForm.qRCodeX;
|
|
|
- let qRCodeY = bibForm.qRCodeY;
|
|
|
-
|
|
|
- // 如果值为null或undefined,强制使用默认值
|
|
|
- if (qRCodeX === null || qRCodeX === undefined || isNaN(qRCodeX)) {
|
|
|
- qRCodeX = 100;
|
|
|
- console.warn('qRCodeX值异常,使用默认值100px');
|
|
|
- }
|
|
|
-
|
|
|
- if (qRCodeY === null || qRCodeY === undefined || isNaN(qRCodeY)) {
|
|
|
- qRCodeY = 200;
|
|
|
- console.warn('qRCodeY值异常,使用默认值200px');
|
|
|
- }
|
|
|
-
|
|
|
- // 获取预览容器的高度用于坐标转换
|
|
|
- const containerHeight = previewContainer.value?.clientHeight || 400;
|
|
|
-
|
|
|
- // 检查背景图片尺寸
|
|
|
- if (!bgImageDimensions.value) {
|
|
|
- proxy?.$modal.msgWarning('正在获取背景图片尺寸,请稍后再试');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 等待一帧确保所有尺寸都已计算完成
|
|
|
- await nextTick();
|
|
|
-
|
|
|
- // Logo坐标(左上角)
|
|
|
- const logoCoords = convertCoordinatesWithScale(bibForm.logoX || 50, bibForm.logoY || 50);
|
|
|
-
|
|
|
- // 二维码坐标(左上角)
|
|
|
- const qrCoords = convertCoordinatesWithScale(qRCodeX, qRCodeY);
|
|
|
-
|
|
|
- const bibParams = {
|
|
|
- logoX: logoCoords.x,
|
|
|
- logoY: logoCoords.y,
|
|
|
- qRCodeX: qrCoords.x,
|
|
|
- qRCodeY: qrCoords.y,
|
|
|
- fontName: bibForm.fontName || 'simhei',
|
|
|
- fontSize: Math.round((bibForm.fontSize || 36) * 0.75), // 字体大小转换为PDF点并四舍五入为整数
|
|
|
- fontColor: parseInt((bibForm.fontColor || '#000000').replace('#', ''), 16)
|
|
|
- };
|
|
|
-
|
|
|
- // 最后一次检查,确保二维码坐标不为null
|
|
|
- if (bibParams.qRCodeX === null || bibParams.qRCodeY === undefined) {
|
|
|
- bibParams.qRCodeX = 148.75; // 100px * 1.4875
|
|
|
- console.error('最后一次修复:qRCodeX仍为null,设置为100px转换后的值');
|
|
|
- }
|
|
|
- if (bibParams.qRCodeY === null || bibParams.qRCodeY === undefined) {
|
|
|
- bibParams.qRCodeY = 421; // 200px * 2.105
|
|
|
- console.error('最后一次修复:qRCodeY仍为null,设置为200px转换后的值');
|
|
|
- }
|
|
|
-
|
|
|
- const response = await generateBib(bgImageFile.value, logoImageFile.value, bibParams);
|
|
|
-
|
|
|
- // 处理文件下载 - response已经是blob数据,不需要再访问.data属性
|
|
|
- const blob = new Blob([response as any], { type: 'application/zip' });
|
|
|
- const url = window.URL.createObjectURL(blob);
|
|
|
- const link = document.createElement('a');
|
|
|
- link.href = url;
|
|
|
- link.download = `参赛证_${new Date().getTime()}.zip`;
|
|
|
- link.click();
|
|
|
- window.URL.revokeObjectURL(url);
|
|
|
-
|
|
|
- proxy?.$modal.msgSuccess('参赛证生成成功');
|
|
|
- handleCloseBibDialog();
|
|
|
- } catch (error) {
|
|
|
- console.error('生成参赛证失败:', error);
|
|
|
- proxy?.$modal.msgError('生成参赛证失败');
|
|
|
- } finally {
|
|
|
- bibDialog.loading = false;
|
|
|
- }
|
|
|
-};
|
|
|
|
|
|
onMounted(() => {
|
|
|
// 获取默认赛事信息
|
|
@@ -1452,86 +1018,6 @@ onActivated(() => {
|
|
|
justify-content: center;
|
|
|
}
|
|
|
|
|
|
-/* 生成参赛证样式 */
|
|
|
-.bib-generator {
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.bib-generator .el-upload__tip {
|
|
|
- color: #909399;
|
|
|
- font-size: 12px;
|
|
|
- margin-top: 8px;
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-container {
|
|
|
- border: 2px dashed #ddd;
|
|
|
- border-radius: 8px;
|
|
|
- min-height: 400px;
|
|
|
- position: relative;
|
|
|
- overflow: hidden;
|
|
|
-}
|
|
|
-
|
|
|
-.preview-canvas {
|
|
|
- width: 100%;
|
|
|
- height: 400px;
|
|
|
- position: relative;
|
|
|
- background-size: cover;
|
|
|
- background-position: center;
|
|
|
- background-repeat: no-repeat;
|
|
|
- background-color: #f5f5f5;
|
|
|
-}
|
|
|
-
|
|
|
-.draggable-element {
|
|
|
- position: absolute;
|
|
|
- cursor: move;
|
|
|
- user-select: none;
|
|
|
- z-index: 10;
|
|
|
-}
|
|
|
-
|
|
|
-.draggable-element:hover {
|
|
|
- opacity: 0.8;
|
|
|
-}
|
|
|
-
|
|
|
-.logo-element {
|
|
|
- border: 2px dashed transparent;
|
|
|
-}
|
|
|
-
|
|
|
-.logo-element:hover {
|
|
|
- border-color: #409eff;
|
|
|
-}
|
|
|
-
|
|
|
-.barcode-element {
|
|
|
- border: 2px dashed transparent;
|
|
|
- padding: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.barcode-element:hover {
|
|
|
- border-color: #67c23a;
|
|
|
- background-color: rgba(103, 194, 58, 0.1);
|
|
|
-}
|
|
|
-
|
|
|
-.number-element {
|
|
|
- font-weight: bold;
|
|
|
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
|
|
- border: 2px dashed transparent;
|
|
|
- padding: 5px;
|
|
|
- white-space: nowrap;
|
|
|
- user-select: none;
|
|
|
- pointer-events: none;
|
|
|
-}
|
|
|
-
|
|
|
-.event-name-preview {
|
|
|
- position: absolute;
|
|
|
- top: 20px;
|
|
|
- left: 50%;
|
|
|
- transform: translateX(-50%);
|
|
|
- font-weight: bold;
|
|
|
- text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
|
|
- user-select: none;
|
|
|
- pointer-events: none;
|
|
|
- z-index: 5;
|
|
|
-}
|
|
|
|
|
|
.operation-buttons .el-button:hover {
|
|
|
transform: translateY(-1px);
|