60ad9a04cd
竞猜功能:发起竞猜、下注、关闭、开奖、奖池分配 黑名单功能:标记游戏、按原因/严重程度筛选、详情展开 修复:双重结算、TOCTOU竞态、订阅泄漏、选项选择兼容性 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
206 lines
4.4 KiB
Vue
206 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import { ElMessage } from 'element-plus'
|
|
import { createBlacklistEntry } from '@/api/gameBlacklist'
|
|
import { useGroupStore } from '@/stores/group'
|
|
import { BlacklistReasonMap, BlacklistSeverityMap } from '@/types'
|
|
import type { BlacklistReason, BlacklistSeverity } from '@/types'
|
|
|
|
const visible = defineModel<boolean>({ default: false })
|
|
|
|
const emit = defineEmits<{
|
|
created: []
|
|
}>()
|
|
|
|
const groupStore = useGroupStore()
|
|
|
|
const form = ref({
|
|
gameName: '',
|
|
reason: '' as BlacklistReason | '',
|
|
severity: '' as BlacklistSeverity | '',
|
|
description: '',
|
|
})
|
|
|
|
const loading = ref(false)
|
|
|
|
function resetForm() {
|
|
form.value = {
|
|
gameName: '',
|
|
reason: '',
|
|
severity: '',
|
|
description: '',
|
|
}
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
// 校验必填字段
|
|
if (!form.value.gameName.trim()) {
|
|
ElMessage.warning('请输入游戏名称')
|
|
return
|
|
}
|
|
if (!form.value.reason) {
|
|
ElMessage.warning('请选择原因')
|
|
return
|
|
}
|
|
if (!form.value.severity) {
|
|
ElMessage.warning('请选择严重程度')
|
|
return
|
|
}
|
|
if (!form.value.description.trim()) {
|
|
ElMessage.warning('请填写描述')
|
|
return
|
|
}
|
|
|
|
const groupId = groupStore.currentGroupId
|
|
if (!groupId) {
|
|
ElMessage.error('请先选择群组')
|
|
return
|
|
}
|
|
|
|
loading.value = true
|
|
try {
|
|
await createBlacklistEntry({
|
|
group: groupId,
|
|
gameName: form.value.gameName.trim(),
|
|
reason: form.value.reason,
|
|
severity: form.value.severity,
|
|
description: form.value.description.trim(),
|
|
})
|
|
|
|
visible.value = false
|
|
resetForm()
|
|
ElMessage.success('标记成功')
|
|
emit('created')
|
|
} catch (error: any) {
|
|
ElMessage.error(error.message || '标记失败')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
function handleOpen() {
|
|
resetForm()
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<el-dialog
|
|
v-model="visible"
|
|
title="标记坑游戏"
|
|
width="460px"
|
|
@open="handleOpen"
|
|
>
|
|
<div class="create-form">
|
|
<!-- 游戏名称 -->
|
|
<div class="form-field">
|
|
<label>游戏名称 <span class="required">*</span></label>
|
|
<el-input
|
|
v-model="form.gameName"
|
|
placeholder="输入游戏名称"
|
|
maxlength="100"
|
|
show-word-limit
|
|
/>
|
|
</div>
|
|
|
|
<!-- 原因选择 -->
|
|
<div class="form-field">
|
|
<label>原因 <span class="required">*</span></label>
|
|
<el-select
|
|
v-model="form.reason"
|
|
placeholder="选择原因"
|
|
style="width: 100%"
|
|
>
|
|
<el-option
|
|
v-for="(label, key) in BlacklistReasonMap"
|
|
:key="key"
|
|
:label="label"
|
|
:value="key"
|
|
/>
|
|
</el-select>
|
|
</div>
|
|
|
|
<!-- 严重程度 -->
|
|
<div class="form-field">
|
|
<label>严重程度 <span class="required">*</span></label>
|
|
<el-select
|
|
v-model="form.severity"
|
|
placeholder="选择严重程度"
|
|
style="width: 100%"
|
|
>
|
|
<el-option
|
|
v-for="(label, key) in BlacklistSeverityMap"
|
|
:key="key"
|
|
:label="label"
|
|
:value="key"
|
|
/>
|
|
</el-select>
|
|
</div>
|
|
|
|
<!-- 描述 -->
|
|
<div class="form-field">
|
|
<label>描述 <span class="required">*</span></label>
|
|
<el-input
|
|
v-model="form.description"
|
|
type="textarea"
|
|
placeholder="描述一下为什么这游戏坑"
|
|
:rows="3"
|
|
maxlength="500"
|
|
show-word-limit
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<el-button @click="visible = false">取消</el-button>
|
|
<button class="submit-btn" :disabled="loading" @click="handleSubmit">
|
|
{{ loading ? '提交中...' : '提交' }}
|
|
</button>
|
|
</template>
|
|
</el-dialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.create-form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
.form-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.form-field label {
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
color: var(--gg-text);
|
|
}
|
|
|
|
.required {
|
|
color: var(--gg-danger);
|
|
}
|
|
|
|
.submit-btn {
|
|
padding: 8px 20px;
|
|
border: none;
|
|
border-radius: var(--gg-radius-sm);
|
|
background: var(--gg-primary);
|
|
color: #fff;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.submit-btn:hover {
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.submit-btn:disabled {
|
|
opacity: 0.6;
|
|
cursor: not-allowed;
|
|
}
|
|
</style>
|