2026-04-07 09:05:06 +08:00

292 lines
7.5 KiB
Vue

<template>
<div class="system-menu-container layout-padding">
<ProTable
ref="tableRef"
:request-api="eventPagePost"
:columns="columns"
:pagination="true"
:tool-button="false"
:initParam="initParam"
toolButton
>
<template #tools>
<el-button v-auth="'event:add'" type="primary" @click="onOpenMenu()"> 新增 </el-button>
<el-button v-auth="'event:add'" type="primary" @click="showExport"> 导出 </el-button>
</template>
<template #index="scope">
{{ scope.$index + 1 }}
</template>
<template #coverImage="scope">
<el-image :src="scope.row.coverImage" style="height: 80px" fit="cover" />
</template>
<template #eventStatus="scope">
<el-tag :type="getEventStatusTagType(scope.row.eventStatus)">
{{ getEventStatusText(scope.row.eventStatus) }}
</el-tag>
</template>
<template #action="scope">
<el-button v-auth="'event:edit'" size="small" text type="primary" @click="onOpenMenu(scope.row.id)"> 编辑 </el-button>
<el-popconfirm title="确认删除吗?" @confirm="onDeleteMenu(scope.row.id)">
<template #reference>
<el-button v-auth="'event:delete'" size="small" text type="danger"> 删除 </el-button>
</template>
</el-popconfirm>
<el-button v-auth="'event:edit'" size="small" text type="primary" @click="onOpenWorkBench(scope.row.id)"> 赛事工作台 </el-button>
</template>
</ProTable>
<MenuDialog ref="menuDialogRef" @refresh="tableRef?.reset" @update:table="refreshTable" />
<WorkDialog ref="workDialogRef" />
<ExportDialog ref="exportDialogRef" @confirm="onConfirmExport" />
</div>
</template>
<script setup name="event">
import { computed, ref, reactive } from 'vue';
import { ElMessage } from 'element-plus';
import { auths } from '/@/utils/authFunction';
import ProTable from '/@/components/ProTable/index.vue';
import MenuDialog from './dialog.vue';
import WorkDialog from './work.vue';
import ExportDialog from './exportDialog.vue';
import { eventPagePost , eventDeleteDelete , eventExportPost} from '/@/api/match/event';
//table组件实例
const tableRef = ref();
const exportDialogRef = ref();
const initParam = ref({
refresh: true,
});
// 赛事状态映射
const eventStatusMap = {
0: { type: 'info', text: '未开始' },
1: { type: 'success', text: '报名中' },
2: { type: 'warning', text: '报名结束' },
3: { type: 'primary', text: '比赛中' },
4: { type: 'danger', text: '已结束' },
};
const getEventStatusTagType = (status) => {
const normalizedStatus = typeof status === 'string' ? Number(status) : status;
return eventStatusMap[normalizedStatus]?.type ?? 'info';
};
const getEventStatusText = (status) => {
const normalizedStatus = typeof status === 'string' ? Number(status) : status;
return eventStatusMap[normalizedStatus]?.text ?? (status ?? '-');
};
const refreshTable = () =>{
initParam.value.refresh = !initParam.value.refresh
}
const columns = reactive([
{
width: '80px',
prop: 'index',
label: '序号',
align: 'center',
},
{
width: '200px',
prop: 'eventName',
label: '赛事名称',
align: 'center',
search: {
el: 'input',
},
},
{
width: '120px',
prop: 'coverImage',
label: '封面',
align: 'center',
},
{
width: '100px',
prop: 'eventType',
label: '赛事类型',
search: {
el: 'select',
},
enum: [
{ label: '全部', value: '' },
{ label: '线上', value: 0 },
{ label: '线下', value: 1 },
],
},
{
width: '130px',
prop: 'registrationType',
label: '报名方式',
enum: [
{ label: '只允许个人报名', value: 0 },
{ label: '只允许团队报名', value: 1 },
{ label: '两者都有', value: 2 },
],
},
{
width: '130px',
prop: 'chargeMode',
label: '收费模式',
search: {
el: 'select',
},
enum: [
{ label: '全部', value: '' },
{ label: '免费', value: 0 },
{ label: '定价(赛事)', value: 1 },
{ label: '单价(赛事)', value: 2 },
{ label: '单价(项目)', value: 3 },
],
},
{ prop: 'merchantName', label: '收款账户', width: '150px', },
{
width: '100px',
prop: 'eventStatus',
label: '赛事状态',
search: {
el: 'select',
},
enum: [
{ label: '未开始', value: 0 },
{ label: '报名中', value: 1 },
{ label: '报名结束', value: 2 },
{ label: '比赛中', value: 3 },
{ label: '已结束', value: 4 },
],
},
{
width: '160px',
prop: 'registrationStartTime',
label: '报名开始时间',
search: {
el: 'date-picker',
props: {
type: 'date',
},
},
},
{
width: '160px',
prop: 'registrationEndTime',
label: '报名结束时间',
search: {
el: 'date-picker',
props: {
type: 'date',
},
},
},
{
width: '160px',
prop: 'matchStartTime',
label: '比赛开始时间',
search: {
el: 'date-picker',
props: {
type: 'date',
},
},
},
{
width: '160px',
prop: 'matchEndTime',
label: '比赛结束时间',
search: {
el: 'date-picker',
props: {
type: 'date',
},
},
},
{ prop: 'action', label: '操作', align: 'center', width: 200, fixed: 'right', isShow: auths(['event:edit', 'event:delete']) },
]);
const exportableColumns = computed(() =>
columns.filter((item) => item?.prop && item?.label && !['action', 'index'].includes(item.prop))
);
// 定义变量内容
const menuDialogRef = ref();
const workDialogRef = ref();
const getTableSearchParams = () => {
console.log('tableRef.value?.searchParam', tableRef.value?.searchParam);
const searchParam = tableRef.value?.searchParam || {};
const pageNo = tableRef.value?.pageable || {}
return {
...searchParam,
pageNo: pageNo?.pageNo || 1,
pageSize: pageNo?.pageSize || 10,
};
};
const downloadByBlob = (blob, filename = '赛事导出.xlsx') => {
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
};
const showExport = () => {
console.log('tableRef.value?', tableRef.value);
console.log('tableRef.value?.pageable', tableRef.value?.pageable);
exportDialogRef.value?.openDialog(exportableColumns.value);
};
const onConfirmExport = async (exportFields) => {
const payload = {
...getTableSearchParams(),
exportFields,
};
try {
const { succeeded, data, errors } = await eventExportPost(payload);
if (!succeeded) {
ElMessage.error(errors || '导出失败');
return;
}
if (!data) {
ElMessage.warning('未获取到导出文件');
return;
}
// data 是 Base64 编码的文件内容,解码为二进制并下载
const byteCharacters = atob(data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
downloadByBlob(blob, '赛事导出.xlsx');
ElMessage.success('导出成功');
} catch (e) {
ElMessage.error('导出失败');
}
};
// 打开添加编辑菜单弹窗
const onOpenMenu = async (id) => {
await menuDialogRef.value.openDialog(id);
};
const onOpenWorkBench = async(id)=>{
await workDialogRef.value.openDialog(id);
};
//删除菜单
const onDeleteMenu = async (id) => {
const { succeeded, errors } = await eventDeleteDelete({ id });
if (succeeded) {
ElMessage.success('删除成功');
tableRef.value?.reset();
} else {
ElMessage.error(errors);
}
};
</script>
<style scoped lang="scss"></style>