292 lines
7.5 KiB
Vue
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>
|