backup: kefu state before examiner-add feature on ExaminerManage
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,17 @@
|
||||
<div class="no-permission-desc">请联系管理员开通权限</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="!isAllClubScope" class="scope-block">
|
||||
<el-alert
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
title="当前为具体小程序视图"
|
||||
description="此处不可新增/编辑/删除全局考核称号。请切换顶栏为「集团汇总」后使用本页;或在「小程序配置 → 抢单考核标签」中仅做上架/下架。"
|
||||
/>
|
||||
<el-button type="primary" link @click="$router.push('/miniapp/kaohe-tags')">前往抢单考核标签</el-button>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<!-- 板块选择 + 添加按钮 -->
|
||||
<div class="section-header">
|
||||
@@ -113,6 +124,9 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import request from '@/utils/request'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { getAdminClubScope } from '@/utils/club-context'
|
||||
|
||||
const isAllClubScope = computed(() => getAdminClubScope() === 'all')
|
||||
|
||||
const username = localStorage.getItem('username') || ''
|
||||
const hasPermission = ref(true)
|
||||
|
||||
@@ -1,8 +1,603 @@
|
||||
<template>
|
||||
<div class="exam-record-page">
|
||||
<div v-if="!hasPermission" class="no-permission">
|
||||
<el-empty description="无考核管理权限,请联系管理员开通 kaohepeizhi" />
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- 统计概览 -->
|
||||
<el-row :gutter="16" class="stats-row">
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card">
|
||||
<div class="stat-label">记录总数</div>
|
||||
<div class="stat-value">{{ stats.total }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card stat-pass">
|
||||
<div class="stat-label">已通过</div>
|
||||
<div class="stat-value">{{ stats.passed }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card stat-fail">
|
||||
<div class="stat-label">未通过</div>
|
||||
<div class="stat-value">{{ stats.failed }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card stat-doing">
|
||||
<div class="stat-label">考核中</div>
|
||||
<div class="stat-value">{{ stats.in_progress }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card stat-wait">
|
||||
<div class="stat-label">待审核</div>
|
||||
<div class="stat-value">{{ stats.pending }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xs="12" :sm="8" :md="4">
|
||||
<el-card shadow="never" class="stat-card stat-fee">
|
||||
<div class="stat-label">累计缴费(元)</div>
|
||||
<div class="stat-value">{{ formatMoney(stats.total_fee) }}</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 标签维度统计 -->
|
||||
<el-card v-if="stats.tag_stats?.length" shadow="never" class="section-card">
|
||||
<template #header>
|
||||
<span class="section-title">各标签考核统计</span>
|
||||
</template>
|
||||
<el-table :data="stats.tag_stats" size="small" stripe>
|
||||
<el-table-column prop="chenghao_name" label="考核标签" min-width="140" />
|
||||
<el-table-column prop="total" label="总数" width="80" align="center" />
|
||||
<el-table-column prop="passed" label="通过" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<span class="text-success">{{ row.passed }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="failed" label="未通过" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<span class="text-danger">{{ row.failed }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="in_progress" label="考核中" width="80" align="center" />
|
||||
<el-table-column prop="pending" label="待审核" width="80" align="center" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- 筛选 -->
|
||||
<el-card shadow="never" class="section-card filter-card">
|
||||
<el-form :inline="true" :model="filter" class="filter-form" @submit.prevent="handleSearch">
|
||||
<el-form-item label="记录ID">
|
||||
<el-input v-model="filter.jilu_id" placeholder="SH..." clearable style="width: 160px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="打手">
|
||||
<el-input v-model="filter.dashou_keyword" placeholder="ID / 昵称 / 手机" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="考核官">
|
||||
<el-input v-model="filter.kaoheguan_keyword" placeholder="ID / 昵称 / 手机" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="板块">
|
||||
<el-select v-model="filter.bankuai_id" placeholder="全部" clearable style="width: 120px">
|
||||
<el-option v-for="b in allBankuai" :key="b.bankuai_id" :label="b.mingcheng" :value="b.bankuai_id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="标签">
|
||||
<el-select v-model="filter.chenghao_id" placeholder="全部" clearable filterable style="width: 140px">
|
||||
<el-option v-for="t in allTags" :key="t.id" :label="t.mingcheng" :value="t.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="filter.zhuangtai" placeholder="全部" clearable style="width: 110px">
|
||||
<el-option label="考核中" :value="0" />
|
||||
<el-option label="已通过" :value="1" />
|
||||
<el-option label="未通过" :value="2" />
|
||||
<el-option label="待审核" :value="3" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="进度">
|
||||
<el-select v-model="filter.assessed" placeholder="全部" clearable style="width: 120px">
|
||||
<el-option label="已考核完" value="done" />
|
||||
<el-option label="未考核完" value="undone" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="第几次">
|
||||
<el-input v-model="filter.cishu" placeholder="次数" clearable style="width: 80px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="时间">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="datetimerange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始"
|
||||
end-placeholder="结束"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
style="width: 340px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
<el-button @click="resetFilter">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-card shadow="never" class="section-card table-card">
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="recordList"
|
||||
stripe
|
||||
border
|
||||
style="width: 100%"
|
||||
class="record-table"
|
||||
empty-text="暂无考核记录"
|
||||
>
|
||||
<el-table-column prop="jilu_id" label="记录ID" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column label="打手" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<div class="user-cell">
|
||||
<el-avatar :size="32" :src="avatarUrl(row.dashou?.avatar)" />
|
||||
<div class="user-meta">
|
||||
<div class="user-name">{{ row.dashou?.nicheng || '-' }}</div>
|
||||
<div class="user-sub">{{ row.dashou?.yonghuid }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="考核官" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.kaoheguan" class="user-cell">
|
||||
<el-avatar :size="32" :src="avatarUrl(row.kaoheguan.avatar)" />
|
||||
<div class="user-meta">
|
||||
<div class="user-name">{{ row.kaoheguan.nicheng }}</div>
|
||||
<div class="user-sub">{{ row.kaoheguan.yonghuid }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tag v-else type="info" size="small">未分配</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bankuai_name" label="板块" width="90" />
|
||||
<el-table-column prop="chenghao_name" label="考核标签" width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="cishu" label="第几次" width="72" align="center" />
|
||||
<el-table-column label="本次费用" width="90" align="right">
|
||||
<template #default="{ row }">¥{{ formatMoney(row.current_fee) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="累计缴费" width="90" align="right">
|
||||
<template #default="{ row }">¥{{ formatMoney(row.jiaofei_jine) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="88" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTagType(row.zhuangtai)" size="small">{{ row.zhuangtai_text }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="CreateTime" label="申请时间" width="168" />
|
||||
<el-table-column label="操作" width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openDetail(row)">详情</el-button>
|
||||
<el-button
|
||||
v-if="row.zhuangtai === 0"
|
||||
link
|
||||
type="warning"
|
||||
@click="handleToPending(row)"
|
||||
>退回待审核</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-wrap">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.page"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
background
|
||||
@current-change="fetchList"
|
||||
@size-change="fetchList"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<!-- 详情抽屉 -->
|
||||
<el-drawer v-model="detailVisible" title="考核记录详情" size="520px" destroy-on-close>
|
||||
<template v-if="detailData">
|
||||
<el-descriptions :column="1" border size="small" class="detail-block">
|
||||
<el-descriptions-item label="记录ID">{{ detailData.jilu_id }}</el-descriptions-item>
|
||||
<el-descriptions-item label="状态">
|
||||
<el-tag :type="statusTagType(detailData.zhuangtai)" size="small">{{ detailData.zhuangtai_text }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="板块">{{ detailData.bankuai_name || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="考核标签">{{ detailData.chenghao_name || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="第几次考核">第 {{ detailData.cishu }} 次</el-descriptions-item>
|
||||
<el-descriptions-item label="申请时间">{{ detailData.CreateTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="更新时间">{{ detailData.UpdateTime }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<h4 class="block-title">打手信息</h4>
|
||||
<div class="profile-card">
|
||||
<el-avatar :size="48" :src="avatarUrl(detailData.dashou?.avatar)" />
|
||||
<div>
|
||||
<div>{{ detailData.dashou?.nicheng }}({{ detailData.dashou?.yonghuid }})</div>
|
||||
<div class="sub">手机:{{ detailData.dashou?.phone || '-' }} · 游戏ID:{{ detailData.dashou?.game_id || '-' }}</div>
|
||||
<div v-if="detailData.dashou?.beizhu" class="sub">备注:{{ detailData.dashou.beizhu }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="block-title">考核官</h4>
|
||||
<div v-if="detailData.kaoheguan" class="profile-card">
|
||||
<el-avatar :size="48" :src="avatarUrl(detailData.kaoheguan.avatar)" />
|
||||
<div>
|
||||
<div>{{ detailData.kaoheguan.nicheng }}({{ detailData.kaoheguan.yonghuid }})</div>
|
||||
<div class="sub">手机:{{ detailData.kaoheguan.phone || '-' }} · 游戏ID:{{ detailData.kaoheguan.game_id || '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="尚未分配考核官" :image-size="60" />
|
||||
|
||||
<h4 v-if="detailData.guize_neirong" class="block-title">考核规则</h4>
|
||||
<div v-if="detailData.guize_neirong" class="rule-box">{{ detailData.guize_neirong }}</div>
|
||||
|
||||
<h4 class="block-title">缴费明细</h4>
|
||||
<el-table :data="detailData.fee_list || []" size="small" border empty-text="暂无明细">
|
||||
<el-table-column prop="cishu" label="第几次" width="80" align="center" />
|
||||
<el-table-column label="金额" align="right">
|
||||
<template #default="{ row }">¥{{ formatMoney(row.jine) }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<h4 class="block-title">拒绝历史</h4>
|
||||
<el-timeline v-if="detailData.reject_list?.length">
|
||||
<el-timeline-item
|
||||
v-for="(item, idx) in detailData.reject_list"
|
||||
:key="idx"
|
||||
:timestamp="item.CreateTime"
|
||||
placement="top"
|
||||
>
|
||||
<div>第 {{ item.cishu }} 次 · 考核官:{{ item.shenheguan_nicheng }}({{ item.shenheguan_id }})</div>
|
||||
<div class="reject-reason">{{ item.yuanyin }}</div>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
<el-empty v-else description="无拒绝记录" :image-size="60" />
|
||||
|
||||
<div v-if="detailData.zhuangtai === 0" class="drawer-actions">
|
||||
<el-button type="warning" @click="handleToPending(detailData, true)">退回待审核(取消指定考核官)</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import request from '@/utils/request'
|
||||
|
||||
const username = localStorage.getItem('username') || ''
|
||||
const hasPermission = ref(true)
|
||||
const loading = ref(false)
|
||||
const recordList = ref([])
|
||||
const allBankuai = ref([])
|
||||
const allTags = ref([])
|
||||
const dateRange = ref(null)
|
||||
|
||||
const stats = reactive({
|
||||
total: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
in_progress: 0,
|
||||
pending: 0,
|
||||
total_fee: 0,
|
||||
tag_stats: [],
|
||||
})
|
||||
|
||||
const filter = reactive({
|
||||
jilu_id: '',
|
||||
dashou_keyword: '',
|
||||
kaoheguan_keyword: '',
|
||||
bankuai_id: null,
|
||||
chenghao_id: null,
|
||||
zhuangtai: null,
|
||||
assessed: null,
|
||||
cishu: '',
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
page: 1,
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
})
|
||||
|
||||
const detailVisible = ref(false)
|
||||
const detailData = ref(null)
|
||||
|
||||
const formatMoney = (val) => {
|
||||
if (val === undefined || val === null) return '0.00'
|
||||
return Number(val).toFixed(2)
|
||||
}
|
||||
|
||||
const avatarUrl = (path) => {
|
||||
if (!path) return ''
|
||||
if (path.startsWith('http')) return path
|
||||
return (window.$ossURL || '') + path
|
||||
}
|
||||
|
||||
const statusTagType = (s) => {
|
||||
const map = { 0: 'warning', 1: 'success', 2: 'danger', 3: 'info' }
|
||||
return map[s] || 'info'
|
||||
}
|
||||
|
||||
const buildParams = () => {
|
||||
const params = {
|
||||
phone: username,
|
||||
page: pagination.page,
|
||||
page_size: pagination.pageSize,
|
||||
}
|
||||
if (filter.jilu_id) params.jilu_id = filter.jilu_id
|
||||
if (filter.dashou_keyword) params.dashou_keyword = filter.dashou_keyword
|
||||
if (filter.kaoheguan_keyword) params.kaoheguan_keyword = filter.kaoheguan_keyword
|
||||
if (filter.bankuai_id != null && filter.bankuai_id !== '') params.bankuai_id = filter.bankuai_id
|
||||
if (filter.chenghao_id != null && filter.chenghao_id !== '') params.chenghao_id = filter.chenghao_id
|
||||
if (filter.zhuangtai != null && filter.zhuangtai !== '') params.zhuangtai = filter.zhuangtai
|
||||
if (filter.assessed) params.assessed = filter.assessed
|
||||
if (filter.cishu) params.cishu = filter.cishu
|
||||
if (dateRange.value?.length === 2) {
|
||||
params.start_time = dateRange.value[0]
|
||||
params.end_time = dateRange.value[1]
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
const fetchList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/khjlgl', buildParams())
|
||||
if (res.code === 0) {
|
||||
const data = res.data || {}
|
||||
recordList.value = Array.isArray(data.list) ? data.list : []
|
||||
pagination.total = Number(data.total) || 0
|
||||
allBankuai.value = data.all_bankuai || []
|
||||
allTags.value = data.all_tags || []
|
||||
const s = data.stats || {}
|
||||
Object.assign(stats, {
|
||||
total: s.total || 0,
|
||||
passed: s.passed || 0,
|
||||
failed: s.failed || 0,
|
||||
in_progress: s.in_progress || 0,
|
||||
pending: s.pending || 0,
|
||||
total_fee: s.total_fee || 0,
|
||||
tag_stats: s.tag_stats || [],
|
||||
})
|
||||
if (pagination.total > 0 && recordList.value.length === 0) {
|
||||
ElMessage.warning('统计有数据但当前页列表为空,请检查后端是否已部署最新 khjlgl 接口')
|
||||
}
|
||||
} else if (res.code === 403) {
|
||||
hasPermission.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg || '加载失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('请求失败:请确认后端已部署 /houtai/khjlgl')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearch = () => {
|
||||
pagination.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const resetFilter = () => {
|
||||
filter.jilu_id = ''
|
||||
filter.dashou_keyword = ''
|
||||
filter.kaoheguan_keyword = ''
|
||||
filter.bankuai_id = null
|
||||
filter.chenghao_id = null
|
||||
filter.zhuangtai = null
|
||||
filter.assessed = null
|
||||
filter.cishu = ''
|
||||
dateRange.value = null
|
||||
pagination.page = 1
|
||||
fetchList()
|
||||
}
|
||||
|
||||
const openDetail = async (row) => {
|
||||
try {
|
||||
const res = await request.post('/houtai/khjlcz', {
|
||||
phone: username,
|
||||
action: 'get_detail',
|
||||
jilu_id: row.jilu_id,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
detailData.value = res.data
|
||||
detailVisible.value = true
|
||||
} else {
|
||||
ElMessage.error(res.msg || '获取详情失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('网络错误')
|
||||
}
|
||||
}
|
||||
|
||||
const handleToPending = async (row, fromDrawer = false) => {
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'将把该记录从「考核中」退回「待审核」,并取消当前考核官指定。是否继续?',
|
||||
'确认操作',
|
||||
{ type: 'warning' },
|
||||
)
|
||||
const res = await request.post('/houtai/khjlcz', {
|
||||
phone: username,
|
||||
action: 'to_pending',
|
||||
jilu_id: row.jilu_id,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success(res.msg || '操作成功')
|
||||
if (fromDrawer) detailVisible.value = false
|
||||
fetchList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '操作失败')
|
||||
}
|
||||
} catch (e) {
|
||||
if (e !== 'cancel') ElMessage.error('操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!username) {
|
||||
ElMessage.error('未登录')
|
||||
return
|
||||
}
|
||||
fetchList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
<style scoped>
|
||||
.exam-record-page {
|
||||
padding: 16px;
|
||||
background: #f5f7fa;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stat-card :deep(.el-card__body) {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.stat-pass .stat-value { color: #67c23a; }
|
||||
.stat-fail .stat-value { color: #f56c6c; }
|
||||
.stat-doing .stat-value { color: #e6a23c; }
|
||||
.stat-wait .stat-value { color: #409eff; }
|
||||
.stat-fee .stat-value { font-size: 18px; }
|
||||
|
||||
.section-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.filter-form {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px 0;
|
||||
}
|
||||
|
||||
/* 仅保证明细表格文字在 Layout 深色背景下可读,不改布局 */
|
||||
.record-table :deep(.el-table__body),
|
||||
.record-table :deep(.el-table__header) {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.record-table :deep(.el-table__header th) {
|
||||
color: #606266;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.user-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
line-height: 1.3;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.user-sub {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.text-success { color: #67c23a; }
|
||||
.text-danger { color: #f56c6c; }
|
||||
|
||||
.pagination-wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.no-permission {
|
||||
padding: 80px 0;
|
||||
}
|
||||
|
||||
.block-title {
|
||||
margin: 20px 0 10px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.profile-card .sub {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.rule-box {
|
||||
padding: 12px;
|
||||
background: #fafafa;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.reject-reason {
|
||||
margin-top: 4px;
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.drawer-actions {
|
||||
margin-top: 24px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.detail-block {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,8 +21,19 @@
|
||||
<el-input v-model="filter.bankuai_name" placeholder="板块名称" clearable class="dark-input filter-input" />
|
||||
<el-button type="primary" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="resetFilter">重置</el-button>
|
||||
<el-button type="success" :disabled="isAllClubScope" @click="openAddDialog">添加考核官</el-button>
|
||||
</div>
|
||||
|
||||
<el-alert
|
||||
v-if="isAllClubScope"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="scope-alert"
|
||||
title="请切换到具体小程序视图后再添加考核官"
|
||||
description="添加考核官只能为本俱乐部用户操作,集团汇总视图下不可用。"
|
||||
/>
|
||||
|
||||
<!-- 板块标签统计(可折叠) -->
|
||||
<el-collapse v-model="activeCollapse" class="stat-collapse">
|
||||
<el-collapse-item title="板块标签统计" name="stats">
|
||||
@@ -211,6 +222,46 @@
|
||||
<el-button v-if="isEditMode" type="success" @click="saveExaminer" :loading="saving">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 添加考核官 -->
|
||||
<el-dialog
|
||||
v-model="addVisible"
|
||||
title="添加考核官"
|
||||
width="520px"
|
||||
@close="closeAddDialog"
|
||||
custom-class="dark-dialog"
|
||||
>
|
||||
<el-form :model="addForm" label-width="110px">
|
||||
<el-form-item label="用户ID" required>
|
||||
<el-input v-model="addForm.yonghuid" placeholder="输入要打手用户ID" clearable class="dark-input" />
|
||||
</el-form-item>
|
||||
<el-form-item label="认证板块" required>
|
||||
<el-select
|
||||
v-model="addForm.bankuai_ids"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="选择板块(可多选)"
|
||||
class="dark-select"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="bk in allBankuaiList"
|
||||
:key="bk.bankuai_id"
|
||||
:label="bk.mingcheng"
|
||||
:value="bk.bankuai_id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="认证状态">
|
||||
<el-switch v-model="addForm.is_renzheng" active-text="已认证" inactive-text="未认证" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="addVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="addSaving" @click="submitAddExaminer">确认添加</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -219,10 +270,12 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import request from '@/utils/request'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { JITUAN_API, getAdminClubScope } from '@/utils/club-context'
|
||||
|
||||
const username = localStorage.getItem('username') || ''
|
||||
const hasPermission = ref(true)
|
||||
const loading = ref(false)
|
||||
const isAllClubScope = computed(() => getAdminClubScope() === 'all')
|
||||
|
||||
// 筛选条件
|
||||
const filter = reactive({
|
||||
@@ -248,6 +301,13 @@ const detailVisible = ref(false)
|
||||
const isEditMode = ref(false)
|
||||
const currentExaminer = ref({})
|
||||
const saving = ref(false)
|
||||
const addVisible = ref(false)
|
||||
const addSaving = ref(false)
|
||||
const addForm = reactive({
|
||||
yonghuid: '',
|
||||
bankuai_ids: [],
|
||||
is_renzheng: true,
|
||||
})
|
||||
|
||||
// 板块标签统计
|
||||
const bankuaiTagsData = ref([])
|
||||
@@ -286,7 +346,7 @@ const fetchExaminerList = async () => {
|
||||
page_size: pagination.pageSize,
|
||||
...filter
|
||||
}
|
||||
const res = await request.post('/houtai/khggl', params)
|
||||
const res = await request.post(JITUAN_API.khggl, params)
|
||||
if (res.code === 0) {
|
||||
const list = (res.data.list || []).map(item => ({
|
||||
...item,
|
||||
@@ -354,7 +414,7 @@ const addBankuai = async () => {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const res = await request.post('/houtai/shgxgsj', {
|
||||
const res = await request.post(JITUAN_API.shgxgsj, {
|
||||
phone: username,
|
||||
yonghuid: currentExaminer.value.yonghuid,
|
||||
action: 'add_bankuai',
|
||||
@@ -382,7 +442,7 @@ const addBankuai = async () => {
|
||||
// 移除板块
|
||||
const removeBankuai = async (bankuaiId) => {
|
||||
try {
|
||||
const res = await request.post('/houtai/shgxgsj', {
|
||||
const res = await request.post(JITUAN_API.shgxgsj, {
|
||||
phone: username,
|
||||
yonghuid: currentExaminer.value.yonghuid,
|
||||
action: 'remove_bankuai',
|
||||
@@ -413,7 +473,7 @@ const saveExaminer = async () => {
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/shgxgsj', payload)
|
||||
const res = await request.post(JITUAN_API.shgxgsj, payload)
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('修改成功')
|
||||
isEditMode.value = false
|
||||
@@ -434,6 +494,53 @@ const saveExaminer = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const openAddDialog = () => {
|
||||
if (isAllClubScope.value) {
|
||||
ElMessage.warning('请切换到具体小程序视图后再添加考核官')
|
||||
return
|
||||
}
|
||||
addForm.yonghuid = ''
|
||||
addForm.bankuai_ids = []
|
||||
addForm.is_renzheng = true
|
||||
addVisible.value = true
|
||||
}
|
||||
|
||||
const closeAddDialog = () => {
|
||||
addVisible.value = false
|
||||
}
|
||||
|
||||
const submitAddExaminer = async () => {
|
||||
const uid = (addForm.yonghuid || '').trim()
|
||||
if (!uid) {
|
||||
ElMessage.warning('请输入用户ID')
|
||||
return
|
||||
}
|
||||
if (!addForm.bankuai_ids.length) {
|
||||
ElMessage.warning('请选择至少一个板块')
|
||||
return
|
||||
}
|
||||
addSaving.value = true
|
||||
try {
|
||||
const res = await request.post(JITUAN_API.khgglAdd, {
|
||||
phone: username,
|
||||
yonghuid: uid,
|
||||
bankuai_ids: addForm.bankuai_ids,
|
||||
is_renzheng: addForm.is_renzheng,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success(res.msg || '添加成功')
|
||||
addVisible.value = false
|
||||
fetchExaminerList()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '添加失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('网络错误')
|
||||
} finally {
|
||||
addSaving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!username) {
|
||||
ElMessage.error('未登录')
|
||||
@@ -474,6 +581,7 @@ onMounted(() => {
|
||||
}
|
||||
.filter-input { width: 160px; }
|
||||
.filter-select { width: 140px; }
|
||||
.scope-alert { margin-bottom: 16px; }
|
||||
|
||||
/* 板块标签统计面板 */
|
||||
.stat-collapse {
|
||||
|
||||
Reference in New Issue
Block a user