2026-04-27 13:22:42 +08:00

332 lines
9.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="system-menu-container layout-padding">
<ProTable ref="tableRef" :request-api="appuserPageGet" @selection-change="handleSelectionChange" :columns="columns" :pagination="true" :tool-button="false" :initParams="initParam" row-key="id">
<template #tools>
<el-popconfirm title="确认批量审核吗?" @confirm="onBatchAudit">
<template #reference>
<el-button v-auth="'user:general:audit'" size="small" type="primary"> 批量审核 </el-button>
</template>
</el-popconfirm>
</template>
<template #index="scope">
{{ scope.$index + 1 }}
</template>
<template #auditStatus="scope">
<el-tag :type="getAuditStatusType(scope.row.auditStatus)">
{{ getAuditStatusText(scope.row.auditStatus) }}
</el-tag>
</template>
<template #idCardImageUrl="scope">
<PreviewImage v-if="scope.row.idCardImageUrl" :src="scope.row.idCardImageUrl" width="100px" height="100px" fit="cover" radius="4px" :show-zoom-icon="true" />
<span v-else>-</span>
</template>
<template #action="scope">
<el-button v-auth="'user:general:record'" size="small" text type="primary" @click="onOpenMenu(scope.row)"> 参赛记录 </el-button>
</template>
</ProTable>
<!-- 弹窗 -->
<el-dialog title="参赛记录" v-model="isShowDialog" width="80%" @close="onDialogClose">
<ProTable v-if="isShowDialog" ref="table" :request-api="eventrecordPageGet" :columns="columnsUser" :pagination="true" :tool-button="false" :initParam="initParamUser" preserve-expanded-content>
<!-- 展开列 -->
<el-table-column type="expand">
<template #default="scope">
<div class="expand-content">
<el-table :data="scope.row.items || []" border style="width: 100%; margin-top: 10px;">
<el-table-column label="项目名称" prop="projectName" min-width="150" />
<el-table-column label="项目类型" prop="projectTypeName" width="120" />
<el-table-column label="参赛组别" prop="groupName" width="120" />
<el-table-column label="报名人数" prop="personCount" width="100" align="center" />
<el-table-column label="成绩" prop="score" width="120" />
<el-table-column label="名次" prop="rank" width="100" />
<el-table-column label="操作" width="150" align="center" fixed="right">
<template #default="item">
<el-button size="small" text type="primary" @click="lookBook(scope.row, item.row)">查看证书</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
</el-table-column>
<template #index="scope">
{{ scope.$index + 1 }}
</template>
<template #eventType="scope">
<el-tag :type="scope.row.eventType === 'Online' ? 'primary' : 'success'">
{{ scope.row.eventType === 'Online' ? '线上' : '线下' }}
</el-tag>
</template>
<template #startTime="scope"> {{ scope.row.startTime }} -- {{ scope.row.endTime }} </template>
<template #action="scope">
<el-button v-auth="'user:general:record'" size="small" text type="primary" @click="lookBook(scope.row)"> 查看证书 </el-button>
</template>
</ProTable>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancel">取消</el-button>
<el-button type="primary" @click="onCancel">确定</el-button>
</span>
</template>
</el-dialog>
<!-- 弹窗 -->
<el-dialog title="查看证书" v-model="isShowBook" width="80%">
<div v-if="certificates.length > 0">
<el-table :data="certificates" border>
<el-table-column label="证书名称" prop="name" />
<el-table-column label="获奖等级" prop="awardLevel" />
<el-table-column label="证书类型" prop="certificateType" />
<el-table-column label="查看">
<template #default="scope">
<el-button size="small" text type="primary" @click="openCertificate(scope.row.imageUrl)">查看</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div v-else>暂无证书</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="onCancelB">取消</el-button>
<el-button type="primary" @click="onCancelB">确定</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup name="general">
import { defineAsyncComponent, ref, reactive } from 'vue';
import { ElMessage, ElForm } from 'element-plus';
import SysMenuApi from '/@/api/SysMenuApi';
import { auths } from '/@/utils/authFunction';
import ProTable from '/@/components/ProTable/index.vue';
import { appuserPageGet, appuserAuditPost } from '/@/api/match/appuser';
import { eventrecordPageGet, eventrecordCertificatesGet } from '/@/api/match/eventRecord';
import PreviewImage from '/@/components/PreviewImage/index.vue';
const initParam = ref({
refresh: true,
});
const selectedListIds = ref([]);
const initParamUser = ref({
appUserId: null,
});
const statusList = ['info', 'warning', 'success', 'danger'];
const getAuditStatusText = (status) => {
switch (status) {
case 0:
return '待提交';
case 1:
return '待审核';
case 2:
return '审核通过';
case 3:
return '审核拒绝';
case 4:
return '已取消';
default:
return status;
}
};
const getAuditStatusType = (status) => {
switch (status) {
case 0:
return 'info';
case 1:
return 'warning';
case 2:
return 'success';
case 3:
return 'danger';
case 4:
return 'info';
default:
return 'info';
}
};
const columns = ref([
{ prop: 'ss', type: 'selection' },
{ prop: 'index', label: '序号', align: 'center' },
{ prop: 'name', label: '姓名', search: { el: 'input' } },
{
prop: 'gender',
label: '性别',
search: {
el: 'select',
},
enum: [
{ label: '全部', value: '' },
{ label: '男', value: 0 },
{ label: '女', value: 1 },
],
},
{ prop: 'mobile', label: '联系电话', search: { el: 'input' } },
{ prop: 'idCardImageUrl', label: '身份证', width: '130px' },
{
prop: 'auditStatus',
label: '审核状态',
search: {
el: 'select',
},
enum: [
{ label: '全部', value: '' },
{ label: '未提交', value: 0 },
{ label: '未审核', value: 1 },
{ label: '已通过', value: 2 },
{ label: '未通过', value: 3 },
],
},
{
prop: 'createdTime',
label: '生成时间',
search: {
el: 'date-picker',
props: { type: 'daterange' },
},
},
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', isShow: auths(['user:general:record']) },
]);
const tableRef = ref();
const handleSelectionChange = (val) => {
console.log(val);
selectedListIds.value = val.map((item) => item.id);
};
const statusNameList = ['未提交', '未审核', '已通过', '未通过'];
const columnsUser = ref([
{ prop: 'index', label: '序号', align: 'center' },
{ prop: 'eventName', label: '赛事名称', search: { el: 'input' } },
{ prop: 'eventType', label: '赛事类型', width: '100' },
{
prop: 'startTime',
label: '起止时间',
search: {
el: 'date-picker',
props: { type: 'daterange' },
},
},
{
prop: 'endTime',
label: '起止时间',
isShow: false,
},
{ prop: 'action', label: '操作', align: 'center', fixed: 'right' },
]);
const isShowDialog = ref(false);
const table = ref();
const certificates = ref([]);
const onOpenMenu = (row) => {
console.log(row);
// 参数验证
if (!row || !row.id) {
ElMessage.warning('用户信息无效,无法查看参赛记录');
return;
}
if (typeof row.id !== 'number' || row.id <= 0) {
ElMessage.warning('用户ID无效,请刷新页面后重试');
return;
}
// 设置用户ID参数
initParamUser.value.appUserId = row.id;
isShowDialog.value = true;
// 下次打开对话框时强制刷新数据
initParamUser.value.refresh = Date.now();
};
const onBatchAudit = async () => {
console.log(selectedListIds.value);
const { succeeded, data } = await appuserAuditPost({ ids: selectedListIds.value, status: 2 });
if (succeeded) {
ElMessage.success('操作成功');
// initParam.value.refresh = !initParam.value.refresh;
tableRef.value.clearSelection();
tableRef.value.getTableList();
} else {
ElMessage.error(data);
}
};
const onCancelB = () => {
isShowBook.value = false;
};
// 查看证书
const isShowBook = ref(false);
const lookBook = async (row, item) => {
console.log('查看证书', row, item);
const registrationIds = row.registrationIds || [];
if (registrationIds.length === 0) {
ElMessage.warning('暂无报名记录');
return;
}
const { succeeded, data } = await eventrecordCertificatesGet(registrationIds);
if (succeeded) {
certificates.value = data || [];
isShowBook.value = true;
} else {
ElMessage.error(data);
}
};
// 打开证书图片
const openCertificate = (url) => {
if (url) {
window.open(url, '_blank');
} else {
ElMessage.warning('证书链接无效');
}
};
// 对话框关闭时清理
const onDialogClose = () => {
// 清理参数,避免下次查询时使用旧参数
initParamUser.value = {
appUserId: null,
refresh: Date.now(),
};
};
// 取消
const onCancel = () => {
isShowDialog.value = false;
};
</script>
<style scoped lang="scss">
.dialog-footer {
margin-top: 80px;
}
/* 时长组合框样式 */
.duration-row {
display: flex;
align-items: center;
gap: 8px;
}
.duration-row .el-input {
width: 120px;
}
.duration-separator {
color: #606266;
font-size: 14px;
}
.duration-label {
color: #909399;
font-size: 14px;
}
</style>