This commit is contained in:
macbook_max
2026-10-15 20:36:59 +08:00
commit 6bf949949c
7923 changed files with 1369582 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
<template>
<div class="page-container">
<el-card shadow="never" class="gift-card">
<template #header>
<span>赠送会员 / 积分</span>
</template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
<el-form-item label="用户 ID" prop="user_ids">
<el-input v-model="form.user_ids" type="textarea" :rows="4"
placeholder="多个用户 ID 用逗号 / 换行 / 空格分隔" />
<div class="text-muted tip">将向解析出的有效数字 ID 去重后赠送</div>
</el-form-item>
<el-form-item label="赠送类型" prop="gift_type">
<el-radio-group v-model="form.gift_type">
<el-radio value="membership">赠送会员</el-radio>
<el-radio value="points">赠送积分</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.gift_type === 'membership'" label="会员套餐" prop="plan_code">
<el-select v-model="form.plan_code" placeholder="请选择会员套餐" style="width: 260px">
<el-option v-for="(text, code) in PLAN_TEXT" :key="code" :label="text" :value="code" />
</el-select>
</el-form-item>
<el-form-item v-if="form.gift_type === 'points'" label="积分数量" prop="points">
<el-input-number v-model="form.points" :min="1" :step="100" style="width: 260px" />
</el-form-item>
<el-form-item label="赠送原因" prop="reason">
<el-input v-model="form.reason" type="textarea" :rows="3" maxlength="200" show-word-limit
placeholder="请填写赠送原因(必填)" />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="submitting" @click="submit">提交赠送</el-button>
</el-form-item>
</el-form>
<div class="text-muted note">
说明:赠送会员写入 membership_orders(source=2),赠送积分写入积分流水(biz_type=5)。
</div>
</el-card>
</div>
</template>
<script setup>
import { ElMessage, ElMessageBox } from 'element-plus'
import { reactive, ref } from 'vue'
import { giftUsers } from '@/api/gift'
const PLAN_TEXT = {
trial: '体验会员',
month: '月卡',
year: '年卡',
lifetime: '终身卡',
}
const formRef = ref()
const submitting = ref(false)
const form = reactive({
user_ids: '',
gift_type: 'membership',
plan_code: 'month',
points: 100,
reason: '',
})
const rules = {
user_ids: [{ required: true, message: '请输入用户 ID', trigger: 'blur' }],
gift_type: [{ required: true, message: '请选择赠送类型', trigger: 'change' }],
plan_code: [{ required: true, message: '请选择会员套餐', trigger: 'change' }],
points: [{ required: true, type: 'number', min: 1, message: '积分需大于 0', trigger: 'blur' }],
reason: [{ required: true, message: '请填写赠送原因', trigger: 'blur' }],
}
/** 解析用户 ID:支持逗号/换行/空格等分隔,过滤非数字并去重 */
function parseUserIds(raw) {
return [
...new Set(
(raw || '')
.split(/[\s,,、;;]+/)
.map((s) => Number(s))
.filter((n) => Number.isInteger(n) && n > 0),
),
]
}
async function submit() {
const valid = await formRef.value.validate().catch(() => false)
if (!valid) return
const userIds = parseUserIds(form.user_ids)
if (!userIds.length) {
ElMessage.warning('请填写有效的用户 ID')
return
}
const desc =
form.gift_type === 'membership'
? `会员(${PLAN_TEXT[form.plan_code]})`
: `${form.points} 积分`
try {
await ElMessageBox.confirm(`将向 ${userIds.length} 个用户赠送 ${desc},确认继续?`, '赠送确认', {
type: 'warning',
})
} catch {
return
}
const payload = {
user_ids: userIds,
gift_type: form.gift_type,
reason: form.reason.trim(),
}
if (form.gift_type === 'membership') {
payload.plan_code = form.plan_code
} else {
payload.points = form.points
}
submitting.value = true
try {
const res = await giftUsers(payload)
const ok = Array.isArray(res?.success) ? res.success.length : res?.success || 0
const fail = Array.isArray(res?.failed) ? res.failed.length : res?.failed || 0
ElMessage.success(`成功 ${ok} 个,失败 ${fail} 个`)
// 表单保留,仅清空用户 ID
form.user_ids = ''
} finally {
submitting.value = false
}
}
</script>
<style scoped>
.gift-card {
max-width: 720px;
}
.tip {
font-size: 12px;
line-height: 1.6;
}
.note {
font-size: 12px;
padding-left: 110px;
}
</style>