Files
school-developer/src/views/stuwork/activityinfo/index.vue
2026-03-12 10:45:02 +08:00

281 lines
9.6 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="modern-page-container">
<div class="page-wrapper">
<!-- 内容卡片 -->
<el-card class="content-card" shadow="never">
<template #header>
<div class="card-header">
<span class="card-title">
<el-icon class="title-icon"><Document /></el-icon>
活动信息列表
</span>
<div class="header-actions">
<el-button icon="Plus" type="primary" @click="formDialogRef.openDialog()"> 新增 </el-button>
<right-toolbar v-model:showSearch="showSearch" class="ml10" @queryTable="getDataList">
<TableColumnControl
ref="columnControlRef"
:columns="tableColumns"
v-model="visibleColumns"
trigger-type="default"
trigger-circle
@change="handleColumnChange"
@order-change="handleColumnOrderChange"
>
<template #trigger>
<el-tooltip class="item" effect="dark" content="列设置" placement="top">
<el-button circle style="margin-left: 0">
<el-icon><Menu /></el-icon>
</el-button>
</el-tooltip>
</template>
</TableColumnControl>
</right-toolbar>
</div>
</div>
</template>
<!-- 表格 -->
<el-table
:data="state.dataList"
v-loading="state.loading"
stripe
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
class="modern-table"
>
<el-table-column type="index" label="序号" width="70" align="center">
<template #header>
<el-icon><List /></el-icon>
</template>
<template #default="{ $index }">
{{ $index + 1 + ((state.pagination?.current || 1) - 1) * (state.pagination?.size || 10) }}
</template>
</el-table-column>
<template v-for="col in visibleColumnsSorted" :key="col.prop || col.label">
<el-table-column
v-if="checkColumnVisible(col.prop || '') && col.prop !== '操作'"
:prop="col.prop"
:label="col.label"
:width="col.width"
:min-width="col.minWidth"
:show-overflow-tooltip="col.showOverflowTooltip !== false"
:align="col.align || 'center'"
>
<template #header>
<el-icon v-if="col.icon"><component :is="col.icon" /></el-icon>
<span :style="{ marginLeft: col.icon ? '4px' : '0' }">{{ col.label }}</span>
</template>
<!-- 活动兼报数列特殊模板 -->
<template v-if="col.prop === 'maxSub'" #default="scope">
<el-tag v-if="scope.row.maxSub" size="small" type="success" effect="plain" round>
{{ scope.row.maxSub }}
</el-tag>
<span v-else>-</span>
</template>
<!-- 开始时间列特殊模板 -->
<template v-else-if="col.prop === 'startTime'" #default="scope">
<span>{{ parseTime(scope.row.startTime, '{y}-{m}-{d}') }}</span>
</template>
<!-- 结束时间列特殊模板 -->
<template v-else-if="col.prop === 'endTime'" #default="scope">
<span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
</template>
<el-table-column label="操作" width="300" align="center" fixed="right">
<template #header>
<el-icon><Setting /></el-icon>
<span style="margin-left: 4px">操作</span>
</template>
<template #default="scope">
<el-button icon="View" link type="primary" @click="handleView(scope.row)"> 查看详情 </el-button>
<el-button icon="Upload" link type="success" @click="handleImportSub(scope.row)"> 导入子项目 </el-button>
<el-button icon="EditPen" link type="primary" @click="handleEdit(scope.row)"> 编辑 </el-button>
<el-button icon="Delete" link type="danger" @click="handleDelete(scope.row)"> 删除 </el-button>
</template>
</el-table-column>
<template #empty>
<el-empty description="暂无数据" :image-size="120">
<el-button type="primary" icon="Plus" @click="formDialogRef.openDialog()">新增活动</el-button>
</el-empty>
</template>
</el-table>
<!-- 分页 -->
<div class="pagination-wrapper">
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</div>
</el-card>
</div>
<!-- 新增/编辑表单弹窗 -->
<form-dialog ref="formDialogRef" @refresh="getDataList" />
<!-- 查看详情弹窗 -->
<detail-dialog ref="detailDialogRef" />
<!-- 导入子项目弹窗 -->
<el-dialog title="导入子项目" v-model="importDialogVisible" :width="500" :close-on-click-modal="false" draggable>
<div style="margin-bottom: 15px">
<el-text>活动主题{{ currentActivity?.activityTheme || '-' }}</el-text>
</div>
<el-upload ref="uploadRef" :auto-upload="false" :on-change="handleFileChange" :limit="1" accept=".xlsx,.xls" drag>
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip">
只能上传 xlsx/xls 文件
<el-link type="primary" :underline="false" @click="handleDownloadTemplate">下载导入模板</el-link>
</div>
</template>
</el-upload>
<template #footer>
<span class="dialog-footer">
<el-button @click="importDialogVisible = false"> </el-button>
<el-button type="primary" @click="handleImportSubmit" :disabled="!importFile || importLoading"> </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="ActivityInfo">
import { reactive, ref } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList, delObj, importSub, downloadImportTemplate } from '/@/api/stuwork/activityinfo';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { parseTime } from '/@/utils/formatTime';
import TableColumnControl from '/@/components/TableColumnControl/index.vue';
import { UploadFilled, List, Trophy, Document, UserFilled, Calendar, Setting, Menu } from '@element-plus/icons-vue';
import { useTableColumnControl } from '/@/hooks/tableColumn';
import FormDialog from './form.vue';
import DetailDialog from './detail.vue';
// 定义变量内容
const formDialogRef = ref();
const detailDialogRef = ref();
const uploadRef = ref();
const columnControlRef = ref();
const showSearch = ref(false);
const importDialogVisible = ref(false);
const importFile = ref<File | null>(null);
const importLoading = ref(false);
const currentActivity = ref<any>(null);
// 表格列配置
const tableColumns = [
{ prop: 'activityTheme', label: '活动主题', icon: Trophy, minWidth: 200 },
{ prop: 'remarks', label: '活动说明', icon: Document, minWidth: 300 },
{ prop: 'maxSub', label: '活动兼报数', icon: UserFilled, width: 120 },
{ prop: 'startTime', label: '开始时间', icon: Calendar, width: 120 },
{ prop: 'endTime', label: '结束时间', icon: Calendar, width: 120 },
];
// 使用表格列控制 Hook
const { visibleColumns, visibleColumnsSorted, checkColumnVisible, handleColumnChange, handleColumnOrderChange } = useTableColumnControl(tableColumns);
// 表格样式
const tableStyle = {
cellStyle: { padding: '8px 0' },
headerCellStyle: { background: '#f5f7fa', color: '#606266', fontWeight: 'bold' },
};
// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
props: {
item: 'records',
totalCount: 'total',
},
createdIsNeed: true,
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle: _tableStyle } = useTable(state);
// 查看详情接口getActivityInfoSubList传入活动ID与行数据用于展示
const handleView = (row: any) => {
detailDialogRef.value?.openDialog(row.id, row);
};
// 编辑
const handleEdit = (row: any) => {
formDialogRef.value?.openDialog('edit', row);
};
// 删除
const handleDelete = async (row: any) => {
const { confirm } = useMessageBox();
try {
await confirm('确定要删除该活动吗?');
await delObj([row.id]);
useMessage().success('删除成功');
getDataList();
} catch (err: any) {
if (err !== 'cancel') {
useMessage().error(err.msg || '删除失败');
}
}
};
// 导入子项目
const handleImportSub = (row: any) => {
currentActivity.value = row;
importFile.value = null;
importDialogVisible.value = true;
uploadRef.value?.clearFiles();
};
// 文件变化
const handleFileChange = (file: any) => {
importFile.value = file.raw;
};
// 提交导入
const handleImportSubmit = async () => {
if (!importFile.value) {
useMessage().warning('请选择要上传的文件!');
return;
}
if (!currentActivity.value?.id) {
useMessage().warning('活动信息不存在!');
return;
}
importLoading.value = true;
try {
await importSub(currentActivity.value.id, importFile.value);
useMessage().success('导入成功');
importDialogVisible.value = false;
importFile.value = null;
uploadRef.value?.clearFiles();
} catch (err: any) {
useMessage().error(err.msg || '导入失败');
} finally {
importLoading.value = false;
}
};
// 下载导入模板
const handleDownloadTemplate = async () => {
try {
const res = await downloadImportTemplate();
const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = '活动子项导入模板.xlsx';
link.click();
window.URL.revokeObjectURL(url);
} catch (err: any) {
useMessage().error(err.msg || '下载模板失败');
}
};
</script>
<style scoped lang="scss">
@import '/@/assets/styles/modern-page.scss';
</style>