vue3的前端页面<template>
<!-- 权限检查:只有 SYSADMIN 能看到页面内容 -->
<div v-if="form.usepermission === 'SYSADMIN'">
<div style="width: 100%; overflow-x: auto; padding: 16px; box-sizing: border-box;">
<!-- 查询区域:添加Flex布局实现左右分布 -->
<div class="search-area">
<el-form :inline="true" :model="queryParams" class="demo-form-inline">
<!-- 左侧区域:关键词、查询、重置 -->
<div class="form-left">
<el-form-item label="关键词">
<el-input v-model="queryParams.keyword" placeholder="课程关键词/工号/姓名"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery" icon="el-icon-search">查询</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</div>
<!-- 右侧区域:审核按钮、下载按钮 -->
<div class="form-right">
<el-form-item>
<el-button type="primary" @click="handleParticipate">
{{ isAuditMode ? '取消审核' : '参训审核' }}
</el-button>
</el-form-item>
<el-form-item>
<el-button @click="handleDownload">DOWNLOAD <i class="el-icon-download"></i></el-button>
</el-form-item>
</div>
</el-form>
</div>
<!-- 当前筛选条件显示 -->
<div v-if="hasActiveFilters" class="active-filters">
<span class="filters-label">当前筛选:</span>
<el-tag
v-for="(value, column) in filters"
:key="column"
closable
type="primary"
@close="clearFilter(column)"
class="filter-tag"
>
{{ getColumnLabel(column) }}: {{ value }}
</el-tag>
<el-button type="text" @click="clearAllFilters" class="clear-all">清除所有</el-button>
</div>
<!-- 表格区域 -->
<div class="table-area">
<el-table
ref="multipleTableRef"
:data="filteredTableData"
border
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="35"></el-table-column>
<!-- 序号列 -->
<el-table-column prop="id" label="序号" width="55">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.id }">
<span>序号</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.id }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'id', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.id }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="id in getUniqueValues('id')"
:key="id"
:command="{ column: 'id', value: id }"
:class="{ 'dropdown-item-active': filters.id === id }"
>
{{ id }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 区分列 -->
<el-table-column prop="category" label="区分" width="100">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.category }">
<span>区分</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.category }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'category', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.category }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="category in getUniqueValues('category')"
:key="category"
:command="{ column: 'category', value: category }"
:class="{ 'dropdown-item-active': filters.category === category }"
>
{{ category }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 等级列 -->
<el-table-column prop="level" label="等级" width="80">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.level }">
<span>等级</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.level }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'level', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.level }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="level in getUniqueValues('level')"
:key="level"
:command="{ column: 'level', value: level }"
:class="{ 'dropdown-item-active': filters.level === level }"
>
{{ level }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 课程名称列 -->
<el-table-column prop="coursename" label="课程名称" width="120">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.coursename }">
<span>课程名称</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.coursename }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'coursename', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.coursename }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="course in getUniqueValues('coursename')"
:key="course"
:command="{ column: 'coursename', value: course }"
:class="{ 'dropdown-item-active': filters.coursename === course }"
>
{{ course }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 期数列 -->
<el-table-column prop="period" label="期数" width="80">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.period }">
<span>期数</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.period }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'period', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.period }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="period in getUniqueValues('period')"
:key="period"
:command="{ column: 'period', value: period }"
:class="{ 'dropdown-item-active': filters.period === period }"
>
{{ period }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 姓名列 -->
<el-table-column prop="name" label="姓名" width="80">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.name }">
<span>姓名</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.name }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'name', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.name }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="name in getUniqueValues('name')"
:key="name"
:command="{ column: 'name', value: name }"
:class="{ 'dropdown-item-active': filters.name === name }"
>
{{ name }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 工号列 -->
<el-table-column prop="employeeid" label="工号" width="80">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.employeeid }">
<span>工号</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.employeeid }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'employeeid', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.employeeid }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="empId in getUniqueValues('employeeid')"
:key="empId"
:command="{ column: 'employeeid', value: empId }"
:class="{ 'dropdown-item-active': filters.employeeid === empId }"
>
{{ empId }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- Team列 -->
<el-table-column prop="team" label="Team" width="80">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.team }">
<span>Team</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.team }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'team', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.team }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="team in getUniqueValues('team')"
:key="team"
:command="{ column: 'team', value: team }"
:class="{ 'dropdown-item-active': filters.team === team }"
>
{{ team }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- Group列 -->
<el-table-column prop="grouptext" label="Group" width="100">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.grouptext }">
<span>Group</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.grouptext }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'grouptext', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.grouptext }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="group in getUniqueValues('grouptext')"
:key="group"
:command="{ column: 'grouptext', value: group }"
:class="{ 'dropdown-item-active': filters.grouptext === group }"
>
{{ group }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- Part列 -->
<el-table-column prop="department" label="Part" width="110">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.department }">
<span>Part</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.department }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'department', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.department }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="dept in getUniqueValues('department')"
:key="dept"
:command="{ column: 'department', value: dept }"
:class="{ 'dropdown-item-active': filters.department === dept }"
>
{{ dept }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 联系方式列 -->
<el-table-column prop="contact" label="联系方式" width="90">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.contact }">
<span>联系方式</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.contact }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'contact', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.contact }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="contact in getUniqueValues('contact')"
:key="contact"
:command="{ column: 'contact', value: contact }"
:class="{ 'dropdown-item-active': filters.contact === contact }"
>
{{ contact }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
<!-- 参训现况列 -->
<el-table-column prop="status" label="参训现况" width="120">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.status }">
<span>参训现况</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.status }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'status', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.status }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="status in getUniqueValues('status')"
:key="status"
:command="{ column: 'status', value: status }"
:class="{ 'dropdown-item-active': filters.status === status }"
>
{{ status }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
<template #default="scope">
<el-select v-model="scope.row.status" placeholder="请选择" @change="handleStatusChange(scope.row)">
<el-option label="参加" value="参加"></el-option>
<el-option label="未参加" value="未参加"></el-option>
</el-select>
</template>
</el-table-column>
<!-- 审核状态列 -->
<el-table-column prop="auditstatus" label="审核状态" width="120">
<template #header>
<div class="filter-header" :class="{ 'filter-active': filters.auditstatus }">
<span>审核状态</span>
<el-dropdown trigger="click" @command="handleFilter">
<el-icon :class="{ 'filter-icon-active': filters.auditstatus }"><Filter /></el-icon>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
:command="{ column: 'auditstatus', value: 'all' }"
:class="{ 'dropdown-item-active': !filters.auditstatus }"
>
全部
</el-dropdown-item>
<el-dropdown-item
v-for="auditStatus in getUniqueValues('auditstatus')"
:key="auditStatus"
:command="{ column: 'auditstatus', value: auditStatus }"
:class="{ 'dropdown-item-active': filters.auditstatus === auditStatus }"
>
{{ auditStatus }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</el-table-column>
</el-table>
<!-- 审核操作按钮:仅isAuditMode为true时显示 -->
<div v-if="isAuditMode" class="action-buttons" style="margin: 10px 0;">
<el-button type="primary" @click="handleApprove">审核通过</el-button>
<el-button type="danger" @click="handleReject">审核不通过</el-button>
</div>
<div class="pagination">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryParams.pageNum"
:page-sizes="[10, 20, 50]"
:page-size="queryParams.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="filteredTotal">
</el-pagination>
</div>
</div>
</div>
</div>
<!-- 无权限时的提示 -->
<div v-else class="permission-denied">
<el-result
icon="warning"
title="权限不足"
sub-title="您没有访问此页面的权限,请联系管理员。"
>
<template #extra>
<el-button type="primary" @click="handleGoBack">返回</el-button>
<el-button @click="handleContactAdmin">联系管理员</el-button>
</template>
</el-result>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import axios from 'axios'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Filter } from '@element-plus/icons-vue'
import { useUserStore } from '@/stores/auth'
const router = useRouter()
const userStore = useUserStore()
// 用户权限信息
const form = ref({
usepermission: userStore.permission || ''
})
console.log('我的权限:', form.value.usepermission)
// 查询参数
const queryParams = reactive({
keyword: '',
pageNum: 1,
pageSize: 10
})
// 表格数据
const tableData = ref([])
// 筛选条件
const filters = reactive({})
// 总条数
const total = ref(0)
// 选中数据
const multipleSelection = ref([])
// 表格引用
const multipleTableRef = ref(null)
// 核心状态变量:仅通过"参训审核/取消审核"按钮修改
const isAuditMode = ref(false)
// 列名映射
const columnLabels = {
id: '序号',
category: '区分',
level: '等级',
coursename: '课程名称',
period: '期数',
name: '姓名',
employeeid: '工号',
team: 'Team',
grouptext: 'Group',
department: 'Part',
contact: '联系方式',
status: '参训现况',
auditstatus: '审核状态'
}
// 获取列标签
const getColumnLabel = (column) => {
return columnLabels[column] || column
}
// 检查是否有活跃的筛选条件
const hasActiveFilters = computed(() => {
return Object.keys(filters).length > 0
})
// 获取唯一值列表
const getUniqueValues = (column) => {
const values = tableData.value.map(item => item[column]).filter(Boolean)
return [...new Set(values)]
}
// 处理筛选
const handleFilter = (command) => {
const { column, value } = command
if (value === 'all') {
// 删除该列的筛选条件
delete filters[column]
} else {
// 设置筛选条件
filters[column] = value
}
// 重置到第一页
queryParams.pageNum = 1
}
// 清除单个筛选条件
const clearFilter = (column) => {
delete filters[column]
}
// 清除所有筛选条件
const clearAllFilters = () => {
Object.keys(filters).forEach(key => {
delete filters[key]
})
}
// 筛选后的数据
const filteredTableData = computed(() => {
let filtered = tableData.value
// 应用所有筛选条件
Object.keys(filters).forEach(column => {
filtered = filtered.filter(item => item[column] === filters[column])
})
return filtered
})
// 筛选后的总条数
const filteredTotal = computed(() => filteredTableData.value.length)
// 获取表格数据
const fetchData = async () => {
// 如果没有权限,不执行数据获取
if (form.value.usepermission !== 'SYSADMIN') {
return
}
try {
const res = await axios.get('/api/training/list', { params: queryParams })
// 处理数据:接口返回的status为空时,默认设为"未参加"
const formattedData = res.data.data.records.map(record => ({
...record,
status: record.status ?? '未参加'
}))
tableData.value = formattedData
total.value = res.data.total
// 重置筛选条件
Object.keys(filters).forEach(key => delete filters[key])
} catch (error) {
console.error(error)
ElMessage.error('获取数据失败')
}
}
// 查询按钮点击事件
const handleQuery = () => {
queryParams.pageNum = 1
fetchData()
}
// 重置按钮点击事件
const handleReset = () => {
queryParams.keyword = ''
queryParams.pageNum = 1
// 重置筛选条件
Object.keys(filters).forEach(key => delete filters[key])
fetchData()
}
// 多选框选中数据
const handleSelectionChange = (selection) => {
multipleSelection.value = selection
}
// 分页大小变化
const handleSizeChange = (val) => {
queryParams.pageSize = val
fetchData()
}
// 当前页变化
const handleCurrentChange = (val) => {
queryParams.pageNum = val
fetchData()
}
// 参训审核/取消审核按钮点击事件
const handleParticipate = () => {
isAuditMode.value = !isAuditMode.value
}
// 审核通过按钮点击事件
const handleApprove = () => {
if (multipleSelection.value.length === 0) {
ElMessage.warning('请先选择需要审核的记录')
return
}
const hasUnparticipated = multipleSelection.value.some(row => row.status !== '参加')
if (hasUnparticipated) {
ElMessage.warning('未参加培训,不能通过')
return
}
batchUpdateStatus('通过')
}
// 审核不通过按钮点击事件
const handleReject = () => {
if (multipleSelection.value.length === 0) {
ElMessage.warning('请先选择需要审核的记录')
return
}
batchUpdateStatus('不通过')
}
// 批量更新审核状态
const batchUpdateStatus = async (status) => {
const selectedIds = multipleSelection.value.map(item => item.id)
ElMessageBox.confirm(`确定要将选中记录审核为"${status}"吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
await axios.put('/api/training/batchStatus', { ids: selectedIds, status })
ElMessage.success('审核成功')
fetchData()
} catch (error) {
console.error(error)
ElMessage.error('审核失败')
}
}).catch(() => {
// 用户取消操作
})
}
// 审核状态变化(单行更新)
const handleStatusChange = async (row) => {
try {
await axios.put(`/api/training/status/${row.id}`, { status: row.status })
ElMessage.success('更新成功')
} catch (error) {
console.error(error)
ElMessage.error('更新失败')
fetchData()
}
}
// 下载按钮点击事件
const handleDownload = () => {
window.open('/api/training/download', '_blank')
}
// 返回上一页
const handleGoBack = () => {
router.back()
}
// 联系管理员
const handleContactAdmin = () => {
ElMessage.info('请联系系统管理员获取权限')
}
// 初始化数据
onMounted(() => {
// 只有 SYSADMIN 权限才获取数据
if (form.value.usepermission === 'SYSADMIN') {
fetchData()
} else {
console.log('当前用户无权限访问此页面,权限为:', form.value.usepermission)
}
})
</script>
<style scoped>
.search-area {
margin-bottom: 10px;
}
.demo-form-inline {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
.form-left .el-form-item {
margin-right: 10px;
}
.form-right .el-form-item {
margin-left: 10px;
}
.action-buttons {
text-align: left;
}
.pagination {
margin-top: 10px;
text-align: right;
}
/* 当前筛选条件样式 */
.active-filters {
margin-bottom: 15px;
padding: 10px;
background-color: #f8f9fa;
border-radius: 4px;
border-left: 4px solid #409EFF;
}
.filters-label {
font-weight: bold;
color: #606266;
margin-right: 10px;
}
.filter-tag {
margin-right: 8px;
margin-bottom: 5px;
}
.clear-all {
margin-left: 10px;
color: #409EFF;
}
/* 筛选头部样式 */
.filter-header {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
padding: 8px 0;
transition: all 0.3s ease;
}
.filter-header.filter-active {
background-color: #ecf5ff;
border-radius: 4px;
padding: 8px 12px;
margin: -8px -12px;
}
.filter-header .el-icon {
color: #c0c4cc;
font-size: 14px;
transition: all 0.3s ease;
}
.filter-header:hover .el-icon {
color: #409EFF;
}
.filter-icon-active {
color: #409EFF !important;
}
/* 下拉菜单选中项样式 */
:deep(.dropdown-item-active) {
background-color: #ecf5ff !important;
color: #409EFF !important;
}
:deep(.dropdown-item-active:hover) {
background-color: #d9ecff !important;
}
/* 无权限提示样式 */
.permission-denied {
display: flex;
justify-content: center;
align-items: center;
height: 60vh;
padding: 20px;
background-color: #f5f7fa;
}
.permission-denied .el-result {
padding: 40px 30px;
}
</style>,请帮我生成一个完整的自适应浏览器的vue3 html