<template>
|
<div class="app-container">
|
<el-tabs v-model="activeTab" type="border-card" @tab-change="handleTabChange">
|
<el-tab-pane label="培训资料" name="materials">
|
<el-form :model="materialFilters" :inline="true">
|
<el-form-item label="资料名称">
|
<el-input v-model="materialFilters.name" placeholder="请输入资料名称" clearable style="width: 200px" />
|
</el-form-item>
|
<el-form-item label="资料类型">
|
<el-select v-model="materialFilters.type" placeholder="请选择" clearable style="width: 150px">
|
<el-option label="PDF" value="PDF" />
|
<el-option label="制度" value="制度" />
|
<el-option label="课件" value="课件" />
|
<el-option label="视频" value="视频" />
|
<el-option label="案例" value="案例" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态">
|
<el-select v-model="materialFilters.status" placeholder="请选择" clearable style="width: 150px">
|
<el-option label="启用" :value="1" />
|
<el-option label="停用" :value="0" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="getMaterialData">搜索</el-button>
|
<el-button @click="resetMaterialFilters">重置</el-button>
|
</el-form-item>
|
</el-form>
|
<div class="table_list">
|
<div class="actions">
|
<el-button type="primary" @click="openMaterialDialog" icon="Upload">上传资料</el-button>
|
</div>
|
<PIMTable :column="materialColumns" :tableData="materialList" :page="materialPage" @pagination="changeMaterialPage" :tableLoading="materialLoading" />
|
</div>
|
</el-tab-pane>
|
|
<el-tab-pane label="培训计划" name="plans">
|
<el-form :model="planFilters" :inline="true">
|
<el-form-item label="计划年度">
|
<el-date-picker v-model="planFilters.year" type="year" placeholder="选择年度" value-format="YYYY" style="width: 150px" />
|
</el-form-item>
|
<el-form-item label="岗位">
|
<el-input v-model="planFilters.post" placeholder="请输入岗位" clearable style="width: 200px" />
|
</el-form-item>
|
<el-form-item label="培训等级">
|
<el-select v-model="planFilters.level" placeholder="请选择" clearable style="width: 150px">
|
<el-option label="一级" value="一级" />
|
<el-option label="二级" value="二级" />
|
<el-option label="三级" value="三级" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态">
|
<el-select v-model="planFilters.status" placeholder="请选择" clearable style="width: 150px">
|
<el-option label="待执行" :value="0" />
|
<el-option label="执行中" :value="1" />
|
<el-option label="已完成" :value="2" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="getPlanData">搜索</el-button>
|
<el-button @click="resetPlanFilters">重置</el-button>
|
</el-form-item>
|
</el-form>
|
<div class="table_list">
|
<div class="actions">
|
<el-button type="primary" @click="openPlanDialog" icon="Plus">制定计划</el-button>
|
</div>
|
<PIMTable :column="planColumns" :tableData="planList" :page="planPage" @pagination="changePlanPage" :tableLoading="planLoading" />
|
</div>
|
</el-tab-pane>
|
|
<el-tab-pane label="完成记录" name="records">
|
<el-form :model="recordFilters" :inline="true">
|
<el-form-item label="员工姓名">
|
<el-input v-model="recordFilters.employeeName" placeholder="请输入员工姓名" clearable style="width: 200px" />
|
</el-form-item>
|
<el-form-item label="状态">
|
<el-select v-model="recordFilters.status" placeholder="请选择" clearable style="width: 150px">
|
<el-option label="已完成" :value="1" />
|
<el-option label="未完成" :value="0" />
|
</el-select>
|
</el-form-item>
|
<el-form-item>
|
<el-button type="primary" @click="getRecordData">搜索</el-button>
|
<el-button @click="resetRecordFilters">重置</el-button>
|
<el-button type="primary" @click="openRecordDialog" icon="Plus">新增</el-button>
|
<el-button type="success" @click="exportRecords" icon="Download">导出</el-button>
|
</el-form-item>
|
</el-form>
|
<div class="table_list">
|
<PIMTable :column="recordColumns" :tableData="recordList" :page="recordPage" @pagination="changeRecordPage" :tableLoading="recordLoading" />
|
</div>
|
</el-tab-pane>
|
</el-tabs>
|
|
<!-- 培训资料弹窗 -->
|
<el-dialog :title="materialDialog.title" v-model="materialDialog.visible" width="600px" append-to-body>
|
<el-form ref="materialFormRef" :model="materialForm" :rules="materialRules" label-width="100px">
|
<el-form-item label="资料名称" prop="name">
|
<el-input v-model="materialForm.name" placeholder="请输入资料名称" />
|
</el-form-item>
|
<el-form-item label="资料类型" prop="type">
|
<el-select v-model="materialForm.type" placeholder="请选择资料类型" style="width: 100%">
|
<el-option label="PDF" value="PDF" />
|
<el-option label="制度" value="制度" />
|
<el-option label="课件" value="课件" />
|
<el-option label="视频" value="视频" />
|
<el-option label="案例" value="案例" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="文件上传" prop="fileUrl" v-if="!materialForm.id">
|
<el-upload
|
ref="uploadRef"
|
action="/dev-api/common/upload"
|
:headers="uploadHeaders"
|
:on-success="handleUploadSuccess"
|
:on-error="handleUploadError"
|
:before-upload="beforeUpload"
|
:limit="1"
|
>
|
<el-button type="primary">选择文件</el-button>
|
<template #tip>
|
<div class="el-upload__tip">支持 PDF、Word、视频等格式</div>
|
</template>
|
</el-upload>
|
</el-form-item>
|
<el-form-item label="文件大小" prop="fileSize" v-if="materialForm.fileSize">
|
<el-input v-model="materialForm.fileSize" disabled />
|
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
<el-radio-group v-model="materialForm.status">
|
<el-radio :value="1">启用</el-radio>
|
<el-radio :value="0">停用</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
<el-form-item label="备注" prop="remark">
|
<el-input v-model="materialForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="materialDialog.visible = false">取 消</el-button>
|
<el-button type="primary" @click="submitMaterialForm" :loading="materialDialog.loading">确 定</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 培训计划弹窗 -->
|
<el-dialog :title="planDialog.title" v-model="planDialog.visible" width="700px" append-to-body>
|
<el-form ref="planFormRef" :model="planForm" :rules="planRules" label-width="100px">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="计划年度" prop="year">
|
<el-date-picker v-model="planForm.year" type="year" placeholder="选择年度" value-format="YYYY" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="适用岗位" prop="post">
|
<el-input v-model="planForm.post" placeholder="请输入适用岗位" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="培训等级" prop="level">
|
<el-select v-model="planForm.level" placeholder="请选择培训等级" style="width: 100%">
|
<el-option label="一级" value="一级" />
|
<el-option label="二级" value="二级" />
|
<el-option label="三级" value="三级" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="计划课时" prop="hours">
|
<el-input-number v-model="planForm.hours" :min="1" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-form-item label="培训内容" prop="content">
|
<el-input v-model="planForm.content" type="textarea" :rows="3" placeholder="请输入培训内容" />
|
</el-form-item>
|
<el-form-item label="培训资料" prop="materialIds">
|
<el-select v-model="planForm.materialIds" multiple placeholder="请选择培训资料" style="width: 100%">
|
<el-option v-for="item in materialOptions" :key="item.id" :label="item.name" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
<el-form-item label="状态" prop="status">
|
<el-radio-group v-model="planForm.status">
|
<el-radio :value="0">待执行</el-radio>
|
<el-radio :value="1">执行中</el-radio>
|
<el-radio :value="2">已完成</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
<el-form-item label="备注" prop="remark">
|
<el-input v-model="planForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="planDialog.visible = false">取 消</el-button>
|
<el-button type="primary" @click="submitPlanForm" :loading="planDialog.loading">确 定</el-button>
|
</template>
|
</el-dialog>
|
|
<!-- 完成记录弹窗 -->
|
<el-dialog :title="recordDialog.title" v-model="recordDialog.visible" width="700px" append-to-body>
|
<el-form ref="recordFormRef" :model="recordForm" :rules="recordRules" label-width="100px">
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="培训计划" prop="planId">
|
<el-select v-model="recordForm.planId" placeholder="请选择培训计划" style="width: 100%" @change="handlePlanChange">
|
<el-option v-for="item in planOptions" :key="item.id" :label="item.content" :value="item.id" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="员工姓名" prop="employeeId">
|
<el-select v-model="recordForm.employeeId" placeholder="请选择员工" style="width: 100%" @change="handleEmployeeChange">
|
<el-option v-for="item in employeeOptions" :key="item.userId" :label="item.userName" :value="item.userId" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="完成时间" prop="completeTime">
|
<el-date-picker v-model="recordForm.completeTime" type="datetime" placeholder="选择完成时间" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="学习时长" prop="duration">
|
<el-input-number v-model="recordForm.duration" :min="0" :precision="1" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="培训方式" prop="method">
|
<el-select v-model="recordForm.method" placeholder="请选择培训方式" style="width: 100%">
|
<el-option label="线下授课" value="线下授课" />
|
<el-option label="线上学习" value="线上学习" />
|
<el-option label="实操演练" value="实操演练" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="考核分数" prop="score">
|
<el-input-number v-model="recordForm.score" :min="0" :max="100" style="width: 100%" />
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-row :gutter="20">
|
<el-col :span="12">
|
<el-form-item label="考核结果" prop="result">
|
<el-select v-model="recordForm.result" placeholder="请选择考核结果" style="width: 100%">
|
<el-option label="通过" value="通过" />
|
<el-option label="未通过" value="未通过" />
|
</el-select>
|
</el-form-item>
|
</el-col>
|
<el-col :span="12">
|
<el-form-item label="状态" prop="status">
|
<el-radio-group v-model="recordForm.status">
|
<el-radio :value="1">已完成</el-radio>
|
<el-radio :value="0">未完成</el-radio>
|
</el-radio-group>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
<el-form-item label="备注" prop="remark">
|
<el-input v-model="recordForm.remark" type="textarea" :rows="3" placeholder="请输入备注" />
|
</el-form-item>
|
</el-form>
|
<template #footer>
|
<el-button @click="recordDialog.visible = false">取 消</el-button>
|
<el-button type="primary" @click="submitRecordForm" :loading="recordDialog.loading">确 定</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script setup>
|
import { ref, reactive, onMounted } from "vue";
|
import PIMTable from "@/components/PIMTable/PIMTable.vue";
|
import {
|
getMaterialList,
|
uploadMaterial as uploadMaterialApi,
|
updateMaterial,
|
deleteMaterial,
|
getMaterialDetail,
|
getPlanList,
|
addPlan as addPlanApi,
|
updatePlan,
|
deletePlan,
|
getPlanDetail,
|
getRecordList,
|
addRecord as addRecordApi,
|
updateRecord,
|
deleteRecord,
|
getRecordDetail,
|
exportRecord
|
} from "@/api/safetyManagement/trainingManage.js";
|
import { listUser } from "@/api/system/user";
|
import { getToken } from "@/utils/auth";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
defineOptions({
|
name: "培训管理",
|
});
|
|
const activeTab = ref("materials");
|
|
// ==================== 培训资料 ====================
|
const materialFilters = reactive({ name: "", type: "", status: null });
|
const materialList = ref([]);
|
const materialPage = reactive({ current: 1, size: 10, total: 0 });
|
const materialLoading = ref(false);
|
const materialColumns = [
|
{ label: "资料名称", prop: "name", align: "center" },
|
{
|
label: "类型",
|
prop: "type",
|
align: "center",
|
dataType: "tag",
|
formatType: () => "primary",
|
formatData: (val) => val || '-'
|
},
|
{ label: "上传人", prop: "uploader", align: "center" },
|
{ label: "上传时间", prop: "uploadTime", align: "center" },
|
{ label: "文件大小", prop: "fileSize", align: "center" },
|
{
|
label: "状态",
|
prop: "status",
|
align: "center",
|
dataType: "tag",
|
formatType: (val) => (val === 1 ? "success" : "info"),
|
formatData: (val) => (val === 1 ? "启用" : "停用")
|
},
|
{
|
label: "操作",
|
prop: "action",
|
align: "center",
|
dataType: "action",
|
operation: [
|
{ name: "编辑", type: "text", clickFun: (row) => handleEditMaterial(row) },
|
{ name: "下载", type: "text", clickFun: (row) => handleDownload(row) },
|
{ name: "删除", type: "text", clickFun: (row) => handleDeleteMaterial(row) }
|
]
|
}
|
];
|
|
const materialDialog = reactive({ visible: false, title: "", loading: false });
|
const materialFormRef = ref(null);
|
const uploadRef = ref(null);
|
const materialForm = reactive({
|
id: null,
|
name: "",
|
type: "",
|
fileUrl: "",
|
fileSize: "",
|
status: 1,
|
remark: ""
|
});
|
const materialRules = {
|
name: [{ required: true, message: "请输入资料名称", trigger: "blur" }],
|
type: [{ required: true, message: "请选择资料类型", trigger: "change" }]
|
};
|
|
const uploadHeaders = reactive({
|
Authorization: "Bearer " + getToken()
|
});
|
|
// ==================== 培训计划 ====================
|
const planFilters = reactive({ year: "", post: "", level: "", status: null });
|
const planList = ref([]);
|
const planPage = reactive({ current: 1, size: 10, total: 0 });
|
const planLoading = ref(false);
|
const planColumns = [
|
{ label: "计划年度", prop: "year", align: "center" },
|
{ label: "岗位", prop: "post", align: "center" },
|
{ label: "培训等级", prop: "level", align: "center" },
|
{ label: "培训内容", prop: "content", align: "center" },
|
{ label: "计划课时", prop: "hours", align: "center" },
|
{
|
label: "状态",
|
prop: "status",
|
align: "center",
|
dataType: "tag",
|
formatType: (val) => {
|
if (val === 0) return 'info';
|
if (val === 1) return 'warning';
|
return 'success';
|
},
|
formatData: (val) => {
|
const statusMap = { 0: '待执行', 1: '执行中', 2: '已完成' };
|
return statusMap[val] || val;
|
}
|
},
|
{
|
label: "操作",
|
prop: "action",
|
align: "center",
|
dataType: "action",
|
operation: [
|
{ name: "编辑", type: "text", clickFun: (row) => handleEditPlan(row) },
|
{ name: "删除", type: "text", clickFun: (row) => handleDeletePlan(row) }
|
]
|
}
|
];
|
|
const planDialog = reactive({ visible: false, title: "", loading: false });
|
const planFormRef = ref(null);
|
const planForm = reactive({
|
id: null,
|
year: "",
|
post: "",
|
level: "",
|
content: "",
|
hours: 1,
|
materialIds: [],
|
status: 0,
|
remark: ""
|
});
|
const planRules = {
|
year: [{ required: true, message: "请选择计划年度", trigger: "change" }],
|
post: [{ required: true, message: "请输入适用岗位", trigger: "blur" }],
|
level: [{ required: true, message: "请选择培训等级", trigger: "change" }],
|
content: [{ required: true, message: "请输入培训内容", trigger: "blur" }],
|
hours: [{ required: true, message: "请输入计划课时", trigger: "blur" }]
|
};
|
const materialOptions = ref([]);
|
|
// ==================== 完成记录 ====================
|
const recordFilters = reactive({ employeeName: "", status: null });
|
const recordList = ref([]);
|
const recordPage = reactive({ current: 1, size: 10, total: 0 });
|
const recordLoading = ref(false);
|
const recordColumns = [
|
{ label: "员工姓名", prop: "employeeName", align: "center" },
|
{ label: "培训内容", prop: "content", align: "center" },
|
{ label: "完成时间", prop: "completeTime", align: "center" },
|
{ label: "学习时长", prop: "duration", align: "center" },
|
{ label: "培训方式", prop: "method", align: "center" },
|
{ label: "分数", prop: "score", align: "center" },
|
{
|
label: "考核结果",
|
prop: "result",
|
align: "center",
|
dataType: "tag",
|
formatType: (val) => {
|
if (val === '优秀' || val === '通过') return 'success';
|
if (val === '良好') return 'primary';
|
if (val === '合格') return 'warning';
|
return 'danger';
|
},
|
formatData: (val) => val || '-'
|
},
|
{
|
label: "操作",
|
prop: "action",
|
align: "center",
|
dataType: "action",
|
operation: [
|
{ name: "编辑", type: "text", clickFun: (row) => handleEditRecord(row) },
|
{ name: "删除", type: "text", clickFun: (row) => handleDeleteRecord(row) }
|
]
|
}
|
];
|
|
const recordDialog = reactive({ visible: false, title: "", loading: false });
|
const recordFormRef = ref(null);
|
const recordForm = reactive({
|
id: null,
|
planId: null,
|
employeeId: null,
|
employeeName: "",
|
content: "",
|
completeTime: "",
|
duration: 0,
|
method: "",
|
score: 0,
|
result: "",
|
status: 1,
|
remark: ""
|
});
|
const recordRules = {
|
planId: [{ required: true, message: "请选择培训计划", trigger: "change" }],
|
employeeId: [{ required: true, message: "请选择员工", trigger: "change" }],
|
completeTime: [{ required: true, message: "请选择完成时间", trigger: "change" }]
|
};
|
const planOptions = ref([]);
|
const employeeOptions = ref([]);
|
|
// ==================== 通用方法 ====================
|
const loadData = () => {
|
switch (activeTab.value) {
|
case 'materials':
|
getMaterialData();
|
break;
|
case 'plans':
|
getPlanData();
|
break;
|
case 'records':
|
getRecordData();
|
break;
|
}
|
};
|
|
const handleTabChange = () => {
|
loadData();
|
};
|
|
// ==================== 培训资料方法 ====================
|
const getMaterialData = async () => {
|
materialLoading.value = true;
|
try {
|
const res = await getMaterialList({
|
pageNum: materialPage.current,
|
pageSize: materialPage.size,
|
...materialFilters
|
});
|
if (res.code === 200) {
|
materialList.value = res.data.records || res.data.rows || [];
|
materialPage.total = res.data.total || 0;
|
}
|
} catch (error) {
|
ElMessage.error('获取培训资料失败');
|
} finally {
|
materialLoading.value = false;
|
}
|
};
|
|
const resetMaterialFilters = () => {
|
materialFilters.name = "";
|
materialFilters.type = "";
|
materialFilters.status = null;
|
materialPage.current = 1;
|
getMaterialData();
|
};
|
|
const changeMaterialPage = ({ page, limit }) => {
|
materialPage.current = page;
|
materialPage.size = limit;
|
getMaterialData();
|
};
|
|
const resetMaterialForm = () => {
|
materialForm.id = null;
|
materialForm.name = "";
|
materialForm.type = "";
|
materialForm.fileUrl = "";
|
materialForm.fileSize = "";
|
materialForm.status = 1;
|
materialForm.remark = "";
|
if (uploadRef.value) {
|
uploadRef.value.clearFiles();
|
}
|
};
|
|
const openMaterialDialog = () => {
|
resetMaterialForm();
|
materialDialog.title = "上传培训资料";
|
materialDialog.visible = true;
|
};
|
|
const handleEditMaterial = async (row) => {
|
resetMaterialForm();
|
try {
|
const res = await getMaterialDetail(row.id);
|
if (res.code === 200) {
|
Object.assign(materialForm, res.data);
|
materialDialog.title = "编辑培训资料";
|
materialDialog.visible = true;
|
}
|
} catch (error) {
|
ElMessage.error('获取资料详情失败');
|
}
|
};
|
|
const handleUploadSuccess = (response) => {
|
if (response.code === 200) {
|
materialForm.fileUrl = response.url;
|
materialForm.fileSize = formatFileSize(response.file?.size || 0);
|
ElMessage.success('文件上传成功');
|
} else {
|
ElMessage.error(response.msg || '上传失败');
|
}
|
};
|
|
const handleUploadError = () => {
|
ElMessage.error('文件上传失败');
|
};
|
|
const beforeUpload = (file) => {
|
const maxSize = 50 * 1024 * 1024; // 50MB
|
if (file.size > maxSize) {
|
ElMessage.error('文件大小不能超过 50MB');
|
return false;
|
}
|
return true;
|
};
|
|
const formatFileSize = (size) => {
|
if (size < 1024) return size + ' B';
|
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + ' KB';
|
if (size < 1024 * 1024 * 1024) return (size / (1024 * 1024)).toFixed(2) + ' MB';
|
return (size / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
|
};
|
|
const submitMaterialForm = async () => {
|
const valid = await materialFormRef.value.validate().catch(() => false);
|
if (!valid) return;
|
|
if (!materialForm.id && !materialForm.fileUrl) {
|
ElMessage.error('请上传文件');
|
return;
|
}
|
|
materialDialog.loading = true;
|
try {
|
const api = materialForm.id ? updateMaterial : uploadMaterialApi;
|
const res = await api(materialForm);
|
if (res.code === 200) {
|
ElMessage.success(materialForm.id ? '修改成功' : '上传成功');
|
materialDialog.visible = false;
|
getMaterialData();
|
}
|
} catch (error) {
|
ElMessage.error(materialForm.id ? '修改失败' : '上传失败');
|
} finally {
|
materialDialog.loading = false;
|
}
|
};
|
|
const handleDownload = (row) => {
|
if (row.fileUrl) {
|
// 处理URL格式问题
|
let url = row.fileUrl;
|
// 修复类似 http://host:portupload/ 的错误格式
|
url = url.replace(/^(http:\/\/[^/]+:\d+)(upload\/)/, '$1/$2');
|
// 如果不是完整URL,添加前缀
|
if (!url.startsWith('http')) {
|
url = '/dev-api/' + url.replace(/^\//, '');
|
}
|
window.open(url, '_blank');
|
} else {
|
ElMessage.warning('文件地址不存在');
|
}
|
};
|
|
const handleDeleteMaterial = (row) => {
|
ElMessageBox.confirm(`确认删除资料 "${row.name}" 吗?`, "提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning"
|
}).then(async () => {
|
try {
|
const res = await deleteMaterial(row.id);
|
if (res.code === 200) {
|
ElMessage.success("删除成功");
|
getMaterialData();
|
}
|
} catch (error) {
|
ElMessage.error("删除失败");
|
}
|
});
|
};
|
|
// ==================== 培训计划方法 ====================
|
const getPlanData = async () => {
|
planLoading.value = true;
|
try {
|
const res = await getPlanList({
|
pageNum: planPage.current,
|
pageSize: planPage.size,
|
...planFilters
|
});
|
if (res.code === 200) {
|
planList.value = res.data.records || res.data.rows || [];
|
planPage.total = res.data.total || 0;
|
}
|
} catch (error) {
|
ElMessage.error('获取培训计划失败');
|
} finally {
|
planLoading.value = false;
|
}
|
};
|
|
const resetPlanFilters = () => {
|
planFilters.year = "";
|
planFilters.post = "";
|
planFilters.level = "";
|
planFilters.status = null;
|
planPage.current = 1;
|
getPlanData();
|
};
|
|
const changePlanPage = ({ page, limit }) => {
|
planPage.current = page;
|
planPage.size = limit;
|
getPlanData();
|
};
|
|
const loadMaterialOptions = async () => {
|
try {
|
const res = await getMaterialList({ pageNum: 1, pageSize: 1000 });
|
if (res.code === 200) {
|
materialOptions.value = res.data.records || res.data.rows || [];
|
}
|
} catch (error) {
|
console.error('加载培训资料选项失败', error);
|
}
|
};
|
|
const resetPlanForm = () => {
|
planForm.id = null;
|
planForm.year = "";
|
planForm.post = "";
|
planForm.level = "";
|
planForm.content = "";
|
planForm.hours = 1;
|
planForm.materialIds = [];
|
planForm.status = 0;
|
planForm.remark = "";
|
};
|
|
const openPlanDialog = () => {
|
resetPlanForm();
|
loadMaterialOptions();
|
planDialog.title = "制定培训计划";
|
planDialog.visible = true;
|
};
|
|
const handleEditPlan = async (row) => {
|
resetPlanForm();
|
loadMaterialOptions();
|
try {
|
const res = await getPlanDetail(row.id);
|
if (res.code === 200) {
|
Object.assign(planForm, res.data);
|
// 将 materialIds 字符串转换为数组
|
if (planForm.materialIds && typeof planForm.materialIds === 'string') {
|
planForm.materialIds = planForm.materialIds.split(',').map(id => parseInt(id));
|
}
|
planDialog.title = "编辑培训计划";
|
planDialog.visible = true;
|
}
|
} catch (error) {
|
ElMessage.error('获取计划详情失败');
|
}
|
};
|
|
const submitPlanForm = async () => {
|
const valid = await planFormRef.value.validate().catch(() => false);
|
if (!valid) return;
|
|
planDialog.loading = true;
|
try {
|
const submitData = { ...planForm };
|
// 将 materialIds 数组转换为逗号分隔的字符串
|
if (Array.isArray(submitData.materialIds)) {
|
submitData.materialIds = submitData.materialIds.join(',');
|
}
|
const api = planForm.id ? updatePlan : addPlanApi;
|
const res = await api(submitData);
|
if (res.code === 200) {
|
ElMessage.success(planForm.id ? '修改成功' : '新增成功');
|
planDialog.visible = false;
|
getPlanData();
|
}
|
} catch (error) {
|
ElMessage.error(planForm.id ? '修改失败' : '新增失败');
|
} finally {
|
planDialog.loading = false;
|
}
|
};
|
|
const handleDeletePlan = (row) => {
|
ElMessageBox.confirm(`确认删除该培训计划吗?`, "提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning"
|
}).then(async () => {
|
try {
|
const res = await deletePlan(row.id);
|
if (res.code === 200) {
|
ElMessage.success("删除成功");
|
getPlanData();
|
}
|
} catch (error) {
|
ElMessage.error("删除失败");
|
}
|
});
|
};
|
|
// ==================== 完成记录方法 ====================
|
const getRecordData = async () => {
|
recordLoading.value = true;
|
try {
|
const res = await getRecordList({
|
pageNum: recordPage.current,
|
pageSize: recordPage.size,
|
...recordFilters
|
});
|
if (res.code === 200) {
|
recordList.value = res.data.records || res.data.rows || [];
|
recordPage.total = res.data.total || 0;
|
}
|
} catch (error) {
|
ElMessage.error('获取完成记录失败');
|
} finally {
|
recordLoading.value = false;
|
}
|
};
|
|
const resetRecordFilters = () => {
|
recordFilters.employeeName = "";
|
recordFilters.status = null;
|
recordPage.current = 1;
|
getRecordData();
|
};
|
|
const changeRecordPage = ({ page, limit }) => {
|
recordPage.current = page;
|
recordPage.size = limit;
|
getRecordData();
|
};
|
|
const exportRecords = async () => {
|
try {
|
const res = await exportRecord(recordFilters);
|
// 处理文件下载
|
const blob = new Blob([res]);
|
const link = document.createElement('a');
|
link.href = URL.createObjectURL(blob);
|
link.download = '培训完成记录.xlsx';
|
link.click();
|
ElMessage.success('导出成功');
|
} catch (error) {
|
ElMessage.error('导出失败');
|
}
|
};
|
|
// 完成记录表单方法
|
const resetRecordForm = () => {
|
recordForm.id = null;
|
recordForm.planId = null;
|
recordForm.employeeId = null;
|
recordForm.employeeName = "";
|
recordForm.content = "";
|
recordForm.completeTime = "";
|
recordForm.duration = 0;
|
recordForm.method = "";
|
recordForm.score = 0;
|
recordForm.result = "";
|
recordForm.status = 1;
|
recordForm.remark = "";
|
};
|
|
// 加载培训计划选项
|
const loadPlanOptions = async () => {
|
try {
|
const res = await getPlanList({ pageNum: 1, pageSize: 1000 });
|
if (res.code === 200) {
|
planOptions.value = res.data.records || res.data.rows || [];
|
}
|
} catch (error) {
|
console.error('加载培训计划失败', error);
|
}
|
};
|
|
// 加载员工选项(从用户管理获取)
|
const loadEmployeeOptions = async () => {
|
try {
|
const res = await listUser({ pageNum: 1, pageSize: 1000 });
|
// 用户管理接口直接返回 rows,没有 code 字段
|
employeeOptions.value = res.rows || [];
|
} catch (error) {
|
console.error('加载员工列表失败', error);
|
}
|
};
|
|
const handlePlanChange = (val) => {
|
const selectedPlan = planOptions.value.find(item => item.id === val);
|
if (selectedPlan) {
|
recordForm.content = selectedPlan.content;
|
}
|
};
|
|
const handleEmployeeChange = (val) => {
|
const selectedEmployee = employeeOptions.value.find(item => item.userId === val);
|
if (selectedEmployee) {
|
recordForm.employeeName = selectedEmployee.userName;
|
}
|
};
|
|
const openRecordDialog = () => {
|
resetRecordForm();
|
loadPlanOptions();
|
loadEmployeeOptions();
|
recordDialog.title = "新增完成记录";
|
recordDialog.visible = true;
|
};
|
|
const handleEditRecord = async (row) => {
|
resetRecordForm();
|
try {
|
const res = await getRecordDetail(row.id);
|
if (res.code === 200) {
|
Object.assign(recordForm, res.data);
|
recordDialog.title = "编辑完成记录";
|
recordDialog.visible = true;
|
}
|
} catch (error) {
|
ElMessage.error('获取记录详情失败');
|
}
|
};
|
|
const submitRecordForm = async () => {
|
const valid = await recordFormRef.value.validate().catch(() => false);
|
if (!valid) return;
|
|
recordDialog.loading = true;
|
try {
|
const api = recordForm.id ? updateRecord : addRecordApi;
|
const res = await api(recordForm);
|
if (res.code === 200) {
|
ElMessage.success(recordForm.id ? '修改成功' : '新增成功');
|
recordDialog.visible = false;
|
getRecordData();
|
}
|
} catch (error) {
|
ElMessage.error(recordForm.id ? '修改失败' : '新增失败');
|
} finally {
|
recordDialog.loading = false;
|
}
|
};
|
|
const handleDeleteRecord = (row) => {
|
ElMessageBox.confirm(`确认删除该完成记录吗?`, "提示", {
|
confirmButtonText: "确认",
|
cancelButtonText: "取消",
|
type: "warning"
|
}).then(async () => {
|
try {
|
const res = await deleteRecord(row.id);
|
if (res.code === 200) {
|
ElMessage.success("删除成功");
|
getRecordData();
|
}
|
} catch (error) {
|
ElMessage.error("删除失败");
|
}
|
});
|
};
|
|
onMounted(() => {
|
getMaterialData();
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.actions {
|
margin-bottom: 15px;
|
display: flex;
|
justify-content: flex-end;
|
}
|
</style>
|