feat: 投诉工单页增加「投诉拦截提现」俱乐部开关

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
XingQue
2026-07-27 00:57:02 +08:00
parent e09e89d9be
commit db18eb4fa8

View File

@@ -1,5 +1,27 @@
<template>
<div class="gongdan-page">
<ClubScopeHint />
<el-card shadow="never" class="config-card" v-loading="configLoading">
<div class="config-row">
<div class="config-main">
<div class="config-title">投诉拦截提现</div>
<div class="config-desc">
开启后当前俱乐部未结清投诉的被投诉人不可提现管事被投诉时上级组长也牵连拦截关闭后仅保留工单不拦提现
</div>
<div v-if="configClubId" class="config-club">当前俱乐部{{ configClubId }}</div>
</div>
<el-switch
v-model="withdrawBlock"
:loading="configSaving"
:disabled="configLoading || configSaving"
inline-prompt
active-text=""
inactive-text=""
@change="onToggleWithdrawBlock"
/>
</div>
</el-card>
<div class="stat-row">
<div class="stat-card danger" @click="quickFilter(1)">
<div class="stat-label">待处理</div>
@@ -35,6 +57,7 @@
<el-option label="已处理" :value="2" />
<el-option label="不满意" :value="3" />
<el-option label="已关闭" :value="4" />
<el-option label="协商中" :value="5" />
</el-select>
</el-form-item>
<el-form-item label="类型">
@@ -44,6 +67,7 @@
<el-option label="罚款投诉" :value="3" />
<el-option label="管事投诉" :value="4" />
<el-option label="被骗投诉" :value="5" />
<el-option label="组长投诉" :value="6" />
</el-select>
</el-form-item>
<el-form-item label="关键词">
@@ -82,6 +106,8 @@
<div class="badge-row">
<el-tag v-if="isPending(row)" type="danger" size="small" effect="dark">待处理</el-tag>
<el-tag v-if="row.zhuangtai === 3" type="warning" size="small" effect="dark">不满意</el-tag>
<el-tag v-if="row.zhuangtai === 5" type="warning" size="small" effect="plain">协商中</el-tag>
<el-tag v-if="row.platform_intervened" type="primary" size="small" effect="dark">平台已介入</el-tag>
<el-tag v-if="(row.shengji_cishu || 0) > 0" type="danger" size="small" effect="plain">
{{ (row.shengji_cishu || 0) + 1 }}次投诉
</el-tag>
@@ -103,20 +129,35 @@
</span>
</template>
</el-table-column>
<el-table-column label="申请人" width="130">
<el-table-column label="申请人" width="150">
<template #default="{ row }">
<div class="id-cell">
<span>{{ row.shenqingren_id || '-' }}</span>
<span>{{ row.complainant_nicheng || row.shenqingren_id || '-' }}</span>
<el-button
v-if="row.shenqingren_id"
type="primary"
link
size="small"
@click.stop="copyText(row.shenqingren_id)"
>复制</el-button>
>复制UID</el-button>
</div>
</template>
</el-table-column>
<el-table-column label="被投诉" width="140">
<template #default="{ row }">
<div v-if="row.target_nicheng || row.target_role_label || row.target_user_id || row.guanshi_id">
<div>{{ row.target_role_label || '' }} {{ row.target_nicheng || '' }}</div>
<el-button
v-if="row.target_user_id || row.guanshi_id"
type="primary"
link
size="small"
@click.stop="copyText(row.target_user_id || row.guanshi_id)"
>复制UID</el-button>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="关联单号" min-width="180">
<template #default="{ row }">
<div v-if="row.order_id" class="id-cell">
@@ -134,12 +175,7 @@
<span class="mono">{{ row.fadan_id }}</span>
<el-button type="primary" link size="small" @click.stop="copyText(row.fadan_id)">复制</el-button>
</div>
<div v-if="row.guanshi_id" class="id-cell">
<span class="muted">管事</span>
<span class="mono">{{ row.guanshi_id }}</span>
<el-button type="primary" link size="small" @click.stop="copyText(row.guanshi_id)">复制</el-button>
</div>
<span v-if="!row.order_id && !row.chongzhi_id && !row.fadan_id && !row.guanshi_id">-</span>
<span v-if="!row.order_id && !row.chongzhi_id && !row.fadan_id">-</span>
</template>
</el-table-column>
<el-table-column prop="shuoming" label="说明" min-width="160" show-overflow-tooltip />
@@ -202,13 +238,30 @@
</div>
<div class="detail-row">
<span class="label">申请人</span>
<span class="value">{{ current.shenqingren_id }}</span>
<span class="value">{{ current.complainant_nicheng || current.shenqingren_id || '-' }}</span>
<el-button
v-if="current.shenqingren_id"
type="primary"
link
@click="copyText(current.shenqingren_id)"
>复制</el-button>
>复制UID</el-button>
</div>
<div v-if="current.target_nicheng || current.target_user_id || current.guanshi_id" class="detail-row">
<span class="label">被投诉</span>
<span class="value">
{{ current.target_role_label || '' }}
{{ current.target_nicheng || '' }}
</span>
<el-button
v-if="current.target_user_id || current.guanshi_id"
type="primary"
link
@click="copyText(current.target_user_id || current.guanshi_id)"
>复制UID</el-button>
</div>
<div v-if="current.platform_intervened" class="detail-row">
<span class="label">介入</span>
<span class="value"><el-tag type="primary" effect="dark" size="small">平台已介入</el-tag></span>
</div>
<div v-if="current.order_id" class="detail-row">
<span class="label">订单ID</span>
@@ -225,11 +278,6 @@
<span class="value mono">{{ current.fadan_id }}</span>
<el-button type="primary" link @click="copyText(current.fadan_id)">复制</el-button>
</div>
<div v-if="current.guanshi_id" class="detail-row">
<span class="label">管事ID</span>
<span class="value mono">{{ current.guanshi_id }}</span>
<el-button type="primary" link @click="copyText(current.guanshi_id)">复制</el-button>
</div>
<div class="detail-row">
<span class="label">创建时间</span>
<span class="value">{{ formatTime(current.CreateTime) }}</span>
@@ -271,7 +319,7 @@
<div class="block-title">处理信息</div>
<div class="detail-row">
<span class="label">处理人</span>
<span class="value">{{ current.chuliren_name || current.chuliren_id || '尚未处理' }}</span>
<span class="value">{{ current.chuliren_name || '尚未处理' }}</span>
</div>
<div class="detail-row">
<span class="label">处理时间</span>
@@ -287,6 +335,12 @@
<div class="block-title">填写处理结果</div>
<el-input v-model="jieguo" type="textarea" :rows="4" placeholder="填写处理结果标记已处理时必填" />
<div class="actions">
<el-button
type="warning"
:loading="saving"
:disabled="!!current.platform_intervened"
@click="handle('intervene')"
>{{ current.platform_intervened ? '已介入' : '标记平台介入' }}</el-button>
<el-button type="primary" :loading="saving" @click="handle('done')">标记已处理</el-button>
<el-button :loading="saving" @click="handle('close')">关闭工单</el-button>
</div>
@@ -300,9 +354,14 @@
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
import ClubScopeHint from '@/components/ClubScopeHint.vue'
const loading = ref(false)
const saving = ref(false)
const configLoading = ref(false)
const configSaving = ref(false)
const withdrawBlock = ref(false)
const configClubId = ref('')
const list = ref([])
const total = ref(0)
const page = ref(1)
@@ -324,11 +383,12 @@ const stats = reactive({
})
function isPending(row) {
return Number(row?.zhuangtai) === 1
const z = Number(row?.zhuangtai)
return z === 1 || z === 5
}
function statusLabel(z) {
return ({ 1: '处理中', 2: '已处理', 3: '不满意', 4: '已关闭' })[Number(z)] || String(z || '')
return ({ 1: '处理中', 2: '已处理', 3: '不满意', 4: '已关闭', 5: '协商中' })[Number(z)] || String(z || '')
}
function statusTagType(z) {
@@ -337,13 +397,14 @@ function statusTagType(z) {
if (n === 2) return 'success'
if (n === 3) return 'warning'
if (n === 4) return 'info'
if (n === 5) return 'warning'
return ''
}
function rowClassName({ row }) {
if (Number(row.zhuangtai) === 1) return 'row-pending'
if (Number(row.zhuangtai) === 1 || Number(row.zhuangtai) === 5) return 'row-pending'
if (Number(row.zhuangtai) === 3) return 'row-dissatisfied'
if ((row.shengji_cishu || 0) > 0 && [1, 3].includes(Number(row.zhuangtai))) return 'row-escalate'
if ((row.shengji_cishu || 0) > 0 && [1, 3, 5].includes(Number(row.zhuangtai))) return 'row-escalate'
return ''
}
@@ -509,10 +570,15 @@ async function handle(action) {
gongdan_id: current.value.gongdan_id,
action,
chuli_jieguo: jieguo.value,
intervene_reason: action === 'intervene' ? 'kefu' : '',
})
if (res.code === 200 || res.code === 0) {
ElMessage.success('已保存')
drawer.value = false
ElMessage.success(action === 'intervene' ? '已标记平台介入' : '已保存')
if (action === 'intervene' && res.data) {
current.value = res.data
} else {
drawer.value = false
}
load(page.value)
} else ElMessage.error(res.message || res.msg || '失败')
} catch (e) {
@@ -522,12 +588,81 @@ async function handle(action) {
}
}
onMounted(() => load(1))
async function loadClubConfig() {
configLoading.value = true
try {
const res = await request.get('/gongdan/admin/club-config/')
if (res.code === 200 || res.code === 0) {
configClubId.value = res.data?.club_id || ''
withdrawBlock.value = !!res.data?.complaint_withdraw_block
}
} catch (e) {
// 旧后端无此接口时忽略
} finally {
configLoading.value = false
}
}
async function onToggleWithdrawBlock(val) {
configSaving.value = true
try {
const res = await request.post('/gongdan/admin/club-config/', {
complaint_withdraw_block: !!val,
})
if (res.code === 200 || res.code === 0) {
withdrawBlock.value = !!res.data?.complaint_withdraw_block
configClubId.value = res.data?.club_id || configClubId.value
ElMessage.success(val ? '已开启投诉拦截提现' : '已关闭投诉拦截提现')
} else {
withdrawBlock.value = !val
ElMessage.error(res.message || res.msg || '保存失败')
}
} catch (e) {
withdrawBlock.value = !val
ElMessage.error('保存失败')
} finally {
configSaving.value = false
}
}
onMounted(() => {
loadClubConfig()
load(1)
})
</script>
<style scoped>
.gongdan-page { padding: 12px; color: #1f2937; }
.config-card {
margin-bottom: 16px;
background: rgba(6, 12, 20, 0.72);
border: 1px solid rgba(0, 242, 255, 0.2);
}
.config-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.config-title {
font-size: 16px;
font-weight: 700;
color: #eef2ff;
margin-bottom: 6px;
}
.config-desc {
font-size: 13px;
line-height: 1.5;
color: rgba(238, 242, 255, 0.72);
max-width: 720px;
}
.config-club {
margin-top: 8px;
font-size: 12px;
color: rgba(0, 242, 255, 0.85);
}
.stat-row {
display: grid;
grid-template-columns: repeat(6, minmax(0, 1fr));