|
@@ -1,43 +1,171 @@
|
|
<template>
|
|
<template>
|
|
<!-- 生成参赛证对话框 -->
|
|
<!-- 生成参赛证对话框 -->
|
|
- <el-dialog v-model="bibDialog.visible" title="生成参赛证" width="800px" append-to-body @close="handleCloseBibDialog">
|
|
|
|
|
|
+ <el-dialog v-model="bibDialog.visible" title="生成参赛证" width="900px" append-to-body @close="handleCloseBibDialog">
|
|
<div class="bib-generator">
|
|
<div class="bib-generator">
|
|
- <el-row :gutter="20">
|
|
|
|
- <!-- 左侧配置面板 -->
|
|
|
|
- <el-col :span="12">
|
|
|
|
- <el-form :model="bibForm" label-width="100px">
|
|
|
|
- <el-form-item label="背景图片" required>
|
|
|
|
- <div class="upload-container">
|
|
|
|
- <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">图片将自动调整为3:2横屏比例,建议尺寸:600×400px</div>
|
|
|
|
|
|
+ <!-- 预览面板 - 占满宽度 -->
|
|
|
|
+ <div class="preview-container" ref="previewContainer">
|
|
|
|
+ <div class="preview-canvas" :style="{
|
|
|
|
+ backgroundImage: bgImageUrl ? `url(${bgImageUrl})` : 'none',
|
|
|
|
+ backgroundSize: '100% 100%',
|
|
|
|
+ backgroundRepeat: 'no-repeat',
|
|
|
|
+ transform: `scale(${canvasScale})`,
|
|
|
|
+ transformOrigin: 'center center'
|
|
|
|
+ }">
|
|
|
|
+ <!-- Logo元素 -->
|
|
|
|
+ <div
|
|
|
|
+ v-if="logoImageUrl"
|
|
|
|
+ class="draggable-element logo-element"
|
|
|
|
+ :style="{
|
|
|
|
+ left: bibForm.logoX + '%',
|
|
|
|
+ top: bibForm.logoY + '%',
|
|
|
|
+ transform: `translateX(-50%) scale(${bibForm.logoScale})`,
|
|
|
|
+ transformOrigin: 'top left'
|
|
|
|
+ }"
|
|
|
|
+ @mousedown="startDrag($event, 'logo')"
|
|
|
|
+ @click="selectedElement = 'logo'"
|
|
|
|
+ :class="{ selected: selectedElement === 'logo' }"
|
|
|
|
+ >
|
|
|
|
+ <img :src="logoImageUrl" alt="Logo" style="max-width: 80px; max-height: 80px" />
|
|
|
|
+ </div>
|
|
|
|
+ <!-- 示例条形码 -->
|
|
|
|
+ <div
|
|
|
|
+ class="draggable-element barcode-element"
|
|
|
|
+ :style="{
|
|
|
|
+ left: (bibForm.qRCodeX || 11.67) + '%',
|
|
|
|
+ top: (bibForm.qRCodeY || 32.5) + '%',
|
|
|
|
+ transform: `translateX(-50%) scale(${bibForm.barcodeScale})`,
|
|
|
|
+ transformOrigin: 'top left',
|
|
|
|
+ }"
|
|
|
|
+ @mousedown="startDrag($event, 'barcode')"
|
|
|
|
+ @click="selectedElement = 'barcode'"
|
|
|
|
+ :class="{ selected: selectedElement === 'barcode' }"
|
|
|
|
+ >
|
|
|
|
+ <svg
|
|
|
|
+ t="1755833734016"
|
|
|
|
+ class="icon"
|
|
|
|
+ viewBox="0 0 1024 1024"
|
|
|
|
+ version="1.1"
|
|
|
|
+ xmlns="http://www.w3.org/2000/svg"
|
|
|
|
+ p-id="2399"
|
|
|
|
+ width="32"
|
|
|
|
+ height="32"
|
|
|
|
+ >
|
|
|
|
+ <path
|
|
|
|
+ d="M540.9 866h59v59h-59v-59zM422.8 423.1V98.4H98.1v324.8h59v59h59v-59h206.7z m-265.7-59V157.4h206.7v206.7H157.1z m0 0"
|
|
|
|
+ p-id="2400"
|
|
|
|
+ ></path>
|
|
|
|
+ <path
|
|
|
|
+ d="M216.2 216.4h88.6V305h-88.6v-88.6zM600 98.4v324.8h324.8V98.4H600z m265.7 265.7H659V157.4h206.7v206.7z m0 0"
|
|
|
|
+ p-id="2401"
|
|
|
|
+ ></path>
|
|
|
|
+ <path
|
|
|
|
+ d="M718.1 216.4h88.6V305h-88.6v-88.6zM216.2 718.3h88.6v88.6h-88.6v-88.6zM98.1 482.2h59v59h-59v-59z m118.1 0h59.1v59h-59.1v-59z m0 0"
|
|
|
|
+ p-id="2402"
|
|
|
|
+ ></path>
|
|
|
|
+ <path
|
|
|
|
+ d="M275.2 600.2H98.1V925h324.8V600.2h-88.6v-59h-59v59z m88.6 59.1V866H157.1V659.3h206.7z m118.1-531.4h59v88.6h-59v-88.6z m0 147.6h59v59h-59v-59zM659 482.2H540.9v-88.6h-59v88.6H334.3v59H600v59h59v-118z m0 118h59.1v59H659v-59z m-177.1 0h59v88.6h-59v-88.6z m0 147.7h59V866h-59V747.9zM600 688.8h59V866h-59V688.8z m177.1-88.6h147.6v59H777.1v-59z m88.6-118h59v59h-59v-59z m-147.6 0h118.1v59H718.1v-59z m0 206.6h59v59h-59v-59z m147.6 59.1h-29.5v59h59v-59h29.5v-59h-59v59z m-147.6 59h59V866h-59v-59.1z m59 59.1h147.6v59H777.1v-59z m0 0"
|
|
|
|
+ p-id="2403"
|
|
|
|
+ ></path>
|
|
|
|
+ </svg>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <!-- 赛事名称预览 -->
|
|
|
|
+ <div
|
|
|
|
+ v-if="bibForm.eventName"
|
|
|
|
+ class="event-name-preview draggable-element"
|
|
|
|
+ :style="{
|
|
|
|
+ fontSize: Math.min(28, Math.max(18, bibForm.fontSize * 0.7)) + 'px',
|
|
|
|
+ color: 'black',
|
|
|
|
+ fontFamily: '黑体',
|
|
|
|
+ left: (bibForm.eventX || 50) + '%',
|
|
|
|
+ top: (bibForm.eventY || 5) + '%',
|
|
|
|
+ transform: `translateX(-50%) scale(${bibForm.eventScale})`,
|
|
|
|
+ transformOrigin: 'top center'
|
|
|
|
+ }"
|
|
|
|
+ @mousedown="startDrag($event, 'event')"
|
|
|
|
+ @click="selectedElement = 'event'"
|
|
|
|
+ :class="{ selected: selectedElement === 'event' }"
|
|
|
|
+ >
|
|
|
|
+ {{ bibForm.eventName }}
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <!-- 示例数字 1234 -->
|
|
|
|
+ <div
|
|
|
|
+ class="draggable-element number-element"
|
|
|
|
+ :style="{
|
|
|
|
+ left: (bibForm.numberX || 50) + '%',
|
|
|
|
+ top: (bibForm.numberY || 50) + '%',
|
|
|
|
+ transform: `translate(-50%, -50%) scale(${bibForm.numberScale})`,
|
|
|
|
+ fontSize: Math.min(bibForm.fontSize, 56) + 'px',
|
|
|
|
+ color: bibForm.fontColorHex,
|
|
|
|
+ fontFamily: bibForm.fontName,
|
|
|
|
+ transformOrigin: 'center'
|
|
|
|
+ }"
|
|
|
|
+ @mousedown="startDrag($event, 'number')"
|
|
|
|
+ @click="selectedElement = 'number'"
|
|
|
|
+ :class="{ selected: selectedElement === 'number' }"
|
|
|
|
+ >
|
|
|
|
+ 1234
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <!-- 上传按钮区域 - 显示在预览面板下方 -->
|
|
|
|
+ <div class="upload-section">
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <div class="upload-item">
|
|
|
|
+ <div class="upload-row">
|
|
|
|
+ <el-upload
|
|
|
|
+ ref="bgUploadRef"
|
|
|
|
+ :limit="1"
|
|
|
|
+ :auto-upload="false"
|
|
|
|
+ :on-change="handleBgImageChange"
|
|
|
|
+ :show-file-list="false"
|
|
|
|
+ accept="image/*"
|
|
|
|
+ >
|
|
|
|
+ <el-button type="primary" :icon="bgImageFile ? 'Select' : 'Upload'">
|
|
|
|
+ {{'上传背景图片' }}
|
|
|
|
+ </el-button>
|
|
</el-upload>
|
|
</el-upload>
|
|
- <div v-if="bgImageFile" class="file-info">
|
|
|
|
- <span class="file-name">{{ bgImageFile.name }}</span>
|
|
|
|
- <el-button type="text" @click="removeBgImage" class="remove-btn">删除</el-button>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <span class="upload-tip">建议尺寸:600×400px</span>
|
|
</div>
|
|
</div>
|
|
- </el-form-item>
|
|
|
|
-
|
|
|
|
- <el-form-item label="Logo图片" required>
|
|
|
|
- <div class="upload-container">
|
|
|
|
- <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>
|
|
|
|
|
|
+ <div v-if="bgImageFile" class="file-info">
|
|
|
|
+ <span class="file-name">{{ bgImageFile.name }}</span>
|
|
|
|
+ <el-button type="text" @click="removeBgImage" class="remove-btn">删除</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <div class="upload-item">
|
|
|
|
+ <div class="upload-row">
|
|
|
|
+ <el-upload
|
|
|
|
+ ref="logoUploadRef"
|
|
|
|
+ :limit="1"
|
|
|
|
+ :auto-upload="false"
|
|
|
|
+ :on-change="handleLogoImageChange"
|
|
|
|
+ :show-file-list="false"
|
|
|
|
+ accept="image/*"
|
|
|
|
+ >
|
|
|
|
+ <el-button type="primary" :icon="logoImageFile ? 'Select' : 'Upload'">
|
|
|
|
+ {{'上传Logo图片' }}
|
|
|
|
+ </el-button>
|
|
</el-upload>
|
|
</el-upload>
|
|
- <div v-if="logoImageFile" class="file-info">
|
|
|
|
- <span class="file-name">{{ logoImageFile.name }}</span>
|
|
|
|
- <el-button type="text" @click="removeLogoImage" class="remove-btn">删除</el-button>
|
|
|
|
- </div>
|
|
|
|
|
|
+ <span class="upload-tip">建议尺寸:80×80px</span>
|
|
</div>
|
|
</div>
|
|
- </el-form-item>
|
|
|
|
|
|
+ <div v-if="logoImageFile" class="file-info">
|
|
|
|
+ <span class="file-name">{{ logoImageFile.name }}</span>
|
|
|
|
+ <el-button type="text" @click="removeLogoImage" class="remove-btn">删除</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
+ <!-- 配置面板 -->
|
|
|
|
+ <el-form :model="bibForm" label-width="100px" class="config-form">
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
+ <el-col :span="12">
|
|
<el-form-item label="字体设置">
|
|
<el-form-item label="字体设置">
|
|
<div style="display: flex; gap: 15px; align-items: center">
|
|
<div style="display: flex; gap: 15px; align-items: center">
|
|
<el-select v-model="bibForm.fontName" placeholder="字体" style="width: 100px">
|
|
<el-select v-model="bibForm.fontName" placeholder="字体" style="width: 100px">
|
|
@@ -49,7 +177,30 @@
|
|
<el-color-picker v-model="bibForm.fontColor" @change="handleFontColorChange"></el-color-picker>
|
|
<el-color-picker v-model="bibForm.fontColor" @change="handleFontColorChange"></el-color-picker>
|
|
</div>
|
|
</div>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <!-- 在字体设置表单项后添加缩放控制 -->
|
|
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="赛事名称">
|
|
|
|
+ <el-input v-model="bibForm.eventName" placeholder="请输入赛事名称" maxlength="50" show-word-limit />
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="画布比例">
|
|
|
|
+ <el-select v-model="canvasScale" placeholder="选择画布比例" style="width: 200px">
|
|
|
|
+ <el-option label="1/4 (四分之一)" :value="0.25"></el-option>
|
|
|
|
+ <el-option label="1/3 (三分之一)" :value="0.33"></el-option>
|
|
|
|
+ <el-option label="1/2 (二分之一)" :value="0.5"></el-option>
|
|
|
|
+ <el-option label="3/4 (四分之三)" :value="0.75"></el-option>
|
|
|
|
+ <el-option label="1/1 (原始大小)" :value="1"></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="24">
|
|
<el-form-item label="选中元素">
|
|
<el-form-item label="选中元素">
|
|
<div style="display: flex; gap: 10px; align-items: center">
|
|
<div style="display: flex; gap: 10px; align-items: center">
|
|
<el-select v-model="selectedElement" placeholder="选择元素" style="width: 120px">
|
|
<el-select v-model="selectedElement" placeholder="选择元素" style="width: 120px">
|
|
@@ -83,121 +234,9 @@
|
|
</el-button>
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</el-form-item>
|
|
</el-form-item>
|
|
- <el-form-item label="赛事名称">
|
|
|
|
- <el-input v-model="bibForm.eventName" placeholder="请输入赛事名称" maxlength="50" show-word-limit />
|
|
|
|
- </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',
|
|
|
|
- backgroundSize: 'contain',
|
|
|
|
- backgroundRepeat: 'no-repeat'
|
|
|
|
- }">
|
|
|
|
- <!-- Logo元素 -->
|
|
|
|
- <div
|
|
|
|
- v-if="logoImageUrl"
|
|
|
|
- class="draggable-element logo-element"
|
|
|
|
- :style="{
|
|
|
|
- left: bibForm.logoX + '%',
|
|
|
|
- top: bibForm.logoY + '%',
|
|
|
|
- transform: `translateX(-50%) scale(${bibForm.logoScale})`,
|
|
|
|
- transformOrigin: 'top left'
|
|
|
|
- }"
|
|
|
|
- @mousedown="startDrag($event, 'logo')"
|
|
|
|
- @click="selectedElement = 'logo'"
|
|
|
|
- :class="{ selected: selectedElement === 'logo' }"
|
|
|
|
- >
|
|
|
|
- <img :src="logoImageUrl" alt="Logo" style="max-width: 80px; max-height: 80px" />
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 示例条形码 -->
|
|
|
|
- <div
|
|
|
|
- class="draggable-element barcode-element"
|
|
|
|
- :style="{
|
|
|
|
- left: (bibForm.qRCodeX || 11.67) + '%',
|
|
|
|
- top: (bibForm.qRCodeY || 32.5) + '%',
|
|
|
|
- transform: `translateX(-50%) scale(${bibForm.barcodeScale})`,
|
|
|
|
- transformOrigin: 'top left',
|
|
|
|
- }"
|
|
|
|
- @mousedown="startDrag($event, 'barcode')"
|
|
|
|
- @click="selectedElement = 'barcode'"
|
|
|
|
- :class="{ selected: selectedElement === 'barcode' }"
|
|
|
|
- >
|
|
|
|
- <svg
|
|
|
|
- t="1755833734016"
|
|
|
|
- class="icon"
|
|
|
|
- viewBox="0 0 1024 1024"
|
|
|
|
- version="1.1"
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- p-id="2399"
|
|
|
|
- width="32"
|
|
|
|
- height="32"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- d="M540.9 866h59v59h-59v-59zM422.8 423.1V98.4H98.1v324.8h59v59h59v-59h206.7z m-265.7-59V157.4h206.7v206.7H157.1z m0 0"
|
|
|
|
- p-id="2400"
|
|
|
|
- ></path>
|
|
|
|
- <path
|
|
|
|
- d="M216.2 216.4h88.6V305h-88.6v-88.6zM600 98.4v324.8h324.8V98.4H600z m265.7 265.7H659V157.4h206.7v206.7z m0 0"
|
|
|
|
- p-id="2401"
|
|
|
|
- ></path>
|
|
|
|
- <path
|
|
|
|
- d="M718.1 216.4h88.6V305h-88.6v-88.6zM216.2 718.3h88.6v88.6h-88.6v-88.6zM98.1 482.2h59v59h-59v-59z m118.1 0h59.1v59h-59.1v-59z m0 0"
|
|
|
|
- p-id="2402"
|
|
|
|
- ></path>
|
|
|
|
- <path
|
|
|
|
- d="M275.2 600.2H98.1V925h324.8V600.2h-88.6v-59h-59v59z m88.6 59.1V866H157.1V659.3h206.7z m118.1-531.4h59v88.6h-59v-88.6z m0 147.6h59v59h-59v-59zM659 482.2H540.9v-88.6h-59v88.6H334.3v59H600v59h59v-118z m0 118h59.1v59H659v-59z m-177.1 0h59v88.6h-59v-88.6z m0 147.7h59V866h-59V747.9zM600 688.8h59V866h-59V688.8z m177.1-88.6h147.6v59H777.1v-59z m88.6-118h59v59h-59v-59z m-147.6 0h118.1v59H718.1v-59z m0 206.6h59v59h-59v-59z m147.6 59.1h-29.5v59h59v-59h29.5v-59h-59v59z m-147.6 59h59V866h-59v-59.1z m59 59.1h147.6v59H777.1v-59z m0 0"
|
|
|
|
- p-id="2403"
|
|
|
|
- ></path>
|
|
|
|
- </svg>
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 赛事名称预览 -->
|
|
|
|
- <div
|
|
|
|
- v-if="bibForm.eventName"
|
|
|
|
- class="event-name-preview draggable-element"
|
|
|
|
- :style="{
|
|
|
|
- fontSize: Math.min(28, Math.max(18, bibForm.fontSize * 0.7)) + 'px',
|
|
|
|
- color: 'black',
|
|
|
|
- fontFamily: '黑体',
|
|
|
|
- left: (bibForm.eventX || 50) + '%',
|
|
|
|
- top: (bibForm.eventY || 5) + '%', // 移除Y轴翻转,与PDF生成保持一致
|
|
|
|
- transform: `translateX(-50%) scale(${bibForm.eventScale})`,
|
|
|
|
- transformOrigin: 'top center'
|
|
|
|
- }"
|
|
|
|
- @mousedown="startDrag($event, 'event')"
|
|
|
|
- @click="selectedElement = 'event'"
|
|
|
|
- :class="{ selected: selectedElement === 'event' }"
|
|
|
|
- >
|
|
|
|
- {{ bibForm.eventName }}
|
|
|
|
- </div>
|
|
|
|
-
|
|
|
|
- <!-- 示例数字 1234 -->
|
|
|
|
- <div
|
|
|
|
- class="draggable-element number-element"
|
|
|
|
- :style="{
|
|
|
|
- left: (bibForm.numberX || 50) + '%',
|
|
|
|
- top: (bibForm.numberY || 50) + '%', // 移除Y轴翻转,与PDF生成保持一致
|
|
|
|
- transform: `translate(-50%, -50%) scale(${bibForm.numberScale})`,
|
|
|
|
- fontSize: Math.min(bibForm.fontSize, 56) + 'px',
|
|
|
|
- color: bibForm.fontColorHex,
|
|
|
|
- fontFamily: bibForm.fontName,
|
|
|
|
- transformOrigin: 'center'
|
|
|
|
- }"
|
|
|
|
- @mousedown="startDrag($event, 'number')"
|
|
|
|
- @click="selectedElement = 'number'"
|
|
|
|
- :class="{ selected: selectedElement === 'number' }"
|
|
|
|
- >
|
|
|
|
- 1234
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </el-col>
|
|
|
|
- </el-row>
|
|
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </el-form>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<template #footer>
|
|
<template #footer>
|
|
@@ -242,6 +281,7 @@ const bibDialog = reactive({
|
|
});
|
|
});
|
|
|
|
|
|
const selectedElement = ref<string>(''); // 当前选中的元素
|
|
const selectedElement = ref<string>(''); // 当前选中的元素
|
|
|
|
+const canvasScale = ref<number>(1); // 画布缩放比例
|
|
|
|
|
|
const bibForm = reactive({
|
|
const bibForm = reactive({
|
|
// 统一使用百分比坐标系统 (0-100)
|
|
// 统一使用百分比坐标系统 (0-100)
|
|
@@ -272,6 +312,7 @@ const bgImageUrl = ref<string>('');
|
|
const logoImageUrl = ref<string>('');
|
|
const logoImageUrl = ref<string>('');
|
|
const previewContainer = ref<HTMLElement>();
|
|
const previewContainer = ref<HTMLElement>();
|
|
const bgImageDimensions = ref<{ width: number; height: number } | null>(null);
|
|
const bgImageDimensions = ref<{ width: number; height: number } | null>(null);
|
|
|
|
+const logoImageDimensions = ref<{ width: number; height: number } | null>(null);
|
|
const bgUploadRef = ref<UploadInstance>();
|
|
const bgUploadRef = ref<UploadInstance>();
|
|
const logoUploadRef = ref<UploadInstance>();
|
|
const logoUploadRef = ref<UploadInstance>();
|
|
|
|
|
|
@@ -341,7 +382,7 @@ const resetElementScale = () => {
|
|
|
|
|
|
// 重置表单
|
|
// 重置表单
|
|
const resetBibForm = () => {
|
|
const resetBibForm = () => {
|
|
- // 设置默认值(百分比单位)- 适配3:2横屏比例
|
|
|
|
|
|
+ // 设置默认值(百分比单位)
|
|
bibForm.logoX = 4.17; // 25/600 * 100 = 4.17%
|
|
bibForm.logoX = 4.17; // 25/600 * 100 = 4.17%
|
|
bibForm.logoY = 6.25; // 25/400 * 100 = 6.25%
|
|
bibForm.logoY = 6.25; // 25/400 * 100 = 6.25%
|
|
bibForm.qRCodeX = 11.67; // 70/600 * 100 = 11.67%
|
|
bibForm.qRCodeX = 11.67; // 70/600 * 100 = 11.67%
|
|
@@ -362,6 +403,8 @@ const resetBibForm = () => {
|
|
logoImageFile.value = null;
|
|
logoImageFile.value = null;
|
|
bgImageUrl.value = '';
|
|
bgImageUrl.value = '';
|
|
logoImageUrl.value = '';
|
|
logoImageUrl.value = '';
|
|
|
|
+ bgImageDimensions.value = null;
|
|
|
|
+ logoImageDimensions.value = null;
|
|
|
|
|
|
// 重置缩放
|
|
// 重置缩放
|
|
bibForm.logoScale = 1;
|
|
bibForm.logoScale = 1;
|
|
@@ -370,6 +413,8 @@ const resetBibForm = () => {
|
|
bibForm.eventScale = 1;
|
|
bibForm.eventScale = 1;
|
|
// 重置选中元素
|
|
// 重置选中元素
|
|
selectedElement.value = '';
|
|
selectedElement.value = '';
|
|
|
|
+ // 重置画布比例
|
|
|
|
+ canvasScale.value = 1;
|
|
|
|
|
|
// 清除上传的文件
|
|
// 清除上传的文件
|
|
if (bgUploadRef.value) {
|
|
if (bgUploadRef.value) {
|
|
@@ -383,19 +428,18 @@ const resetBibForm = () => {
|
|
// 背景图片改变处理
|
|
// 背景图片改变处理
|
|
const handleBgImageChange = async (file: any) => {
|
|
const handleBgImageChange = async (file: any) => {
|
|
if (file.raw) {
|
|
if (file.raw) {
|
|
- // 处理图片比例,转换为3:2横屏(600×400px)
|
|
|
|
- const processedFile = await processImageToRatio(file.raw, 3, 2);
|
|
|
|
- bgImageFile.value = processedFile;
|
|
|
|
|
|
+ // 直接使用原始图片,不进行裁剪
|
|
|
|
+ bgImageFile.value = file.raw;
|
|
|
|
|
|
const reader = new FileReader();
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
reader.onload = (e) => {
|
|
bgImageUrl.value = e.target?.result as string;
|
|
bgImageUrl.value = e.target?.result as string;
|
|
};
|
|
};
|
|
- reader.readAsDataURL(processedFile);
|
|
|
|
|
|
+ reader.readAsDataURL(file.raw);
|
|
|
|
|
|
- // 获取处理后的图片尺寸
|
|
|
|
|
|
+ // 获取原始图片尺寸
|
|
try {
|
|
try {
|
|
- const dimensions = await getImageDimensions(processedFile);
|
|
|
|
|
|
+ const dimensions = await getImageDimensions(file.raw);
|
|
bgImageDimensions.value = dimensions;
|
|
bgImageDimensions.value = dimensions;
|
|
} catch (error) {
|
|
} catch (error) {
|
|
console.error('获取图片尺寸失败:', error);
|
|
console.error('获取图片尺寸失败:', error);
|
|
@@ -407,7 +451,7 @@ const handleBgImageChange = async (file: any) => {
|
|
};
|
|
};
|
|
|
|
|
|
// Logo图片改变处理
|
|
// Logo图片改变处理
|
|
-const handleLogoImageChange = (file: any) => {
|
|
|
|
|
|
+const handleLogoImageChange = async (file: any) => {
|
|
if (file.raw) {
|
|
if (file.raw) {
|
|
logoImageFile.value = file.raw;
|
|
logoImageFile.value = file.raw;
|
|
const reader = new FileReader();
|
|
const reader = new FileReader();
|
|
@@ -416,6 +460,14 @@ const handleLogoImageChange = (file: any) => {
|
|
};
|
|
};
|
|
reader.readAsDataURL(file.raw);
|
|
reader.readAsDataURL(file.raw);
|
|
|
|
|
|
|
|
+ // 获取Logo图片尺寸
|
|
|
|
+ try {
|
|
|
|
+ const dimensions = await getImageDimensions(file.raw);
|
|
|
|
+ logoImageDimensions.value = dimensions;
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error('获取Logo图片尺寸失败:', error);
|
|
|
|
+ }
|
|
|
|
+
|
|
// 添加成功提示
|
|
// 添加成功提示
|
|
proxy?.$modal.msgSuccess('Logo图片上传成功');
|
|
proxy?.$modal.msgSuccess('Logo图片上传成功');
|
|
}
|
|
}
|
|
@@ -436,6 +488,7 @@ const removeBgImage = () => {
|
|
const removeLogoImage = () => {
|
|
const removeLogoImage = () => {
|
|
logoImageFile.value = null;
|
|
logoImageFile.value = null;
|
|
logoImageUrl.value = '';
|
|
logoImageUrl.value = '';
|
|
|
|
+ logoImageDimensions.value = null;
|
|
if (logoUploadRef.value) {
|
|
if (logoUploadRef.value) {
|
|
logoUploadRef.value.clearFiles();
|
|
logoUploadRef.value.clearFiles();
|
|
}
|
|
}
|
|
@@ -496,34 +549,62 @@ const handleDrag = (event: MouseEvent) => {
|
|
if (dragState.dragTarget === 'logo') {
|
|
if (dragState.dragTarget === 'logo') {
|
|
bibForm.logoX = newX;
|
|
bibForm.logoX = newX;
|
|
bibForm.logoY = newY;
|
|
bibForm.logoY = newY;
|
|
|
|
+ console.log('Logo位置 - X:', newX.toFixed(2) + '%', 'Y:', newY.toFixed(2) + '%');
|
|
} else if (dragState.dragTarget === 'barcode') {
|
|
} else if (dragState.dragTarget === 'barcode') {
|
|
bibForm.qRCodeX = newX;
|
|
bibForm.qRCodeX = newX;
|
|
bibForm.qRCodeY = newY;
|
|
bibForm.qRCodeY = newY;
|
|
|
|
+ console.log('二维码位置 - X:', newX.toFixed(2) + '%', 'Y:', newY.toFixed(2) + '%');
|
|
} else if (dragState.dragTarget === 'number') {
|
|
} else if (dragState.dragTarget === 'number') {
|
|
bibForm.numberX = newX;
|
|
bibForm.numberX = newX;
|
|
bibForm.numberY = newY;
|
|
bibForm.numberY = newY;
|
|
|
|
+ console.log('号码位置 - X:', newX.toFixed(2) + '%', 'Y:', newY.toFixed(2) + '%');
|
|
} else if (dragState.dragTarget === 'event') {
|
|
} else if (dragState.dragTarget === 'event') {
|
|
bibForm.eventX = newX;
|
|
bibForm.eventX = newX;
|
|
bibForm.eventY = newY;
|
|
bibForm.eventY = newY;
|
|
|
|
+ console.log('赛事名称位置 - X:', newX.toFixed(2) + '%', 'Y:', newY.toFixed(2) + '%');
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
// 停止拖拽
|
|
// 停止拖拽
|
|
const stopDrag = () => {
|
|
const stopDrag = () => {
|
|
|
|
+ if (dragState.dragTarget) {
|
|
|
|
+ let finalX = 0, finalY = 0, targetName = '';
|
|
|
|
+
|
|
|
|
+ if (dragState.dragTarget === 'logo') {
|
|
|
|
+ finalX = bibForm.logoX;
|
|
|
|
+ finalY = bibForm.logoY;
|
|
|
|
+ targetName = 'Logo';
|
|
|
|
+ } else if (dragState.dragTarget === 'barcode') {
|
|
|
|
+ finalX = bibForm.qRCodeX;
|
|
|
|
+ finalY = bibForm.qRCodeY;
|
|
|
|
+ targetName = '二维码';
|
|
|
|
+ } else if (dragState.dragTarget === 'number') {
|
|
|
|
+ finalX = bibForm.numberX;
|
|
|
|
+ finalY = bibForm.numberY;
|
|
|
|
+ targetName = '号码';
|
|
|
|
+ } else if (dragState.dragTarget === 'event') {
|
|
|
|
+ finalX = bibForm.eventX;
|
|
|
|
+ finalY = bibForm.eventY;
|
|
|
|
+ targetName = '赛事名称';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ console.log(`✅ ${targetName}最终位置 - X: ${finalX.toFixed(2)}%, Y: ${finalY.toFixed(2)}%`);
|
|
|
|
+ }
|
|
|
|
+
|
|
dragState.isDragging = false;
|
|
dragState.isDragging = false;
|
|
dragState.dragTarget = '';
|
|
dragState.dragTarget = '';
|
|
document.removeEventListener('mousemove', handleDrag);
|
|
document.removeEventListener('mousemove', handleDrag);
|
|
document.removeEventListener('mouseup', stopDrag);
|
|
document.removeEventListener('mouseup', stopDrag);
|
|
};
|
|
};
|
|
|
|
|
|
-// 坐标转换函数:根据3:2横屏比例的背景图片尺寸调整坐标
|
|
|
|
|
|
+// 坐标转换函数:根据背景图片实际尺寸调整坐标
|
|
const convertCoordinatesWithScale = (x: number, y: number): { x: number; y: number } => {
|
|
const convertCoordinatesWithScale = (x: number, y: number): { x: number; y: number } => {
|
|
// 获取预览容器尺寸
|
|
// 获取预览容器尺寸
|
|
const container = previewContainer.value;
|
|
const container = previewContainer.value;
|
|
const previewWidth = container?.clientWidth || container?.offsetWidth || PREVIEW_WIDTH;
|
|
const previewWidth = container?.clientWidth || container?.offsetWidth || PREVIEW_WIDTH;
|
|
const previewHeight = container?.clientHeight || container?.offsetHeight || PREVIEW_HEIGHT;
|
|
const previewHeight = container?.clientHeight || container?.offsetHeight || PREVIEW_HEIGHT;
|
|
|
|
|
|
- // 使用实际背景图片尺寸,如果没有则使用默认3:2横屏比例尺寸(600×400px)
|
|
|
|
|
|
+ // 使用实际背景图片尺寸,如果没有则使用默认尺寸(600×400px)
|
|
const actualWidth = bgImageDimensions.value?.width || 600;
|
|
const actualWidth = bgImageDimensions.value?.width || 600;
|
|
const actualHeight = bgImageDimensions.value?.height || 400;
|
|
const actualHeight = bgImageDimensions.value?.height || 400;
|
|
|
|
|
|
@@ -541,7 +622,7 @@ const convertCoordinatesWithScale = (x: number, y: number): { x: number; y: numb
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
-// 新增:获取背景图片实际尺寸的函数
|
|
|
|
|
|
+// 获取背景图片实际尺寸的函数
|
|
const getImageDimensions = (file: File): Promise<{ width: number; height: number }> => {
|
|
const getImageDimensions = (file: File): Promise<{ width: number; height: number }> => {
|
|
return new Promise((resolve) => {
|
|
return new Promise((resolve) => {
|
|
const img = new Image();
|
|
const img = new Image();
|
|
@@ -552,68 +633,6 @@ const getImageDimensions = (file: File): Promise<{ width: number; height: number
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
|
|
-// 处理图片比例转换函数
|
|
|
|
-const processImageToRatio = (file: File, targetRatio: number, targetRatio2: number): Promise<File> => {
|
|
|
|
- return new Promise((resolve) => {
|
|
|
|
- const img = new Image();
|
|
|
|
- img.onload = () => {
|
|
|
|
- const canvas = document.createElement('canvas');
|
|
|
|
- const ctx = canvas.getContext('2d');
|
|
|
|
-
|
|
|
|
- if (!ctx) {
|
|
|
|
- resolve(file);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const originalWidth = img.width;
|
|
|
|
- const originalHeight = img.height;
|
|
|
|
- const targetRatioValue = targetRatio / targetRatio2; // 3/2 = 1.5
|
|
|
|
-
|
|
|
|
- let newWidth, newHeight, sourceX, sourceY, sourceWidth, sourceHeight;
|
|
|
|
-
|
|
|
|
- if (originalWidth / originalHeight > targetRatioValue) {
|
|
|
|
- // 原图更宽,需要裁剪宽度
|
|
|
|
- newHeight = originalHeight;
|
|
|
|
- newWidth = originalHeight * targetRatioValue;
|
|
|
|
- sourceX = (originalWidth - newWidth) / 2;
|
|
|
|
- sourceY = 0;
|
|
|
|
- sourceWidth = newWidth;
|
|
|
|
- sourceHeight = originalHeight;
|
|
|
|
- } else {
|
|
|
|
- // 原图更高,需要裁剪高度
|
|
|
|
- newWidth = originalWidth;
|
|
|
|
- newHeight = originalWidth / targetRatioValue;
|
|
|
|
- sourceX = 0;
|
|
|
|
- sourceY = (originalHeight - newHeight) / 2;
|
|
|
|
- sourceWidth = originalWidth;
|
|
|
|
- sourceHeight = newHeight;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 设置画布尺寸为3:2横屏比例
|
|
|
|
- canvas.width = newWidth;
|
|
|
|
- canvas.height = newHeight;
|
|
|
|
-
|
|
|
|
- // 绘制裁剪后的图片
|
|
|
|
- ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight, 0, 0, newWidth, newHeight);
|
|
|
|
-
|
|
|
|
- // 转换为Blob
|
|
|
|
- canvas.toBlob(
|
|
|
|
- (blob) => {
|
|
|
|
- if (blob) {
|
|
|
|
- const processedFile = new File([blob], file.name, { type: file.type });
|
|
|
|
- resolve(processedFile);
|
|
|
|
- } else {
|
|
|
|
- resolve(file);
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- file.type || 'image/jpeg',
|
|
|
|
- 0.9
|
|
|
|
- );
|
|
|
|
- };
|
|
|
|
- img.src = URL.createObjectURL(file);
|
|
|
|
- });
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
// 创建参赛证生成任务
|
|
// 创建参赛证生成任务
|
|
const handleCreateTask = async () => {
|
|
const handleCreateTask = async () => {
|
|
// 校验必须上传背景图
|
|
// 校验必须上传背景图
|
|
@@ -667,6 +686,21 @@ const handleCreateTask = async () => {
|
|
|
|
|
|
console.log('二维码坐标转换 - 原始坐标:', { qRCodeX, qRCodeY }, '有效坐标:', { validQRCodeX, validQRCodeY }, '转换后坐标:', qrCoords);
|
|
console.log('二维码坐标转换 - 原始坐标:', { qRCodeX, qRCodeY }, '有效坐标:', { validQRCodeX, validQRCodeY }, '转换后坐标:', qrCoords);
|
|
|
|
|
|
|
|
+ // 计算画布比例处理后的宽高
|
|
|
|
+ const originalWidth = bgImageDimensions.value?.width || 600;
|
|
|
|
+ const originalHeight = bgImageDimensions.value?.height || 400;
|
|
|
|
+ const scaledWidth = Math.round(originalWidth * canvasScale.value);
|
|
|
|
+ const scaledHeight = Math.round(originalHeight * canvasScale.value);
|
|
|
|
+
|
|
|
|
+ // 计算Logo尺寸(前端统一处理,避免后端重复计算)
|
|
|
|
+ // 预览时限制为最大80px,应用用户缩放,计算最终尺寸传递给后端
|
|
|
|
+ const logoOriginalWidth = logoImageDimensions.value?.width || 80;
|
|
|
|
+ const logoOriginalHeight = logoImageDimensions.value?.height || 80;
|
|
|
|
+ const logoPreviewSize = 80; // 前端预览时的最大尺寸
|
|
|
|
+ const logoScale = Math.min(1.0, logoPreviewSize / Math.max(logoOriginalWidth, logoOriginalHeight));
|
|
|
|
+ const logoFinalWidth = Math.round(logoOriginalWidth * logoScale * bibForm.logoScale);
|
|
|
|
+ const logoFinalHeight = Math.round(logoOriginalHeight * logoScale * bibForm.logoScale);
|
|
|
|
+
|
|
const bibParams = {
|
|
const bibParams = {
|
|
// Logo坐标(百分比)
|
|
// Logo坐标(百分比)
|
|
logoX: logoCoords.x,
|
|
logoX: logoCoords.x,
|
|
@@ -675,7 +709,7 @@ const handleCreateTask = async () => {
|
|
qRCodeX: qrCoords.x,
|
|
qRCodeX: qrCoords.x,
|
|
qRCodeY: qrCoords.y,
|
|
qRCodeY: qrCoords.y,
|
|
fontName: bibForm.fontName || 'simhei',
|
|
fontName: bibForm.fontName || 'simhei',
|
|
- fontSize: Math.round((bibForm.fontSize || 36) * 0.75),
|
|
|
|
|
|
+ fontSize: bibForm.fontSize || 36, // 直接传递原始字体大小,后端会应用numberScale
|
|
fontColor: parseInt((bibForm.fontColor || '#000000').replace('#', ''), 16),
|
|
fontColor: parseInt((bibForm.fontColor || '#000000').replace('#', ''), 16),
|
|
eventName: bibForm.eventName || '',
|
|
eventName: bibForm.eventName || '',
|
|
// 位置参数(百分比)
|
|
// 位置参数(百分比)
|
|
@@ -688,6 +722,12 @@ const handleCreateTask = async () => {
|
|
barcodeScale: bibForm.barcodeScale,
|
|
barcodeScale: bibForm.barcodeScale,
|
|
numberScale: bibForm.numberScale,
|
|
numberScale: bibForm.numberScale,
|
|
eventScale: bibForm.eventScale,
|
|
eventScale: bibForm.eventScale,
|
|
|
|
+ // 画布比例处理后的宽高
|
|
|
|
+ width: scaledWidth,
|
|
|
|
+ height: scaledHeight,
|
|
|
|
+ // Logo尺寸
|
|
|
|
+ logoWidth: logoFinalWidth,
|
|
|
|
+ logoHeight: logoFinalHeight,
|
|
};
|
|
};
|
|
|
|
|
|
console.log('发送给后端的参数:', bibParams);
|
|
console.log('发送给后端的参数:', bibParams);
|
|
@@ -725,6 +765,8 @@ defineExpose({
|
|
bgImageUrl,
|
|
bgImageUrl,
|
|
logoImageUrl,
|
|
logoImageUrl,
|
|
bgImageDimensions,
|
|
bgImageDimensions,
|
|
|
|
+ logoImageDimensions,
|
|
|
|
+ canvasScale,
|
|
handleCloseBibDialog,
|
|
handleCloseBibDialog,
|
|
resetBibForm,
|
|
resetBibForm,
|
|
handleBgImageChange,
|
|
handleBgImageChange,
|
|
@@ -740,51 +782,60 @@ defineExpose({
|
|
<style scoped lang="scss">
|
|
<style scoped lang="scss">
|
|
/* 生成参赛证样式 */
|
|
/* 生成参赛证样式 */
|
|
.bib-generator {
|
|
.bib-generator {
|
|
- padding: 20px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.bib-generator .el-upload__tip {
|
|
|
|
- color: #909399;
|
|
|
|
- font-size: 12px;
|
|
|
|
- margin-top: 8px;
|
|
|
|
- text-align: center;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 必填项样式 */
|
|
|
|
-.bib-generator .el-form-item.is-required .el-form-item__label::before {
|
|
|
|
- content: '*';
|
|
|
|
- color: #f56c6c;
|
|
|
|
- margin-right: 4px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-/* 上传成功状态样式 */
|
|
|
|
-.bib-generator .el-upload--success {
|
|
|
|
- border-color: #67c23a;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.bib-generator .el-upload--success .el-upload__text {
|
|
|
|
- color: #67c23a;
|
|
|
|
|
|
+ padding: 10px;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* 预览容器 - 占满宽度 */
|
|
.preview-container {
|
|
.preview-container {
|
|
border: 2px dashed #ddd;
|
|
border: 2px dashed #ddd;
|
|
border-radius: 8px;
|
|
border-radius: 8px;
|
|
- min-height: 200px;
|
|
|
|
- max-height: 300px;
|
|
|
|
|
|
+ min-height: 300px;
|
|
|
|
+ max-height: 400px;
|
|
position: relative;
|
|
position: relative;
|
|
- overflow: hidden;
|
|
|
|
|
|
+ overflow: auto;
|
|
aspect-ratio: 3/2;
|
|
aspect-ratio: 3/2;
|
|
display: flex;
|
|
display: flex;
|
|
align-items: center;
|
|
align-items: center;
|
|
justify-content: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
width: 100%;
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
+ background-color: #f8f9fa;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 上传按钮区域 */
|
|
|
|
+.upload-section {
|
|
|
|
+ margin-bottom: 20px;
|
|
|
|
+ padding: 15px;
|
|
|
|
+ background-color: #f5f7fa;
|
|
|
|
+ border-radius: 8px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.upload-item {
|
|
|
|
+ display: flex;
|
|
|
|
+ flex-direction: column;
|
|
|
|
+ gap: 8px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.upload-row {
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ gap: 10px;
|
|
|
|
+
|
|
|
|
+ .el-upload {
|
|
|
|
+ display: inline-block;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 配置表单 */
|
|
|
|
+.config-form {
|
|
|
|
+ margin-top: 10px;
|
|
}
|
|
}
|
|
|
|
|
|
.preview-canvas {
|
|
.preview-canvas {
|
|
width: 100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
height: 100%;
|
|
position: relative;
|
|
position: relative;
|
|
- background-size: auto;
|
|
|
|
|
|
+ background-size: 100% 100%;
|
|
background-position: center;
|
|
background-position: center;
|
|
background-repeat: no-repeat;
|
|
background-repeat: no-repeat;
|
|
background-color: #f5f5f5;
|
|
background-color: #f5f5f5;
|
|
@@ -823,15 +874,18 @@ defineExpose({
|
|
background-color: rgba(103, 194, 58, 0.1);
|
|
background-color: rgba(103, 194, 58, 0.1);
|
|
}
|
|
}
|
|
|
|
|
|
-/* 上传容器样式 */
|
|
|
|
-.upload-container {
|
|
|
|
- width: 100%;
|
|
|
|
|
|
+.upload-tip {
|
|
|
|
+ color: #909399;
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ line-height: 1.5;
|
|
|
|
+ white-space: nowrap;
|
|
}
|
|
}
|
|
|
|
|
|
.file-info {
|
|
.file-info {
|
|
margin-top: 8px;
|
|
margin-top: 8px;
|
|
padding: 8px;
|
|
padding: 8px;
|
|
- background-color: #f5f7fa;
|
|
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ border: 1px solid #dcdfe6;
|
|
border-radius: 4px;
|
|
border-radius: 4px;
|
|
display: flex;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
@@ -895,4 +949,58 @@ defineExpose({
|
|
outline: 2px solid #409eff;
|
|
outline: 2px solid #409eff;
|
|
outline-offset: 2px;
|
|
outline-offset: 2px;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+/* 坐标系统说明样式 */
|
|
|
|
+.coordinate-info {
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+ pointer-events: none;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.coord-marker {
|
|
|
|
+ position: absolute;
|
|
|
|
+ width: 10px;
|
|
|
|
+ height: 10px;
|
|
|
|
+ background-color: #f56c6c;
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+ border: 2px solid #fff;
|
|
|
|
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
|
|
|
|
+ z-index: 100;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.coord-label {
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 15px;
|
|
|
|
+ top: -5px;
|
|
|
|
+ background-color: rgba(245, 108, 108, 0.9);
|
|
|
|
+ color: #fff;
|
|
|
|
+ padding: 2px 8px;
|
|
|
|
+ border-radius: 4px;
|
|
|
|
+ font-size: 12px;
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.coord-text {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 50%;
|
|
|
|
+ left: 50%;
|
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
|
+ text-align: center;
|
|
|
|
+ color: #909399;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+ line-height: 1.8;
|
|
|
|
+
|
|
|
|
+ p:first-child {
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ color: #606266;
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ p {
|
|
|
|
+ margin: 5px 0;
|
|
|
|
+ }
|
|
|
|
+}
|
|
</style>
|
|
</style>
|