feat: add image upload component with backend proxy and auto thumbnail

- Create reusable ImageUpload.vue component (drag-drop, preview, progress)
- Replace URL input fields with ImageUpload in category and template dialogs
- Upload via backend proxy to avoid OSS CORS issues
- Auto-fill thumbnail_url and image dimensions on template image upload

Made-with: Cursor
This commit is contained in:
nepiedg
2026-04-04 02:52:50 +08:00
parent 54b461dfb4
commit d62c51f140
3 changed files with 239 additions and 7 deletions
+39 -7
View File
@@ -161,8 +161,14 @@
<el-form-item label="名称" required>
<el-input v-model="categoryForm.name" maxlength="50" show-word-limit />
</el-form-item>
<el-form-item label="图标URL">
<el-input v-model="categoryForm.icon" placeholder="可选:填写图标链接" />
<el-form-item label="图标">
<ImageUpload
v-model="categoryForm.icon"
placeholder="上传图标"
preview-width="64px"
preview-height="64px"
:max-size="2"
/>
</el-form-item>
<el-form-item label="排序">
<el-input-number v-model="categoryForm.sort_order" :min="0" :max="9999" />
@@ -191,11 +197,24 @@
<el-option v-for="item in categories" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="图片URL" required>
<el-input v-model="templateForm.image_url" placeholder="模板原图 URL" />
<el-form-item label="模板图片" required>
<ImageUpload
v-model="templateForm.image_url"
placeholder="上传模板原图"
preview-width="160px"
preview-height="200px"
:max-size="10"
:on-uploaded="onTemplateImageUploaded"
/>
</el-form-item>
<el-form-item label="缩略图URL">
<el-input v-model="templateForm.thumbnail_url" placeholder="可选:缩略图 URL" />
<el-form-item label="缩略图">
<ImageUpload
v-model="templateForm.thumbnail_url"
placeholder="上传缩略图(可选)"
preview-width="100px"
preview-height="100px"
:max-size="5"
/>
</el-form-item>
<el-form-item label="宽度(px)">
<el-input-number v-model="templateForm.width" :min="0" :max="10000" />
@@ -221,6 +240,7 @@
<script setup>
import { onMounted, reactive, ref } from 'vue'
import { ElMessage } from 'element-plus'
import ImageUpload from '../../components/ImageUpload.vue'
import {
createMarketingCategory,
createMarketingTemplate,
@@ -439,6 +459,18 @@ const openTemplateDialog = (row) => {
templateDialogVisible.value = true
}
const onTemplateImageUploaded = (result) => {
if (result.thumbnailUrl && !templateForm.thumbnail_url) {
templateForm.thumbnail_url = result.thumbnailUrl
}
const img = new Image()
img.onload = () => {
templateForm.width = img.naturalWidth
templateForm.height = img.naturalHeight
}
img.src = result.url
}
const saveTemplate = async () => {
if (!(templateForm.title || '').trim()) {
ElMessage.warning('请先填写模板名称')
@@ -449,7 +481,7 @@ const saveTemplate = async () => {
return
}
if (!(templateForm.image_url || '').trim()) {
ElMessage.warning('请先填写图片URL')
ElMessage.warning('请先上传模板图片')
return
}