feat: 打手详情赠送会员 UI,并改善后台错误提示

新增赠送会员送/改期/移除;请求失败优先展示后端 msg;考核官添加防重复提交。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-17 02:26:09 +08:00
parent fa6b456630
commit 6e7e775c55
5 changed files with 197 additions and 12 deletions

View File

@@ -53,7 +53,7 @@ service.interceptors.response.use(
ElMessage.error('没有权限')
}
} else {
ElMessage.error(error.response.data?.message || '请求失败')
ElMessage.error(error.response.data?.msg || error.response.data?.message || '请求失败')
}
} else {
ElMessage.error('网络错误')

View File

@@ -835,6 +835,10 @@ const confirmAddUser = async () => {
ElMessage.warning('密码和二级密码至少6位')
return
}
if (newUserRoleCodes.value.length === 0) {
ElMessage.warning('请至少选择一个角色')
return
}
addingUser.value = true
try {
const res = await request.post('/houtai/tjyhjs', {

View File

@@ -282,7 +282,7 @@ const saveChenghao = async () => {
ElMessage.error(res.msg || '操作失败')
}
} catch (e) {
ElMessage.error('网络错误')
ElMessage.error(e?.response?.data?.msg || e?.message || '网络错误')
} finally {
saving.value = false
}
@@ -311,7 +311,7 @@ const deleteChenghao = async () => {
ElMessage.error(res.msg || '删除失败')
}
} catch (e) {
ElMessage.error('网络错误')
ElMessage.error(e?.response?.data?.msg || e?.message || '网络错误')
}
}

View File

@@ -510,6 +510,7 @@ const closeAddDialog = () => {
}
const submitAddExaminer = async () => {
if (addSaving.value) return
const uid = (addForm.yonghuid || '').trim()
if (!uid) {
ElMessage.warning('请输入用户ID')
@@ -535,7 +536,7 @@ const submitAddExaminer = async () => {
ElMessage.error(res.msg || '添加失败')
}
} catch (e) {
ElMessage.error('网络错误')
ElMessage.error(e?.response?.data?.msg || e?.message || '网络错误')
} finally {
addSaving.value = false
}

View File

@@ -325,6 +325,46 @@
</div>
</el-card>
<!-- 赠送会员免费接单独立表 -->
<el-card class="info-card" shadow="hover">
<template #header>
<div class="card-header">
<span>🎁 赠送会员免费接单</span>
<el-button
type="success"
size="small"
@click="openGiftDialog()"
:disabled="!hasGiftPermission"
>送会员</el-button>
</div>
<div v-if="!hasGiftPermission" class="member-hint warn">需要打手基础管理或加积分权限</div>
<div v-else class="member-hint">与上方购买会员分开仅用于抢单资格不写购买表</div>
</template>
<div class="member-list">
<div v-for="gift in giftMemberList" :key="'g-' + gift.id" class="member-item gift-item">
<el-tag :type="gift.is_active ? 'success' : 'info'" effect="plain">
{{ gift.huiyuan_name }} 到期: {{ gift.daoqi_time || '--' }}
</el-tag>
<span class="gift-meta">赠送人 {{ gift.song_ren || '--' }} · {{ gift.song_time || '--' }}</span>
<el-button
type="warning"
size="small"
link
@click="openGiftDialog(gift)"
:disabled="!hasGiftPermission"
>改期</el-button>
<el-button
type="danger"
size="small"
link
@click="removeGiftMember(gift)"
:disabled="!hasGiftPermission"
>移除</el-button>
</div>
<div v-if="giftMemberList.length === 0" class="empty-message">暂无赠送会员</div>
</div>
</el-card>
<!-- 其他信息卡片 -->
<el-card class="info-card" shadow="hover">
<template #header>
@@ -377,24 +417,64 @@
<!-- 添加会员弹窗 -->
<el-dialog v-model="memberDialogVisible" title="添加会员" width="400px">
<el-form :model="memberForm" label-width="80px">
<el-form label-width="90px">
<el-form-item label="会员类型" required>
<el-select v-model="memberForm.huiyuan_id" placeholder="请选择会员" style="width: 100%">
<el-select v-model="memberForm.huiyuan_id" placeholder="请选择" filterable style="width: 100%">
<el-option
v-for="item in allMembers"
:key="item.huiyuan_id"
:label="item.jieshao"
:value="item.huiyuan_id"
v-for="m in allMembers"
:key="m.huiyuan_id"
:label="`${m.jieshao} (${m.huiyuan_id})`"
:value="m.huiyuan_id"
/>
</el-select>
</el-form-item>
<el-form-item label="天数" required>
<el-input-number v-model="memberForm.days" :min="1" :step="1" style="width: 100%" />
<el-input-number v-model="memberForm.days" :min="1" :max="3650" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="memberDialogVisible = false">取消</el-button>
<el-button type="primary" @click="addMember" :loading="memberAdding">确认</el-button>
<el-button type="primary" :loading="memberAdding" @click="addMember">确认</el-button>
</template>
</el-dialog>
<!-- 赠送会员弹窗 -->
<el-dialog
v-model="giftDialogVisible"
:title="giftForm.id ? '修改赠送会员到期时间' : '送会员(免费接单)'"
width="420px"
>
<el-form label-width="100px">
<el-form-item label="会员类型" required>
<el-select
v-model="giftForm.huiyuan_id"
placeholder="请选择真实会员类型"
filterable
style="width: 100%"
:disabled="!!giftForm.id"
>
<el-option
v-for="m in allMembers"
:key="'g-' + m.huiyuan_id"
:label="`${m.jieshao} (${m.huiyuan_id})`"
:value="m.huiyuan_id"
/>
</el-select>
</el-form-item>
<el-form-item label="到期日期" required>
<el-date-picker
v-model="giftForm.daoqi_time"
type="datetime"
placeholder="选择到期时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<div class="member-hint">赠送时若积分不是 10将自动改成 10 并写入操作日志</div>
</el-form>
<template #footer>
<el-button @click="giftDialogVisible = false">取消</el-button>
<el-button type="primary" :loading="giftSaving" @click="submitGiftMember">确认</el-button>
</template>
</el-dialog>
</div>
@@ -418,6 +498,7 @@ const username = ref(localStorage.getItem('username') || '')
const playerInfo = ref({})
const originalInfo = ref({})
const memberList = ref([])
const giftMemberList = ref([])
const allMembers = ref([])
const isEditMode = ref(false)
const editData = ref({})
@@ -427,6 +508,11 @@ const memberDialogVisible = ref(false)
const memberForm = reactive({ huiyuan_id: '', days: 30 })
const memberAdding = ref(false)
// 赠送会员弹窗
const giftDialogVisible = ref(false)
const giftSaving = ref(false)
const giftForm = reactive({ id: null, huiyuan_id: '', daoqi_time: '' })
// 权限控制
const userPermissions = ref([])
@@ -436,6 +522,14 @@ const hasMemberPermission = computed(() =>
userPermissions.value.includes('001ff') ||
userPermissions.value.includes('001gg')
)
const hasGiftPermission = computed(() =>
userPermissions.value.includes('000001') ||
userPermissions.value.includes('001aa') ||
userPermissions.value.includes('001bb') ||
userPermissions.value.includes('001cc') ||
userPermissions.value.includes('001dd') ||
userPermissions.value.includes('001ee')
)
const hasChenghaoPermission = computed(() => userPermissions.value.includes('001hh'))
const canChangeInviter = computed(() => userPermissions.value.includes('001ee') || userPermissions.value.includes('000001'))
@@ -536,6 +630,7 @@ const fetchDetail = async () => {
}
originalInfo.value = JSON.parse(JSON.stringify(playerInfo.value))
memberList.value = data.member_list || []
giftMemberList.value = data.gift_member_list || []
allMembers.value = data.all_members || []
userPermissions.value = data.permissions || []
} else if (res.code === 403) {
@@ -714,6 +809,82 @@ const removeMember = async (member) => {
}
// 关键:从路由参数中获取 playerId参数名必须为 playerId
const openGiftDialog = (gift = null) => {
if (!hasGiftPermission.value) {
ElMessage.warning('无赠送会员权限')
return
}
if (gift) {
giftForm.id = gift.id
giftForm.huiyuan_id = gift.huiyuan_id
giftForm.daoqi_time = gift.daoqi_time || ''
} else {
giftForm.id = null
giftForm.huiyuan_id = ''
giftForm.daoqi_time = ''
}
giftDialogVisible.value = true
}
const submitGiftMember = async () => {
if (!giftForm.huiyuan_id) {
ElMessage.warning('请选择会员类型')
return
}
if (!giftForm.daoqi_time) {
ElMessage.warning('请选择到期时间')
return
}
giftSaving.value = true
try {
const payload = {
phone: username.value,
dashou_id: playerId.value,
huiyuan_id: giftForm.huiyuan_id,
daoqi_time: giftForm.daoqi_time,
}
if (giftForm.id) payload.id = giftForm.id
const res = await request.post('/houtai/dszsonghy', payload)
if (res.code === 0) {
ElMessage.success(res.msg || '操作成功')
giftDialogVisible.value = false
await fetchDetail()
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (e) {
ElMessage.error(e?.response?.data?.msg || '操作失败')
} finally {
giftSaving.value = false
}
}
const removeGiftMember = async (gift) => {
try {
await ElMessageBox.confirm(
`确定移除赠送会员“${gift.huiyuan_name}”吗?移除后将无法用该赠送资格抢单。`,
'提示',
{ type: 'warning' }
)
} catch { return }
try {
const res = await request.post('/houtai/dsycsonghy', {
phone: username.value,
dashou_id: playerId.value,
id: gift.id,
huiyuan_id: gift.huiyuan_id,
})
if (res.code === 0) {
ElMessage.success('移除成功')
await fetchDetail()
} else {
ElMessage.error(res.msg || '移除失败')
}
} catch (e) {
ElMessage.error(e?.response?.data?.msg || '移除失败')
}
}
onMounted(() => {
playerId.value = route.params.playerId
if (!playerId.value) {
@@ -737,6 +908,15 @@ onMounted(() => {
flex-direction: column;
gap: 12px;
}
.gift-item {
flex-wrap: wrap;
gap: 6px;
}
.gift-meta {
font-size: 12px;
color: #909399;
margin: 0 4px;
}
.member-item {
display: flex;
justify-content: space-between;