Files
gamegroup2/frontend/src/components/game/GameFormDialog.vue
T

184 lines
5.4 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { addGame, updateGame, getGameCoverUrl } from '@/api/games'
import type { Game, GamePlatform } from '@/types'
import { ElMessage } from 'element-plus'
import { getAllPlatforms } from '@/api/games'
import { Plus } from '@element-plus/icons-vue'
import type { UploadFile, UploadInstance } from 'element-plus'
const props = defineProps<{
modelValue: boolean
groupId: string
game?: Game | null
}>()
const emit = defineEmits<{
'update:modelValue': [value: boolean]
'saved': []
}>()
const visible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
const isEdit = computed(() => !!props.game)
const name = ref('')
const aliasesInput = ref('')
const platform = ref<GamePlatform | ''>('')
const tagsInput = ref('')
const coverFile = ref<File | null>(null)
const coverPreview = ref('')
const uploadRef = ref<UploadInstance>()
const loading = ref(false)
const platforms = getAllPlatforms()
watch(() => props.modelValue, (val) => {
if (val && props.game) {
name.value = props.game.name
aliasesInput.value = (props.game.aliases || []).join(', ')
platform.value = props.game.platform || ''
tagsInput.value = (props.game.tags || []).join(', ')
coverFile.value = null
coverPreview.value = getGameCoverUrl(props.game) || ''
} else if (val) {
name.value = ''
aliasesInput.value = ''
platform.value = ''
tagsInput.value = ''
coverFile.value = null
coverPreview.value = ''
}
})
function handleFileChange(uploadFile: UploadFile) {
if (uploadFile.raw) {
coverFile.value = uploadFile.raw
coverPreview.value = URL.createObjectURL(uploadFile.raw)
}
}
function handleFileRemove() {
coverFile.value = null
coverPreview.value = ''
}
async function handleSubmit() {
if (!name.value.trim()) {
ElMessage.warning('请输入游戏名称')
return
}
try {
loading.value = true
const aliases = aliasesInput.value.split(',').map(t => t.trim()).filter(Boolean)
const tags = tagsInput.value.split(',').map(t => t.trim()).filter(Boolean)
if (isEdit.value && props.game) {
await updateGame(props.game.id, {
name: name.value.trim(),
aliases: aliases.length > 0 ? aliases : undefined,
platform: platform.value || undefined,
tags: tags.length > 0 ? tags : undefined,
coverFile: coverFile.value || undefined
})
ElMessage.success('修改成功')
} else {
await addGame(props.groupId, {
name: name.value.trim(),
aliases: aliases.length > 0 ? aliases : undefined,
platform: platform.value || undefined,
tags: tags.length > 0 ? tags : undefined,
coverFile: coverFile.value || undefined
})
ElMessage.success('添加成功')
}
name.value = ''
aliasesInput.value = ''
platform.value = ''
tagsInput.value = ''
coverFile.value = null
coverPreview.value = ''
uploadRef.value?.clearFiles()
emit('saved')
visible.value = false
} catch (error: any) {
ElMessage.error(error.message || (isEdit.value ? '修改失败' : '添加失败'))
} finally {
loading.value = false
}
}
</script>
<template>
<el-dialog v-model="visible" :title="isEdit ? '编辑游戏' : '添加游戏'" width="440px">
<div class="form-fields">
<div class="field">
<label>游戏名称 *</label>
<el-input v-model="name" placeholder="输入游戏名称" maxlength="100" />
</div>
<div class="field">
<label>别名</label>
<el-input v-model="aliasesInput" placeholder="逗号分隔,如: LOL,英雄联盟,撸啊撸" />
</div>
<div class="field">
<label>平台</label>
<el-select v-model="platform" placeholder="选择平台" clearable style="width: 100%">
<el-option v-for="p in platforms" :key="p" :label="p" :value="p" />
</el-select>
</div>
<div class="field">
<label>标签</label>
<el-input v-model="tagsInput" placeholder="逗号分隔,如: MOBA,竞技,5v5" />
</div>
<div class="field">
<label>封面图</label>
<el-upload
ref="uploadRef"
:auto-upload="false"
:limit="1"
accept="image/*"
:on-change="handleFileChange"
:on-remove="handleFileRemove"
drag
>
<div v-if="coverPreview" class="cover-preview">
<img :src="coverPreview" alt="封面预览" />
</div>
<div v-else class="upload-placeholder">
<el-icon :size="28"><Plus /></el-icon>
<span>点击或拖拽上传封面</span>
</div>
</el-upload>
</div>
</div>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" :loading="loading" @click="handleSubmit">{{ isEdit ? '保存' : '添加' }}</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.form-fields { display: flex; flex-direction: column; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 13px; font-weight: 500; color: var(--gg-text-secondary); }
.cover-preview img {
width: 100%;
max-height: 200px;
object-fit: contain;
border-radius: 6px;
}
.upload-placeholder {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 20px;
color: var(--gg-text-muted);
font-size: 13px;
}
</style>