路由更新

This commit is contained in:
2025-10-16 18:03:46 +08:00
parent 1199cbc176
commit 0811af6d03
94 changed files with 9511 additions and 667 deletions

View File

@@ -0,0 +1,37 @@
<template>
<div class="study-management">
<h1 class="page-title">学习管理</h1>
<el-tabs v-model="activeTab">
<el-tab-pane label="学习任务发布" name="task-publish">
<TaskPublish />
</el-tab-pane>
<el-tab-pane label="学习记录" name="task-records">
<StudyRecords />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ElTabs, ElTabPane } from 'element-plus';
import TaskPublish from './components/TaskPublish.vue';
import StudyRecords from './components/StudyRecords.vue';
const activeTab = ref('task-publish');
</script>
<style lang="scss" scoped>
.study-management {
padding: 20px;
}
.page-title {
font-size: 28px;
font-weight: 600;
color: #141F38;
margin-bottom: 24px;
}
</style>

View File

@@ -0,0 +1,149 @@
<template>
<div class="study-records">
<div class="filter-bar">
<el-input
v-model="searchKeyword"
placeholder="搜索用户..."
style="width: 200px"
clearable
/>
<el-select v-model="selectedTask" placeholder="选择任务" style="width: 200px" clearable>
<el-option
v-for="task in tasks"
:key="task.id"
:label="task.name"
:value="task.id"
/>
</el-select>
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleExport">导出</el-button>
</div>
<el-table :data="records" style="width: 100%">
<el-table-column prop="userName" label="用户" width="120" />
<el-table-column prop="taskName" label="任务名称" min-width="180" />
<el-table-column prop="progress" label="完成进度" width="120">
<template #default="{ row }">
<el-progress :percentage="row.progress" />
</template>
</el-table-column>
<el-table-column prop="duration" label="学习时长" width="120" />
<el-table-column prop="startDate" label="开始时间" width="150" />
<el-table-column prop="status" label="状态" width="100">
<template #default="{ row }">
<el-tag :type="getStatusType(row.status)">
{{ getStatusText(row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="120" fixed="right">
<template #default="{ row }">
<el-button size="small" @click="viewDetail(row)">查看详情</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElInput, ElSelect, ElOption, ElDatePicker, ElButton, ElTable, ElTableColumn, ElTag, ElProgress, ElPagination, ElMessage } from 'element-plus';
const searchKeyword = ref('');
const selectedTask = ref('');
const dateRange = ref<[Date, Date] | null>(null);
const currentPage = ref(1);
const pageSize = ref(10);
const total = ref(0);
const records = ref<any[]>([]);
const tasks = ref<any[]>([]);
onMounted(() => {
loadTasks();
loadRecords();
});
function loadTasks() {
// TODO: 加载任务列表
}
function loadRecords() {
// TODO: 加载学习记录
}
function handleSearch() {
currentPage.value = 1;
loadRecords();
}
function handleExport() {
// TODO: 导出学习记录
ElMessage.info('导出功能开发中');
}
function getStatusType(status: string) {
const typeMap: Record<string, any> = {
'completed': 'success',
'in-progress': 'warning',
'not-started': 'info'
};
return typeMap[status] || 'info';
}
function getStatusText(status: string) {
const textMap: Record<string, string> = {
'completed': '已完成',
'in-progress': '进行中',
'not-started': '未开始'
};
return textMap[status] || status;
}
function viewDetail(row: any) {
// TODO: 查看学习记录详情
}
function handleSizeChange(val: number) {
pageSize.value = val;
loadRecords();
}
function handleCurrentChange(val: number) {
currentPage.value = val;
loadRecords();
}
</script>
<style lang="scss" scoped>
.study-records {
padding: 20px;
}
.filter-bar {
display: flex;
gap: 16px;
margin-bottom: 20px;
align-items: center;
}
.el-table {
margin-bottom: 20px;
}
</style>

View File

@@ -0,0 +1,135 @@
<template>
<div class="task-publish">
<el-form :model="taskForm" :rules="taskRules" ref="taskFormRef" label-width="120px">
<el-form-item label="任务名称" prop="name">
<el-input v-model="taskForm.name" placeholder="请输入任务名称" />
</el-form-item>
<el-form-item label="任务描述" prop="description">
<el-input
v-model="taskForm.description"
type="textarea"
:rows="4"
placeholder="请输入任务描述"
/>
</el-form-item>
<el-form-item label="任务周期" prop="period">
<el-date-picker
v-model="taskForm.period"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
<el-form-item label="关联资源" prop="resources">
<el-button @click="showResourceSelector">选择资源</el-button>
<div class="selected-resources" v-if="taskForm.resources.length">
<el-tag
v-for="resource in taskForm.resources"
:key="resource.id"
closable
@close="removeResource(resource)"
>
{{ resource.name }}
</el-tag>
</div>
</el-form-item>
<el-form-item label="任务接受对象" prop="targets">
<el-radio-group v-model="taskForm.targetType">
<el-radio label="dept">按部门</el-radio>
<el-radio label="role">按权限</el-radio>
<el-radio label="user">选人员</el-radio>
</el-radio-group>
<el-button @click="showTargetSelector" style="margin-left: 16px;">
选择对象
</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handlePublish">发布任务</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ElForm, ElFormItem, ElInput, ElDatePicker, ElButton, ElRadioGroup, ElRadio, ElTag, ElMessage, type FormInstance, type FormRules } from 'element-plus';
const taskFormRef = ref<FormInstance>();
const taskForm = ref({
name: '',
description: '',
period: null as [Date, Date] | null,
resources: [] as any[],
targetType: 'dept',
targets: [] as any[]
});
const taskRules: FormRules = {
name: [
{ required: true, message: '请输入任务名称', trigger: 'blur' }
],
description: [
{ required: true, message: '请输入任务描述', trigger: 'blur' }
],
period: [
{ required: true, message: '请选择任务周期', trigger: 'change' }
]
};
function showResourceSelector() {
// TODO: 显示资源选择器
}
function removeResource(resource: any) {
const index = taskForm.value.resources.indexOf(resource);
if (index > -1) {
taskForm.value.resources.splice(index, 1);
}
}
function showTargetSelector() {
// TODO: 显示对象选择器
}
async function handlePublish() {
if (!taskFormRef.value) return;
try {
await taskFormRef.value.validate();
// TODO: 调用发布任务API
ElMessage.success('任务发布成功');
handleReset();
} catch (error) {
console.error('表单验证失败', error);
}
}
function handleReset() {
taskFormRef.value?.resetFields();
taskForm.value.resources = [];
taskForm.value.targets = [];
}
</script>
<style lang="scss" scoped>
.task-publish {
padding: 20px;
max-width: 800px;
}
.selected-resources {
margin-top: 12px;
display: flex;
flex-wrap: wrap;
gap: 8px;
}
</style>