<template>
|
<div class="workspace-container h-full">
|
<!-- 左侧主要内容区 -->
|
<div class="flex flex-col h-full overflow-hidden" :style="{ gap: layoutGap }">
|
<!-- 工作概览 -->
|
<div class="overview-section flex-0 bg-white border border-solid border-white rounded-lg p-[20px] h-[150px]">
|
<div class="section-header mb-4">
|
<h3 class="font-bold">工作概览</h3>
|
</div>
|
<div class="overview-cards">
|
<!-- 管理人数 -->
|
<div class="overview-card bg-[#dee8ff] rounded-lg p-4 flex items-center">
|
<i class="i-carbon:user-multiple text-3xl text-blue-500 mr-4"></i>
|
<div>
|
<div class="text-3xl font-bold text-[#4f85f6]">3</div>
|
<div class="text-gray-600">管理人数</div>
|
</div>
|
</div>
|
<!-- 待办事项 -->
|
<div class="overview-card bg-[#faeaed] rounded-lg p-4 flex items-center">
|
<i class="i-carbon:task text-3xl text-red-500 mr-4"></i>
|
<div>
|
<div class="text-3xl font-bold text-red-500">3</div>
|
<div class="text-gray-600">待办事项</div>
|
</div>
|
</div>
|
<!-- 预警事项 -->
|
<div class="overview-card bg-[#dbf2f8] rounded-lg p-4 flex items-center">
|
<i class="i-carbon:warning text-3xl text-cyan-500 mr-4"></i>
|
<div>
|
<div class="text-3xl font-bold text-cyan-500">3</div>
|
<div class="text-gray-600">预警事项</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<div class="flex flex-col flex-auto" :style="{ gap: layoutGap }">
|
<!-- 待办事项和我发起的表格 -->
|
<div class="flex h-1/2" :style="{ gap: layoutGap }">
|
<!-- 待办事项 -->
|
<div class="bg-white rounded-lg p-4 shadow-sm flex flex-col w-1/2">
|
<div class="flex justify-between items-center mb-4 flex-0">
|
<div class="text-lg font-bold">待办事项</div>
|
<el-tabs v-model="todoType" class="todo-tabs">
|
<el-tab-pane label="待办事项" name="todo" />
|
<el-tab-pane label="已办事项" name="done" />
|
</el-tabs>
|
</div>
|
<el-table class="flex-auto" :data="todoList" style="width: 100%" size="small">
|
<el-table-column prop="name" label="事件类型" min-width="120">
|
<template #default="{ row }">
|
<span :class="getEventTypeClass(row.type)">{{ row.name }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="sender" label="发起人" width="100" />
|
<el-table-column prop="time" label="发起时间" width="100" />
|
<el-table-column prop="status" label="状态" width="80">
|
<template #default="{ row }">
|
<el-tag :type="getStatusType(row.status)" size="small">
|
{{ row.status }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80" fixed="right">
|
<template #default>
|
<el-button type="primary" size="small" class="custom-button">办理</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
|
<!-- 我发起的 -->
|
<div class="bg-white rounded-lg p-4 shadow-sm flex flex-col h-full w-1/2">
|
<div class="flex justify-between items-center mb-4 flex-0">
|
<div class="text-lg font-bold">我发起的</div>
|
<el-tabs v-model="initiatedType" class="todo-tabs">
|
<el-tab-pane label="我发起" name="initiated" />
|
<el-tab-pane label="我收到" name="received" />
|
</el-tabs>
|
</div>
|
|
<el-table :data="initiatedList" class="flex-auto" style="width: 100%" size="small">
|
<el-table-column prop="type" label="类型" min-width="120">
|
<template #default="{ row }">
|
<span :class="getEventTypeClass(row.type)">{{ row.type }}</span>
|
</template>
|
</el-table-column>
|
<el-table-column prop="sender" label="发起人" width="100" />
|
<el-table-column prop="time" label="发起时间" width="100" />
|
<el-table-column prop="status" label="状态" width="80">
|
<template #default="{ row }">
|
<el-tag :type="getStatusType(row.status)" size="small">
|
{{ row.status }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="80" fixed="right">
|
<template #default>
|
<el-button type="primary" size="small" class="custom-button">详情</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
|
<!-- 预警表格 -->
|
<div class="bg-white rounded-lg p-4 shadow-sm h-1/2">
|
<div class="text-lg font-bold mb-4">预警</div>
|
<el-table :data="warningList" style="width: 100%" size="small">
|
<el-table-column prop="studentId" label="学号" min-width="120" />
|
<el-table-column prop="name" label="姓名" width="100" />
|
<el-table-column prop="type" label="学生类型" width="100" />
|
<el-table-column prop="guardianId" label="护照号" min-width="150" />
|
<el-table-column prop="warningType" label="预警类型" width="120">
|
<template #default="{ row }">
|
<el-tag :type="getWarningType(row.warningType)" size="small">
|
{{ row.warningType }}
|
</el-tag>
|
</template>
|
</el-table-column>
|
<el-table-column label="操作" width="100" fixed="right">
|
<template #default>
|
<el-button type="primary" size="small" class="custom-button">提交预警</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</div>
|
</div>
|
</div>
|
<!-- 右侧边栏 -->
|
<div class="sidebar h-full overflow-hidden flex flex-col" :style="{ gap: layoutGap }">
|
<!-- 个人信息 -->
|
<div class="profile-card p-[20px] bg-white border border-solid border-white rounded-lg h-[150px] flex-0">
|
<div class="section-header mb-4">
|
<h3>个人信息</h3>
|
</div>
|
<div class="profile-header flex gap-4">
|
<!-- <div class="avatar-placeholder">
|
<i class="i-carbon:user text-3xl text-gray-400"></i>
|
</div> -->
|
<div class="profile-info flex flex-col gap-2">
|
<div class="flex items-center" v-for="item in 3" :key="item">
|
<span class="mr-1">用户名:</span>
|
<span>wjj</span>
|
</div>
|
</div>
|
<div class="profile-info flex flex-col gap-2">
|
<div class="flex items-center" v-for="item in 3" :key="item">
|
<span class="mr-1">用户名:</span>
|
<span>wjj</span>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 统计图表 -->
|
<div class="chart-container p-[20px] h-1/2 overflow-hidden">
|
<div class="chart-header">
|
<h3>统计图表</h3>
|
<span class="subtitle">国别</span>
|
</div>
|
<div class="chart" ref="chartRef"></div>
|
</div>
|
|
<!-- 日历 -->
|
<div class="calendar-container p-[20px] h-1/2 overflow-hidden">
|
<div class="calendar-header">
|
<h3>时间</h3>
|
<div class="flex items-center gap-2">
|
<el-date-picker v-model="currentMonth" type="month" format="YYYY年MM月" :placeholder="'选择月份'" size="small" />
|
</div>
|
</div>
|
<div class="calendar-notice mb-0.5">您今日无待办</div>
|
<el-calendar v-model="currentDate">
|
<template #dateCell="{ data }">
|
<div class="custom-calendar-cell">
|
<span class="date-text">{{ data.day.split('-')[2] }}</span>
|
<div v-if="hasEvent(data)" class="event-dot"></div>
|
</div>
|
</template>
|
</el-calendar>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script setup lang="ts">
|
import * as echarts from 'echarts';
|
import { computed, onMounted, ref } from 'vue';
|
|
const layoutGap = '10px';
|
interface CalendarData {
|
day: string;
|
[key: string]: any;
|
}
|
|
// 状态变量
|
const todoType = ref('todo');
|
const initiatedType = ref('initiated');
|
const currentDate = ref(new Date('2025-04-06'));
|
const currentMonth = computed(() => {
|
const date = currentDate.value;
|
return date instanceof Date ? date : new Date(date);
|
});
|
const chartRef = ref<HTMLElement>();
|
|
// 示例数据 - 增加更多数据
|
const todoList = ref([
|
{ name: '实验室更新', type: 'update', sender: '王美丽', time: '2021.12.06', status: '待确认' },
|
{ name: '新生指导', type: 'guide', sender: '李明', time: '2021.12.06', status: '未读' },
|
{ name: '活动报名', type: 'activity', sender: '张三', time: '2021.12.06', status: '已读' },
|
{ name: '课程变更', type: 'update', sender: '李四', time: '2021.12.06', status: '待确认' },
|
{ name: '会议通知', type: 'notice', sender: '王五', time: '2021.12.06', status: '未读' },
|
{ name: '教材订购', type: 'order', sender: '赵六', time: '2021.12.06', status: '已处理' },
|
{ name: '成绩录入', type: 'grade', sender: '孙七', time: '2021.12.06', status: '待确认' },
|
{ name: '请假审批', type: 'leave', sender: '周八', time: '2021.12.06', status: '已读' },
|
{ name: '请假审批', type: 'leave', sender: '周八', time: '2021.12.06', status: '已读' },
|
{ name: '请假审批', type: 'leave', sender: '周八', time: '2021.12.06', status: '已读' },
|
{ name: '请假审批', type: 'leave', sender: '周八', time: '2021.12.06', status: '已读' },
|
{ name: '请假审批', type: 'leave', sender: '周八', time: '2021.12.06', status: '已读' },
|
]);
|
|
const initiatedList = ref([
|
{ type: '活动', sender: '王美丽', time: '2021.12.06', status: '进行中' },
|
{ type: '报到注册', sender: '李明', time: '2021.12.06', status: '关闭' },
|
{ type: '课程变更', sender: '张三', time: '2021.12.06', status: '待审核' },
|
{ type: '会议通知', sender: '李四', time: '2021.12.06', status: '已完成' },
|
{ type: '教材订购', sender: '王五', time: '2021.12.06', status: '进行中' },
|
{ type: '成绩录入', sender: '赵六', time: '2021.12.06', status: '待审核' },
|
{ type: '请假审批', sender: '孙七', time: '2021.12.06', status: '已拒绝' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
{ type: '活动策划', sender: '周八', time: '2021.12.06', status: '进行中' },
|
]);
|
|
const warningList = ref([
|
{ studentId: 'N20930498594', name: '王美丽', type: '高中', guardianId: '309209382903943', warningType: '迟到预警' },
|
{ studentId: 'N20930498595', name: '李明', type: '高中', guardianId: '309209382903944', warningType: '缺勤预警' },
|
{ studentId: 'N20930498596', name: '张三', type: '初中', guardianId: '309209382903945', warningType: '成绩预警' },
|
{ studentId: 'N20930498597', name: '李四', type: '高中', guardianId: '309209382903946', warningType: '行为预警' },
|
{ studentId: 'N20930498598', name: '王五', type: '初中', guardianId: '309209382903947', warningType: '迟到预警' },
|
]);
|
|
// 工具函数
|
const getEventTypeClass = (type: string) => {
|
const classes = {
|
update: 'text-green-500',
|
guide: 'text-blue-500',
|
activity: 'text-orange-500',
|
notice: 'text-purple-500',
|
order: 'text-cyan-500',
|
grade: 'text-pink-500',
|
leave: 'text-indigo-500',
|
};
|
return classes[type] || '';
|
};
|
|
const getStatusType = (status: string) => {
|
const types = {
|
待确认: 'warning',
|
未读: 'danger',
|
已读: 'info',
|
已处理: 'success',
|
进行中: 'primary',
|
关闭: 'info',
|
待审核: 'warning',
|
已完成: 'success',
|
已拒绝: 'danger',
|
};
|
return types[status] || 'default';
|
};
|
|
const getWarningType = (type: string) => {
|
const types = {
|
迟到预警: 'danger',
|
缺勤预警: 'warning',
|
成绩预警: 'info',
|
行为预警: 'warning',
|
};
|
return types[type] || 'default';
|
};
|
|
const hasEvent = (date: CalendarData) => {
|
// 实现判断日期是否有事件的逻辑
|
return Math.random() > 0.8;
|
};
|
|
// 图表初始化
|
onMounted(() => {
|
if (chartRef.value) {
|
const chart = echarts.init(chartRef.value);
|
chart.setOption({
|
xAxis: {
|
type: 'category',
|
data: ['中国', '德国', '法国', '英国', '新西兰', '美国', '瑞士'],
|
},
|
yAxis: {
|
type: 'value',
|
},
|
series: [
|
{
|
data: [80, 50, 100, 30, 70, 80, 60],
|
type: 'bar',
|
barWidth: '30%',
|
itemStyle: {
|
color: '#409EFF',
|
},
|
},
|
],
|
});
|
}
|
});
|
</script>
|
|
<style scoped lang="scss">
|
.workspace-container {
|
display: grid;
|
grid-template-columns: 1fr 300px;
|
gap: v-bind(layoutGap);
|
padding: 20px;
|
background-color: #f5f7fa;
|
}
|
|
.overview-cards {
|
display: grid;
|
grid-template-columns: repeat(3, 1fr);
|
gap: 20px;
|
}
|
|
// 自定义按钮样式
|
.custom-button {
|
--el-button-bg-color: var(--color-btn-base);
|
--el-button-border-color: var(--color-btn-base);
|
--el-button-hover-bg-color: var(--color-btn-hover);
|
--el-button-hover-border-color: var(--color-btn-hover);
|
}
|
|
// 自定义 tabs 样式
|
:deep(.todo-tabs) {
|
.el-tabs__header {
|
margin: 0;
|
}
|
|
.el-tabs__nav-wrap::after {
|
display: none;
|
}
|
|
.el-tabs__item {
|
padding: 0 10px;
|
height: 32px;
|
line-height: 32px;
|
font-size: 14px;
|
|
&.is-active {
|
color: var(--color-btn-base);
|
}
|
}
|
|
.el-tabs__active-bar {
|
background-color: var(--color-btn-base);
|
}
|
}
|
|
// 自定义日历样式
|
:deep(.el-calendar) {
|
--el-calendar-border: none;
|
--el-calendar-header-border-bottom: none;
|
background: none;
|
|
.el-calendar__header {
|
display: none;
|
}
|
|
.el-calendar__body {
|
padding: 12px 0;
|
}
|
|
.el-calendar-table {
|
td {
|
border: none;
|
padding: 4px;
|
}
|
|
.current {
|
background: none;
|
}
|
}
|
}
|
|
.custom-calendar-cell {
|
height: 32px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
position: relative;
|
|
.date-text {
|
font-size: 14px;
|
}
|
|
.event-dot {
|
position: absolute;
|
top: 2px;
|
right: 2px;
|
width: 6px;
|
height: 6px;
|
border-radius: 50%;
|
background-color: var(--el-color-primary);
|
}
|
}
|
|
.calendar-notice {
|
background-color: #fff7e6;
|
color: #fa8c16;
|
padding: 8px 12px;
|
border-radius: 4px;
|
font-size: 14px;
|
}
|
|
.avatar-placeholder {
|
width: 64px;
|
height: 64px;
|
border-radius: 50%;
|
background-color: #f5f7fa;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
}
|
|
:deep(.el-calendar-table .el-calendar-day) {
|
--el-calendar-cell-width: 10px;
|
}
|
|
.chart-container {
|
background: white;
|
border-radius: 8px;
|
|
.chart {
|
height: 300px;
|
}
|
|
.chart-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 16px;
|
|
.subtitle {
|
color: var(--el-text-color-secondary);
|
font-size: 14px;
|
}
|
}
|
}
|
|
.calendar-container {
|
background: white;
|
border-radius: 8px;
|
|
.calendar-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 16px;
|
|
h3 {
|
font-size: 16px;
|
font-weight: 500;
|
margin: 0;
|
}
|
}
|
}
|
|
:deep(.el-date-picker) {
|
--el-input-width: 120px;
|
}
|
|
.section-header {
|
h3 {
|
font-size: 16px;
|
// font-weight: 500;
|
// margin: 0;
|
// color: var(--el-text-color-primary);
|
}
|
}
|
</style>
|