This commit is contained in:
lzcode
2026-10-16 14:01:02 +08:00
parent 8fc899d0a9
commit 24d63e6702
3 changed files with 104 additions and 2 deletions
+62 -2
View File
@@ -58,8 +58,30 @@
<el-form-item label="标题">
<el-input v-model="form.title" maxlength="100" show-word-limit />
</el-form-item>
<el-form-item label="封面图 URL">
<el-input v-model="form.cover_url" placeholder="https://..." />
<el-form-item label="封面图">
<div class="cover-upload">
<el-upload
:show-file-list="false"
:auto-upload="false"
accept="image/jpeg,image/png,image/webp,image/gif"
:on-change="(f) => uploadCover(f)"
>
<div v-if="form.cover_url" class="cover-preview">
<img :src="form.cover_url" />
<span v-if="coverUploading" class="mask">上传中…</span>
</div>
<el-button v-else plain :loading="coverUploading">选择图片</el-button>
</el-upload>
<el-button
v-if="form.cover_url"
link type="danger"
style="margin-left: 12px"
@click="form.cover_url = ''"
>移除</el-button>
</div>
</el-form-item>
<el-form-item label="封面 URL">
<el-input v-model="form.cover_url" placeholder="可直接粘贴或通过上方选择上传" />
</el-form-item>
<el-form-item label="分类">
<el-select v-model="form.category_id" placeholder="请选择" style="width: 100%">
@@ -93,11 +115,38 @@ const categories = ref([])
const dialogVisible = ref(false)
const editing = ref(null)
const submitting = ref(false)
const coverUploading = ref(false)
const form = reactive({
title: '', cover_url: '', description: '', category_id: 0,
})
async function uploadCover(file) {
if (!file || !file.raw) return
const allowed = ['image/jpeg', 'image/png', 'image/webp', 'image/gif']
if (!allowed.includes(file.raw.type)) {
return ElMessage.error('仅支持 jpg/png/webp/gif')
}
if (file.raw.size > 5 * 1024 * 1024) {
return ElMessage.error('图片不能超过 5MB')
}
coverUploading.value = true
try {
const fd = new FormData()
fd.append('file', file.raw)
const r = await request({
url: '/admin/upload/image', method: 'post', data: fd,
headers: { 'Content-Type': 'multipart/form-data' },
})
form.cover_url = r.data.url
ElMessage.success('封面上传成功')
} catch (e) {
ElMessage.error(e?.message || '上传失败')
} finally {
coverUploading.value = false
}
}
onMounted(async () => {
load()
try {
@@ -181,4 +230,15 @@ async function del(row) {
.header { display: flex; justify-content: space-between; align-items: center; }
.title-col { display: flex; align-items: center; gap: 8px; }
.cover { width: 40px; height: 40px; border-radius: 4px; object-fit: cover; }
.cover-upload { display: flex; align-items: center; }
.cover-preview {
width: 120px; height: 70px; border-radius: 6px; overflow: hidden;
border: 1px dashed #dcdfe6; cursor: pointer; position: relative;
display: flex; align-items: center; justify-content: center;
}
.cover-preview img { width: 100%; height: 100%; object-fit: cover; }
.cover-preview .mask {
position: absolute; inset: 0; background: rgba(0,0,0,.6);
color: #fff; font-size: 12px; display: flex; align-items: center; justify-content: center;
}
</style>