第一次提交:Vue3 后台前端项目当前最新版

This commit is contained in:
XingQue
2026-06-12 22:04:02 +08:00
commit a7f7bd0c39
74 changed files with 30910 additions and 0 deletions

View File

@@ -0,0 +1,420 @@
<template>
<div class="exam-config">
<div v-if="!hasPermission" class="no-permission">
<div class="no-permission-icon">🔒</div>
<div class="no-permission-text">您无权访问此页面</div>
<div class="no-permission-desc">请联系管理员开通权限</div>
</div>
<div v-else>
<!-- 板块选择 + 添加按钮 -->
<div class="section-header">
<div class="header-item">
<span class="label">选择板块</span>
<el-select v-model="currentBankuaiId" placeholder="全部板块" clearable @change="onBankuaiChange" class="dark-select">
<el-option v-for="bk in bankuaiList" :key="bk.bankuai_id" :label="bk.mingcheng" :value="bk.bankuai_id" />
</el-select>
</div>
<el-button type="primary" :icon="Plus" @click="openCreateDialog">添加新称号</el-button>
</div>
<!-- 称号卡片网格 -->
<div class="chenghao-grid" v-loading="loading">
<div v-for="ch in filteredChenghao" :key="ch.id" class="chenghao-card">
<div class="card-header">
<span class="ch-name">{{ ch.mingcheng }}</span>
<span class="ch-type">{{ ch.leixing_name }}</span>
</div>
<div class="card-body">
<div class="info-line"><span>所属板块</span>{{ getBankuaiName(ch.bankuai_id) }}</div>
<div class="info-line"><span>金牌</span>{{ ch.kaioi_jinpai ? '开启' : '关闭' }}</div>
<div class="info-line"><span>创建时间</span>{{ ch.create_time }}</div>
<div class="info-line"><span>考核次数</span>{{ ch.max_cishu }} </div>
</div>
<div class="card-actions">
<el-button size="small" @click="openDetailDialog(ch)">详情</el-button>
</div>
</div>
<div v-if="!loading && filteredChenghao.length === 0" class="empty-state">
<el-empty description="暂无称号数据" />
</div>
</div>
</div>
<!-- 详情/编辑弹窗 -->
<el-dialog
v-model="detailVisible"
:title="isNewChenghao ? '新建称号' : (isEditMode ? '编辑称号' : '称号详情')"
width="700px"
@close="closeDetailDialog"
custom-class="dark-dialog"
>
<el-form :model="currentChenghao" :rules="formRules" ref="detailFormRef" label-width="100px" :disabled="!isEditMode">
<el-form-item label="称号名称" prop="mingcheng">
<el-input v-model="currentChenghao.mingcheng" maxlength="50" />
</el-form-item>
<el-form-item label="类型" prop="leixing">
<el-select v-model="currentChenghao.leixing" class="dark-select">
<el-option label="打手" value="dashou" />
<el-option label="老板" value="boss" />
<el-option label="商家" value="shangjia" />
<el-option label="管事" value="guanshi" />
<el-option label="组长" value="zuzhang" />
</el-select>
</el-form-item>
<el-form-item label="所属板块" prop="bankuai_id">
<el-select v-model="currentChenghao.bankuai_id" placeholder="可选" clearable class="dark-select">
<el-option v-for="bk in bankuaiList" :key="bk.bankuai_id" :label="bk.mingcheng" :value="bk.bankuai_id" />
</el-select>
</el-form-item>
<el-form-item label="特效描述">
<el-input v-model="currentChenghao.texiao_miaoshu" type="textarea" rows="3" />
</el-form-item>
<el-form-item label="考核规则">
<el-input v-model="currentChenghao.kaohe_guize" type="textarea" rows="4" />
</el-form-item>
<el-form-item label="同时开启金牌">
<el-switch v-model="currentChenghao.kaioi_jinpai" :disabled="!isEditMode" />
</el-form-item>
<!-- 考核费用区域 -->
<el-divider content-position="left">考核费用 (每次需缴纳金额)</el-divider>
<div class="feiyong-section">
<div v-if="feiyongList.length === 0" class="empty-feiyong">暂未设置费用</div>
<div v-for="(item, index) in feiyongList" :key="index" class="feiyong-row">
<span class="feiyong-label"> {{ item.cishu }} </span>
<template v-if="isEditMode">
<el-input-number v-model="item.feiyong" :min="0" :step="10" style="width: 140px" />
<el-button v-if="item.cishu > 1" size="small" type="danger" plain @click="removeFeiyong(index)">删除</el-button>
</template>
<template v-else>
<span class="feiyong-value">{{ formatMoney(item.feiyong) }} </span>
</template>
</div>
<el-button v-if="isEditMode" size="small" type="primary" plain @click="addFeiyongRow" class="add-row-btn">
+ 添加新次数
</el-button>
</div>
</el-form>
<template #footer>
<el-button @click="detailVisible = false">取消</el-button>
<el-button v-if="!isEditMode && !isNewChenghao" type="primary" @click="enterEditMode">编辑</el-button>
<el-button v-if="isEditMode" type="success" @click="saveChenghao" :loading="saving">保存</el-button>
<el-button v-if="isEditMode && !isNewChenghao" type="danger" plain @click="deleteChenghao">删除此称号</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import request from '@/utils/request'
import { cloneDeep } from 'lodash-es'
const username = localStorage.getItem('username') || ''
const hasPermission = ref(true)
const loading = ref(false)
// 板块
const bankuaiList = ref([])
const currentBankuaiId = ref(null)
// 称号数据
const allChenghao = ref([])
const filteredChenghao = computed(() => {
if (!currentBankuaiId.value) return allChenghao.value
return allChenghao.value.filter(ch => ch.bankuai_id === currentBankuaiId.value)
})
// 弹窗状态
const detailVisible = ref(false)
const isEditMode = ref(false)
const isNewChenghao = ref(false)
const currentChenghao = ref({})
const feiyongList = ref([]) // [{cishu, feiyong}, ...]
const detailFormRef = ref(null)
const saving = ref(false)
// 表单校验
const formRules = {
mingcheng: [{ required: true, message: '请输入称号名称', trigger: 'blur' }],
leixing: [{ required: true, message: '请选择类型', trigger: 'change' }],
}
// 工具函数
const getBankuaiName = (id) => {
const bk = bankuaiList.value.find(b => b.bankuai_id === id)
return bk ? bk.mingcheng : '未指定'
}
const formatMoney = (val) => {
if (val === undefined || val === null) return '0.00'
return Number(val).toFixed(2)
}
// 获取所有配置
const fetchData = async () => {
loading.value = true
try {
const res = await request.post('/houtai/khpzhq', { phone: username })
if (res.code === 0) {
bankuaiList.value = res.data.bankuai || []
allChenghao.value = res.data.chenghao || []
if (bankuaiList.value.length > 0 && !currentBankuaiId.value) {
currentBankuaiId.value = bankuaiList.value[0].bankuai_id
}
} else if (res.code === 403) {
hasPermission.value = false
} else {
ElMessage.error(res.msg || '获取数据失败')
}
} catch (e) {
ElMessage.error('网络错误')
} finally {
loading.value = false
}
}
// 板块切换
const onBankuaiChange = () => {}
// 打开详情
const openDetailDialog = (ch) => {
isNewChenghao.value = false
isEditMode.value = false
currentChenghao.value = cloneDeep(ch)
// 费用字典转数组排序
const feeDict = ch.feiyong || {}
feiyongList.value = Object.keys(feeDict).map(cishu => ({
cishu: Number(cishu),
feiyong: feeDict[cishu]
})).sort((a, b) => a.cishu - b.cishu)
detailVisible.value = true
}
// 进入编辑模式
const enterEditMode = () => {
isEditMode.value = true
}
// 关闭弹窗
const closeDetailDialog = () => {
detailVisible.value = false
isEditMode.value = false
isNewChenghao.value = false
currentChenghao.value = {}
feiyongList.value = []
}
// 添加新费用次数
const addFeiyongRow = () => {
const maxCishu = feiyongList.value.length > 0
? Math.max(...feiyongList.value.map(f => f.cishu))
: 0
feiyongList.value.push({ cishu: maxCishu + 1, feiyong: 0 })
}
// 删除费用项
const removeFeiyong = (index) => {
feiyongList.value.splice(index, 1)
}
// 保存(创建或更新)
const saveChenghao = async () => {
try {
await detailFormRef.value?.validate()
} catch { return }
// 确保至少有一次费用
if (feiyongList.value.length === 0) {
ElMessage.warning('请至少设置第1次考核费用')
return
}
// 确保序号连续并包含第1次
const cishuSet = new Set(feiyongList.value.map(f => f.cishu))
if (!cishuSet.has(1)) {
ElMessage.warning('必须包含第1次考核费用')
return
}
const payload = {
phone: username,
action: isNewChenghao.value ? 'create' : 'update',
mingcheng: currentChenghao.value.mingcheng,
leixing: currentChenghao.value.leixing,
bankuai_id: currentChenghao.value.bankuai_id,
texiao_miaoshu: currentChenghao.value.texiao_miaoshu || '',
kaohe_guize: currentChenghao.value.kaohe_guize || '',
kaioi_jinpai: currentChenghao.value.kaioi_jinpai,
feiyong_list: feiyongList.value.map(item => ({
cishu: item.cishu,
feiyong: item.feiyong
}))
}
if (!isNewChenghao.value) {
payload.chenghao_id = currentChenghao.value.id
}
saving.value = true
try {
const res = await request.post('/houtai/chzsgc', payload)
if (res.code === 0) {
ElMessage.success(isNewChenghao.value ? '创建成功' : '修改成功')
detailVisible.value = false
await fetchData()
} else {
ElMessage.error(res.msg || '操作失败')
}
} catch (e) {
ElMessage.error('网络错误')
} finally {
saving.value = false
}
}
// 删除称号
const deleteChenghao = async () => {
try {
await ElMessageBox.confirm('确定删除该称号吗?所有相关费用将被清除。', '警告', {
type: 'warning',
confirmButtonText: '确认删除'
})
} catch { return }
try {
const res = await request.post('/houtai/chzsgc', {
phone: username,
action: 'delete',
chenghao_id: currentChenghao.value.id
})
if (res.code === 0) {
ElMessage.success('删除成功')
detailVisible.value = false
await fetchData()
} else {
ElMessage.error(res.msg || '删除失败')
}
} catch (e) {
ElMessage.error('网络错误')
}
}
// 打开创建弹窗
const openCreateDialog = () => {
isNewChenghao.value = true
isEditMode.value = true
currentChenghao.value = {
mingcheng: '',
leixing: 'dashou',
bankuai_id: currentBankuaiId.value || (bankuaiList.value.length > 0 ? bankuaiList.value[0].bankuai_id : null),
texiao_miaoshu: '',
kaohe_guize: '',
kaioi_jinpai: false
}
feiyongList.value = [{ cishu: 1, feiyong: 0 }]
detailVisible.value = true
}
onMounted(() => {
if (!username) {
ElMessage.error('未登录')
return
}
fetchData()
})
</script>
<style scoped>
.exam-config {
padding: 20px;
color: #e0e0e0;
min-height: 100vh;
background: radial-gradient(circle at top, #1a1a2e 0%, #0d0d1a 100%);
}
.no-permission {
text-align: center;
padding: 120px 0;
color: #c0a060;
}
.no-permission-icon { font-size: 64px; filter: drop-shadow(0 0 10px #ffd700); }
.no-permission-text { font-size: 22px; margin: 24px 0 12px; color: #ffd700; }
.no-permission-desc { font-size: 15px; color: #b0a080; }
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
}
.header-item { display: flex; align-items: center; gap: 12px; }
.label { font-weight: bold; color: #ffd700; }
.chenghao-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
}
.chenghao-card {
background: rgba(18,18,30,0.8);
backdrop-filter: blur(14px);
border: 1px solid rgba(255,215,0,0.25);
border-radius: 16px;
padding: 20px;
box-shadow: 0 8px 20px rgba(0,0,0,0.5);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(255,215,0,0.15);
}
.ch-name { font-size: 18px; font-weight: 600; color: #ffd700; }
.ch-type { font-size: 12px; background: rgba(255,215,0,0.15); color: #ffd700; padding: 2px 8px; border-radius: 10px; }
.card-body .info-line { font-size: 13px; color: #ccc; margin-bottom: 6px; }
.card-body .info-line span { color: #888; }
.card-actions { margin-top: 12px; text-align: right; }
.empty-state { margin-top: 40px; }
/* 弹窗暗黑 */
:deep(.dark-dialog) {
background: #1a1a2e !important;
border: 1px solid #ffd700 !important;
border-radius: 20px !important;
}
:deep(.dark-dialog .el-dialog__header) { border-bottom: 1px solid #ffd700; }
:deep(.dark-dialog .el-dialog__title) { color: #ffd700; font-weight: bold; }
/* 费用区域 */
.feiyong-section {
margin-top: 8px;
}
.feiyong-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
}
.feiyong-label { color: #ccc; width: 80px; }
.feiyong-value { color: #ffd700; font-weight: 600; }
.empty-feiyong { color: #888; margin-bottom: 10px; }
.add-row-btn { margin-top: 5px; }
/* 全局控件暗黑 */
:deep(.el-input__inner),
:deep(.el-select .el-input__inner),
:deep(.el-textarea__inner) {
background-color: #2a2a3c !important;
border-color: #ffd700 !important;
color: #e0e0e0 !important;
}
:deep(.el-input-number__decrease),
:deep(.el-input-number__increase) {
background-color: #1f1f30 !important;
color: #ffd700 !important;
}
</style>

View File

@@ -0,0 +1,8 @@
<template>
</template>
<script>
</script>
<style>
</style>

View File

@@ -0,0 +1,586 @@
<template>
<div class="examiner-manager">
<div v-if="!hasPermission" class="no-permission">
<div class="no-permission-icon">🔒</div>
<div class="no-permission-text">您无权访问此页面</div>
<div class="no-permission-desc">请联系管理员开通权限</div>
</div>
<div v-else>
<!-- 顶部筛选栏 -->
<div class="filter-bar">
<el-input v-model="filter.yonghuid" placeholder="用户ID" clearable class="dark-input filter-input" />
<el-select v-model="filter.zhuangtai" placeholder="账号状态" clearable class="dark-select filter-select">
<el-option label="正常" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
<el-select v-model="filter.shenhe_zhuangtai" placeholder="审核官状态" clearable class="dark-select filter-select">
<el-option label="空闲" :value="0" />
<el-option label="审核中" :value="1" />
</el-select>
<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>
</div>
<!-- 板块标签统计可折叠 -->
<el-collapse v-model="activeCollapse" class="stat-collapse">
<el-collapse-item title="板块标签统计" name="stats">
<div class="bankuai-tags-grid">
<div v-for="bk in bankuaiTagsData" :key="bk.bankuai_id" class="bankuai-tags-card">
<div class="card-title">{{ bk.mingcheng }}</div>
<div class="tags-list">
<el-tag v-for="tag in bk.tags" :key="tag.id" size="small" class="tag-item">
{{ tag.name }}{{ tag.user_count }}
</el-tag>
<span v-if="bk.tags.length === 0" class="empty-tip">暂无标签</span>
</div>
</div>
</div>
</el-collapse-item>
</el-collapse>
<!-- 数据表格 -->
<el-table :data="examinerList" style="width: 100%" class="dark-table" v-loading="loading" border>
<el-table-column prop="yonghuid" label="用户ID" width="120" />
<el-table-column prop="phone" label="手机号" width="140" />
<el-table-column prop="nicheng" label="打手昵称" width="120" />
<el-table-column label="认证状态" width="100">
<template #default="{ row }">
<el-tag :type="row.is_renzheng ? 'success' : 'info'">
{{ row.is_renzheng ? '已认证' : '未认证' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="zhuangtai" label="账号状态" width="100">
<template #default="{ row }">
<el-tag :type="row.zhuangtai === 1 ? 'success' : 'danger'">
{{ row.zhuangtai === 1 ? '正常' : '禁用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="shenhe_zhuangtai" label="审核官状态" width="120">
<template #default="{ row }">
<el-tag :type="row.shenhe_zhuangtai === 0 ? 'info' : 'warning'">
{{ row.shenhe_zhuangtai === 0 ? '空闲' : '审核中' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="shenhe_zongshu" label="审核总数" width="100" />
<el-table-column prop="tongguo_zongshu" label="通过总数" width="100" />
<el-table-column prop="yue" label="可提现余额(¥)" width="130">
<template #default="{ row }"> ¥{{ formatMoney(row.yue) }} </template>
</el-table-column>
<el-table-column label="关联板块" min-width="220">
<template #default="{ row }">
<el-tag v-for="bk in row.bankuai" :key="bk.bankuai_id" size="small" class="bankuai-tag">
{{ bk.mingcheng }}({{ bk.dashou_count }})
</el-tag>
<span v-if="row.bankuai.length === 0" class="empty-tip"></span>
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="openDetailDialog(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, 15, 20, 30]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="handlePageChange"
@size-change="handlePageChange"
/>
</div>
</div>
<!-- 详情/编辑弹窗 -->
<el-dialog
v-model="detailVisible"
:title="isEditMode ? '编辑审核官' : '审核官详情'"
width="650px"
@close="closeDetailDialog"
custom-class="dark-dialog"
>
<el-form :model="currentExaminer" label-width="110px" :disabled="!isEditMode">
<el-form-item label="头像">
<img :src="currentExaminer.avatar_full || ''" class="avatar-img" />
</el-form-item>
<el-form-item label="用户ID">
<el-input :model-value="currentExaminer.yonghuid" disabled />
</el-form-item>
<el-form-item label="手机号">
<el-input :model-value="currentExaminer.phone" disabled />
</el-form-item>
<el-form-item label="打手昵称">
<el-input :model-value="currentExaminer.nicheng || ''" disabled />
</el-form-item>
<el-form-item label="认证状态">
<el-switch v-model="currentExaminer.is_renzheng" active-text="已认证" inactive-text="未认证" :disabled="!isEditMode" />
</el-form-item>
<el-form-item label="账号状态">
<el-select v-model="currentExaminer.zhuangtai" class="dark-select" :disabled="!isEditMode">
<el-option label="正常" :value="1" />
<el-option label="禁用" :value="0" />
</el-select>
</el-form-item>
<el-form-item label="审核官状态">
<el-select v-model="currentExaminer.shenhe_zhuangtai" class="dark-select" :disabled="!isEditMode">
<el-option label="空闲" :value="0" />
<el-option label="审核中" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="可提现余额">
<el-input-number v-model="currentExaminer.yue" :min="0" :step="10" :precision="2" :disabled="!isEditMode" />
</el-form-item>
<el-form-item label="审核总数">
<el-input-number :model-value="currentExaminer.shenhe_zongshu" disabled />
</el-form-item>
<el-form-item label="通过总数">
<el-input-number :model-value="currentExaminer.tongguo_zongshu" disabled />
</el-form-item>
<el-form-item label="赚取总额">
<el-input-number :model-value="currentExaminer.zonge" disabled :precision="2" />
</el-form-item>
<!-- 板块管理区域 -->
<el-divider content-position="left">关联板块</el-divider>
<div class="bankuai-manage">
<div class="bankuai-current">
<span class="label">已关联板块</span>
<template v-if="currentExaminer.bankuai && currentExaminer.bankuai.length > 0">
<el-tag
v-for="bk in currentExaminer.bankuai"
:key="bk.bankuai_id"
size="small"
closable
:disable-transitions="false"
@close="removeBankuai(bk.bankuai_id)"
v-if="isEditMode"
class="bankuai-tag"
>
{{ bk.mingcheng }}({{ bk.dashou_count }})
</el-tag>
<template v-if="!isEditMode">
<el-tag v-for="bk in currentExaminer.bankuai" :key="bk.bankuai_id" size="small" class="bankuai-tag">
{{ bk.mingcheng }}({{ bk.dashou_count }})
</el-tag>
</template>
</template>
<span v-else class="empty-tip">暂无关联板块</span>
</div>
<div v-if="isEditMode" class="bankuai-add-row">
<el-select
v-model="pendingBankuaiId"
placeholder="选择板块"
class="dark-select add-select"
size="small"
clearable
@change="onSelectBankuai"
>
<el-option
v-for="bk in availableBankuai"
:key="bk.bankuai_id"
:label="bk.mingcheng"
:value="bk.bankuai_id"
/>
</el-select>
<el-button
type="primary"
size="small"
:disabled="!pendingBankuaiId"
@click="addBankuai"
style="margin-left: 8px;"
>
确认添加
</el-button>
</div>
</div>
</el-form>
<template #footer>
<el-button @click="detailVisible = false">取消</el-button>
<el-button v-if="!isEditMode" type="primary" @click="isEditMode = true">编辑</el-button>
<el-button v-if="isEditMode" type="success" @click="saveExaminer" :loading="saving">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '@/utils/request'
import { cloneDeep } from 'lodash-es'
const username = localStorage.getItem('username') || ''
const hasPermission = ref(true)
const loading = ref(false)
// 筛选条件
const filter = reactive({
yonghuid: '',
zhuangtai: null,
shenhe_zhuangtai: null,
bankuai_name: ''
})
// 分页
const pagination = reactive({
page: 1,
pageSize: 15,
total: 0
})
// 列表数据
const examinerList = ref([])
const allBankuaiList = ref([]) // 所有板块(用于添加时下拉)
// 详情弹窗相关
const detailVisible = ref(false)
const isEditMode = ref(false)
const currentExaminer = ref({})
const saving = ref(false)
// 板块标签统计
const bankuaiTagsData = ref([])
const activeCollapse = ref([]) // 默认收起
// 待添加的板块ID
const pendingBankuaiId = ref(null)
// 当前审核官可添加的板块
const availableBankuai = computed(() => {
if (!currentExaminer.value.bankuai) return allBankuaiList.value
const associatedIds = currentExaminer.value.bankuai.map(b => b.bankuai_id)
return allBankuaiList.value.filter(bk => !associatedIds.includes(bk.bankuai_id))
})
// 格式化金额
const formatMoney = (val) => {
if (val === undefined || val === null) return '0.00'
return Number(val).toFixed(2)
}
// 拼接头像完整URL
const getFullAvatar = (avatar) => {
if (!avatar) return ''
if (avatar.startsWith('http')) return avatar
return (window.$ossURL || '') + avatar
}
// 获取考核官列表
const fetchExaminerList = async () => {
loading.value = true
try {
const params = {
phone: username,
page: pagination.page,
page_size: pagination.pageSize,
...filter
}
const res = await request.post('/houtai/khggl', params)
if (res.code === 0) {
const list = (res.data.list || []).map(item => ({
...item,
avatar_full: getFullAvatar(item.avatar)
}))
examinerList.value = list
pagination.total = res.data.total || 0
allBankuaiList.value = res.data.all_bankuai || []
bankuaiTagsData.value = res.data.bankuai_tags || [] // 接收板块标签数据
} else if (res.code === 403) {
hasPermission.value = false
} else {
ElMessage.error(res.msg || '获取数据失败')
}
} catch (e) {
ElMessage.error('网络错误')
} finally {
loading.value = false
}
}
// 搜索
const handleSearch = () => {
pagination.page = 1
fetchExaminerList()
}
// 重置
const resetFilter = () => {
filter.yonghuid = ''
filter.zhuangtai = null
filter.shenhe_zhuangtai = null
filter.bankuai_name = ''
handleSearch()
}
// 翻页
const handlePageChange = () => {
fetchExaminerList()
}
// 打开详情弹窗(查看模式)
const openDetailDialog = (row) => {
const detail = cloneDeep(row)
detail.avatar_full = getFullAvatar(detail.avatar)
currentExaminer.value = detail
isEditMode.value = false
pendingBankuaiId.value = null
detailVisible.value = true
}
// 关闭详情弹窗
const closeDetailDialog = () => {
detailVisible.value = false
isEditMode.value = false
currentExaminer.value = {}
pendingBankuaiId.value = null
}
// 添加板块
const addBankuai = async () => {
const bankuaiId = pendingBankuaiId.value
if (!bankuaiId) {
ElMessage.warning('请先选择板块')
return
}
try {
const res = await request.post('/houtai/shgxgsj', {
phone: username,
yonghuid: currentExaminer.value.yonghuid,
action: 'add_bankuai',
bankuai_id: bankuaiId
})
if (res.code === 0) {
ElMessage.success('板块添加成功')
const bk = allBankuaiList.value.find(b => b.bankuai_id === bankuaiId)
if (bk) {
currentExaminer.value.bankuai.push({
bankuai_id: bankuaiId,
mingcheng: bk.mingcheng,
dashou_count: 0
})
}
pendingBankuaiId.value = null
} else {
ElMessage.error(res.msg || '添加失败')
}
} catch (e) {
ElMessage.error('网络错误')
}
}
// 移除板块
const removeBankuai = async (bankuaiId) => {
try {
const res = await request.post('/houtai/shgxgsj', {
phone: username,
yonghuid: currentExaminer.value.yonghuid,
action: 'remove_bankuai',
bankuai_id: bankuaiId
})
if (res.code === 0) {
ElMessage.success('板块移除成功')
currentExaminer.value.bankuai = currentExaminer.value.bankuai.filter(b => b.bankuai_id !== bankuaiId)
} else {
ElMessage.error(res.msg || '移除失败')
}
} catch (e) {
ElMessage.error('网络错误')
}
}
// 保存基本信息
const saveExaminer = async () => {
const payload = {
phone: username,
yonghuid: currentExaminer.value.yonghuid,
action: 'update_info',
yue: currentExaminer.value.yue,
zhuangtai: currentExaminer.value.zhuangtai,
shenhe_zhuangtai: currentExaminer.value.shenhe_zhuangtai,
is_renzheng: currentExaminer.value.is_renzheng
}
saving.value = true
try {
const res = await request.post('/houtai/shgxgsj', payload)
if (res.code === 0) {
ElMessage.success('修改成功')
isEditMode.value = false
const index = examinerList.value.findIndex(item => item.yonghuid === currentExaminer.value.yonghuid)
if (index !== -1) {
examinerList.value[index].zhuangtai = currentExaminer.value.zhuangtai
examinerList.value[index].shenhe_zhuangtai = currentExaminer.value.shenhe_zhuangtai
examinerList.value[index].yue = currentExaminer.value.yue
examinerList.value[index].is_renzheng = currentExaminer.value.is_renzheng
}
} else {
ElMessage.error(res.msg || '修改失败')
}
} catch (e) {
ElMessage.error('网络错误')
} finally {
saving.value = false
}
}
onMounted(() => {
if (!username) {
ElMessage.error('未登录')
return
}
fetchExaminerList()
})
</script>
<style scoped>
.examiner-manager {
padding: 20px;
color: #e0e0e0;
background: radial-gradient(circle at top, #1a1a2e 0%, #0d0d1a 100%);
min-height: 100vh;
}
.no-permission {
text-align: center;
padding: 120px 0;
color: #c0a060;
}
.no-permission-icon { font-size: 64px; filter: drop-shadow(0 0 10px #ffd700); }
.no-permission-text { font-size: 22px; margin: 24px 0 12px; color: #ffd700; }
.no-permission-desc { font-size: 15px; color: #b0a080; }
.filter-bar {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 20px;
padding: 16px;
background: rgba(18,18,30,0.8);
backdrop-filter: blur(14px);
border: 1px solid rgba(255,215,0,0.2);
border-radius: 12px;
align-items: center;
}
.filter-input { width: 160px; }
.filter-select { width: 140px; }
/* 板块标签统计面板 */
.stat-collapse {
margin-bottom: 20px;
background: rgba(18,18,30,0.8);
border: 1px solid rgba(255,215,0,0.2);
border-radius: 12px;
overflow: hidden;
}
.bankuai-tags-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
padding: 10px;
}
.bankuai-tags-card {
background: rgba(255,255,255,0.05);
border-radius: 8px;
padding: 12px;
border: 1px solid rgba(255,215,0,0.1);
}
.card-title {
color: #ffd700;
font-weight: bold;
margin-bottom: 8px;
font-size: 16px;
}
.tags-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.tag-item {
background: rgba(255,215,0,0.15);
border-color: #ffd700;
color: #ffd700;
}
.empty-tip {
color: #888;
font-size: 14px;
}
/* 表格暗黑主题 */
:deep(.dark-table) {
--el-table-bg-color: rgba(18,18,30,0.7);
--el-table-tr-bg-color: transparent;
--el-table-header-bg-color: rgba(0,0,0,0.5);
--el-table-border-color: rgba(255,215,0,0.15);
--el-table-text-color: #e0e0e0;
--el-table-header-text-color: #ffd700;
margin-bottom: 20px;
}
.bankuai-tag {
margin-right: 6px;
margin-bottom: 4px;
background: rgba(255,215,0,0.15);
border-color: #ffd700;
color: #ffd700;
}
.empty-tip { color: #888; }
.pagination-wrap {
display: flex;
justify-content: center;
margin-top: 20px;
}
/* 详情弹窗 */
:deep(.dark-dialog) {
background: #1a1a2e !important;
border: 1px solid #ffd700 !important;
border-radius: 20px !important;
}
:deep(.dark-dialog .el-dialog__header) { border-bottom: 1px solid #ffd700; }
:deep(.dark-dialog .el-dialog__title) { color: #ffd700; font-weight: bold; }
.bankuai-manage { margin-top: 10px; }
.bankuai-current { margin-bottom: 12px; display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.bankuai-current .label { color: #ccc; }
.bankuai-add-row { display: flex; align-items: center; margin-top: 10px; }
.add-select { width: 200px; }
:deep(.dark-input .el-input__inner),
:deep(.dark-select .el-input__inner),
:deep(.el-input-number .el-input__inner) {
background-color: #2a2a3c !important;
border-color: #ffd700 !important;
color: #e0e0e0 !important;
}
:deep(.el-input-number__decrease),
:deep(.el-input-number__increase) {
background-color: #1f1f30 !important;
color: #ffd700 !important;
}
:deep(.el-button--primary) {
background: linear-gradient(135deg, #ffd700, #f0a500) !important;
border: none !important;
color: #000 !important;
font-weight: bold;
}
.avatar-img {
width: 60px;
height: 60px;
border-radius: 50%;
border: 2px solid #ffd700;
object-fit: cover;
}
</style>