教培档案管理

dev
zhangyanli 2024-03-15 10:01:08 +08:00
parent a6a2fbc88b
commit da60a2c7c8
33 changed files with 5395 additions and 15 deletions

View File

@ -160,6 +160,14 @@ a {
display: none;
}
.mb {
margin-bottom: 10px;
}
.mt {
margin-top: 16px;
}
.text-blue {
color: #3b3bff;
}

View File

@ -11,6 +11,8 @@ export const getVerifyDuplicateEmail = (params) =>
post("/user/hasEmail", params); // 验证邮箱重复
export const getVerifyDeduplicationUser = (params) =>
post("/user/hasUser", params); // 用户名去重
export const getVerifyDeduplicationUserIdCard = (params) =>
post("/user/hasUserIdCard", params); // 用户身份证去重
export const setAvatar = (params) => upload("/photo/saveNew", params); // 修改头像
export const getInfo = (params) =>
post("/head/getInfo", { loading: false, ...params }); // 获取用户信息

View File

@ -0,0 +1,98 @@
import { post } from "@/request/axios.js";
export const getStudentsList = (params) =>
post("/archives/getStudentsList", params); // 一人一档用户列表
export const getClassForHealthList = (params) =>
post("/class/classForHealthList", params); // 学员档案列表
export const getClassForHealthStudentList = (params) =>
post("/student/classForHealthStudentList", params); // 学员档案的学员列表
export const downLoadStudentArchive = (params) =>
post("/archives/studentArchive", params); // 学员档案下载
export const getClassesList = (params) =>
post("/archives/getClassesList", params); // 一期一档档案列表
export const getUserClassesList = (params) =>
post("/archives/getUserClassesList", params); // 一人一档班级详情
export const getArchivesStudentEdit = (params) =>
post("/archivesstudent/goEdit", params); // 一人一档-人员登记表
export const downloadRegisterform = (params) =>
post("/archivesstudent/registerform", params); // 一人一档:个人登记表导出
export const getUserArchives = (params) =>
post("/archives/getUserArchives", params); // 一人一档-档案详情
export const getLearningRecord = (params) =>
post("/archives/getLearningRecord", params);
export const getDict = (params) => post("/dictionaries/getLevels", params); // 获取人员类型
export const downloadFilesdetailword = (params) =>
post("/archives/filesdetailword", params); // 一人一档:档案详情导出
export const getClassPapers = (params) =>
post("/archives/getClassPapers", params); // 一期一档:班级试卷列表
export const getClassPaperList = (params) =>
post("/archives/getClassPaperList", params); // 班级试卷列表
export const getClassCurriculumList = (params) =>
post("/archives/getClassCurriculumList", params); // 一期一档安全培训教材或课程讲义列表
export const getClassGoEdit = (params) => post("/class/goEdit", params);
export const getReviewGoEdit = (params) =>
post("/archivesReview/goEdit", params); // 一期一档安全培训教材会审表详情
export const getReviewRecord = (params) =>
post("/archives/reviewRecord", params); // 一期一档安全培训教材会审表情况
export const getStudentSigns = (params) =>
post("/archives/getStudentSigns", params); // 一期一档学员考核成绩统计表
export const getClassPaper = (params) => post("/archives/getPaper", params); // 一期一档试卷详情
export const getStudentFaces = (params) =>
post("/archives/getStudentFaces", params); // 一期一档影像资料
export const getCoursewares = (params) =>
post("/archives/getCoursewares", params); // 一期一档安全培训教材或课程讲义
export const getTrainingSchedule = (params) =>
post("/archives/trainingscheduleGoEdit", params); // 一期一档培训日程安排通知/也可称为培训计划
export const downloadArchiveDirectory = (params) =>
post("/archives/archiveDirectory", params); // 一期一档:档案目录批量导出
export const downloadTeachingMaterialAll = (params) =>
post("/archives/teachingMaterialAll", params); // 一期一档:安全培训教材或课程讲义批量导出
export const downloadTrainingPlan = (params) =>
post("/archives/trainingPlan", params); // 一期一档:安全培训教育记录及签字表批量导出
export const downloadArchivePapers = (params) =>
post("/archives/archivePapers", params); // 一期一档:考核试卷批量导出
export const downloadHsAll = (params) => post("/archives/hsAll", params); // 一期一档:会审表批量导出
export const downloadHs = (params) => post("/archives/hs", params); // 一期一档:会审表导出
export const downloadStudentsumtable = (params) =>
post("/archives/studentsumtable", params); // 一期一档:学员统计总表导出
export const downloadEvaluationreport = (params) =>
post("/archives/evaluationreport", params); // 一期一档:综合考评报告导出
export const downloadExaminationpaper = (params) =>
post("/archives/examinationpaper", params); // 一期一档:考核试卷导出
export const downloadImagedata = (params) =>
post("/archives/imagedata", params); // 一期一档:安全培训教育记录及签字表批量导出
export const downloadTeachingMaterial = (params) =>
post("/archives/teachingMaterial", params); // 一期一档:安全培训教材或课程讲义导出
export const downloadSign = (params) => post("/archives/sign", params); // 一期一档:安全培训教育记录及签字表批量导出
export const downloadAllwordzip = (params) =>
post("/archivesallcorpword/allwordzip", params); // 一企一档:档案目录
export const getArchivesfilesList = (params) =>
post("/archivesfiles/list", params); // 一企一档列表
export const getArchivesPostmanList = (params) =>
post("/archivespostman/list", params); // 一企一档:年度三岗人员管理台账列表
export const downloadPersonmanage = (params) =>
post("/archivespostman/personmanage", params); // 一企一档:三岗人员管理台账导出
export const getArchivesTeacherList = (params) =>
post("/archivesteacher/list", params); // 一企一档:年度本单位师资管理台账
export const getArchivesPlanList = (params) =>
post("/archiveseduplan/list", params); // 一企一档:年度安全培训教育计划
export const getArchivesManagerList = (params) =>
post("/archivesedumanager/list", params); // 一企一档:年度安全培训教育管理台账
export const getArchivesCapitalList = (params) =>
post("/archivescapital/list", params); // 一企一档:年度培训资金提取和使用情况管理台账
export const downloadFundmanageword = (params) =>
post("/archivescapital/fundmanageword", params); // 一企一档:年度培训资金提取和使用情况管理台账导出
export const downloadTrainingplanword = (params) =>
post("/archiveseduplan/trainingplanword", params); // 一企一档:年度安全培训教育计划导出
export const downloadEdumanageword = (params) =>
post("/archivesedumanager/edumanageword", params); // 一企一档:年度安全培训教育管理台账导出
export const downloadTeacherword = (params) =>
post("/archivesteacher/teacherword", params); // 一企一档:年度本单位师资管理台账
export const getPdffileList = (params) => post("/archivespdffile/list", params); // 档案下载重新下载
export const redownLoad = (params) =>
post("/archivespdffile/redownload", params); // 档案下载重新下载

View File

@ -1,21 +1,19 @@
import { post, upload } from "@/request/axios.js";
export const getVideoCoursewareList = (params) =>
post("/platform/videocourseware/list", params); // 视频课件列表
post("/videocourseware/list", params); // 视频课件列表
export const getPreviewingVideo = (params) =>
post("/platform/videocourseware/getPlayInfo", params); // 预览视频
post("/videocourseware/getPlayInfo", params); // 预览视频
export const getVideoCoursewareView = (params) =>
post("/platform/videocourseware/goEdit", params); // 视频课件查看
post("/videocourseware/goEdit", params); // 视频课件查看
export const getVideoCoursewareExercisesList = (params) =>
post("/platform/question/list", params); // 视频课件习题列表
post("/question/list", params); // 视频课件习题列表
export const getCourseManagementList = (params) =>
post("/platform/curriculum/list", params); // 课程管理列表
post("/curriculum/list", params); // 课程管理列表
export const setCourseManagementDelete = (params) =>
post("/curriculum/delById", params); // 课程管理删除
export const getCourseManagementView = (params) =>
post("/curriculum/goEdit", params); // 课程管理查看
export const getSelectCourseManagementList = (params) =>
post("/videocourseware/list", params); // 选择视频课件列表
export const setCourseManagementAdd = (params) =>
upload("/curriculum/add", params); // 课程管理添加
export const setCourseManagementEdit = (params) =>

View File

@ -0,0 +1,176 @@
<template>
<div>
<el-form
:model="searchForm"
label-width="80px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="档案描述" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入档案描述"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="档案类型" prop="TYPE">
<el-select
v-model="searchForm.TYPE"
placeholder="请选择档案类型"
style="width: 100%"
>
<el-option
v-for="item in data.typeList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="获取时间" prop="DATES">
<el-date-picker
v-model="searchForm.DATES"
type="daterange"
range-separator="至"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态" prop="STATUS">
<el-select
v-model="searchForm.STATUS"
placeholder="请选择状态"
style="width: 100%"
>
<el-option
v-for="item in data.statusList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit"> 搜索 </el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column
reserve-selection
type="selection"
width="55"
align="center"
/>
<el-table-column label="序号" width="60" align="center">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="DESCR" label="档案描述" align="center" />
<el-table-column prop="TYPE" label="档案类型" align="center" width="100">
<template #default="{ row }">
<template v-if="row.TYPE === '1'"> </template>
<template v-else-if="row.TYPE === '2'"> 一期一档 </template>
<template v-else-if="row.TYPE === '3'"> 一企一档 </template>
</template>
</el-table-column>
<el-table-column prop="STATUS" label="状态" align="center" width="100">
<template #default="{ row }">
<template v-if="row.STATUS === '0'">
<div>上传中</div>
</template>
<template v-else-if="row.STATUS === '1'">
<div style="color: green">上传成功</div>
</template>
<template v-else-if="row.STATUS === '-1'">
<div style="color: red">上传失败</div>
</template>
<template v-else-if="row.STATUS === '-2'">
<div>已删除</div>
</template>
</template>
</el-table-column>
<el-table-column prop="CREATOR" label="获取人" align="center" />
<el-table-column prop="CREATTIME" label="获取时间" align="center" />
<el-table-column label="操作" align="center" width="150" fixed="right">
<template #default="{ row }">
<el-button
v-show="row.STATUS === '1' && row.FILE_PATH"
type="text"
@click="fnHandleDownload(row.FILE_PATH)"
>下载</el-button
>
<el-button
v-show="row.STATUS === '-1' && row.FILE_PATH"
type="text"
@click="fnRedownLoad(row.ARCHIVES_PDF_FILE_ID)"
>重新下载</el-button
>
</template>
</el-table-column>
</layout-table>
</div>
</template>
<script setup>
import LayoutTable from "@/components/table/index.vue";
import { serialNumber } from "@/assets/js/utils";
import { ElMessageBox } from "element-plus";
import { reactive, ref } from "vue";
import {
getPdffileList,
redownLoad,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.js";
const tableRef = ref(null);
const FILE_URL = import.meta.env.VITE_FILE_URL;
const data = reactive({
typeList: [
{ id: "1", name: "一人一档" },
{ id: "2", name: "一期一档" },
{ id: "3", name: "一企一档" },
],
statusList: [
{ id: "0", name: "上传中" },
{ id: "1", name: "上传成功" },
{ id: "-1", name: "上传失败" },
{ id: "-2", name: "已删除" },
],
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getPdffileList);
const fnHandleDownload = (filePath) => {
window.open(FILE_URL + filePath);
};
const fnRedownLoad = async (ARCHIVES_PDF_FILE_ID) => {
ElMessageBox.confirm("确定要重新下载吗?(如状态未更新,请稍后刷新页面)", {
type: "info",
});
await redownLoad({
ARCHIVES_PDF_FILE_ID,
});
setTimeout(() => {
fnGetData();
}, 2000);
};
</script>
<style scoped></style>

View File

@ -0,0 +1,108 @@
<template>
<div>
<el-card>
<el-form label-width="80px">
<el-row>
<el-col :span="6">
<el-form-item label="年份" prop="YEAR">
<el-date-picker
v-model="data.YEAR"
value-format="YYYY"
type="year"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" @click="fnExport"></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column prop="NAME" label="目录" />
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button type="primary" text link @click="fnEdit(row)"
>编辑</el-button
>
</template>
</el-table-column>
</layout-table>
<component
:is="data.component"
v-if="data.component"
v-model:type="data.type"
:title="data.title"
:year="data.YEAR"
/>
</el-card>
</div>
</template>
<script setup>
import LayoutTable from "@/components/table/index.vue";
import { markRaw, reactive } from "vue";
import dayjs from "dayjs";
import { debounce } from "throttle-debounce";
import { ElMessageBox } from "element-plus";
import Pdf from "./components/pdf.vue";
import Postman from "./components/postman.vue";
import Teacher from "./components/teacher";
import Eduplan from "./components/eduplan";
import Edumanager from "./components/edumanager";
import Capital from "./components/capital";
import { downloadAllwordzip } from "@/request/training_archive_management.js";
const data = reactive({
list: [
{ NAME: "安全培训教育制度", TYPE: 1, component: markRaw(Pdf) },
{
NAME: "关于任命安全教育主管部门和人员的文件",
TYPE: 2,
component: markRaw(Pdf),
},
{ NAME: "三岗人员管理台账", TYPE: 101, component: markRaw(Postman) },
{ NAME: "培训需求调查表", TYPE: 3, component: markRaw(Pdf) },
{ NAME: "本单位师资管理台账", TYPE: 102, component: markRaw(Teacher) },
{ NAME: "年度安全培训教育计划", TYPE: 103, component: markRaw(Eduplan) },
{
NAME: "年度安全培训教育管理台账",
TYPE: 104,
component: markRaw(Edumanager),
},
{
NAME: "年度培训资金提取和使用情况管理台账",
TYPE: 105,
component: markRaw(Capital),
},
{ NAME: "培训条件证明材料", TYPE: 4, component: markRaw(Pdf) },
],
YEAR: dayjs().format("YYYY"),
component: "",
type: "",
title: "",
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadAllwordzip({
YEAR: data.YEAR,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnEdit = ({ TYPE, NAME, component }) => {
data.type = TYPE;
data.title = NAME;
data.component = component;
};
</script>
<style scoped></style>

View File

@ -0,0 +1,125 @@
<template>
<el-dialog
:title="title"
:model-value="type === 105"
width="1100px"
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ year }}年度培训资金提取和使用情况管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="DATE" label="日期" />
<el-table-column label="费用项目">
<el-table-column prop="AMOUNT" label="提取金额" />
<el-table-column prop="ITEM_TYPE" label="项目类型" />
<el-table-column prop="MATERIAL_COST" label="培训教材教具费" />
<el-table-column prop="TEACHER_COST" label="师资费" />
<el-table-column prop="PAPER_COST" label="试卷印制费" />
<el-table-column prop="OUTSIDE_COST" label="外出培训费" />
<el-table-column
prop="EQUIPMENT_COST"
label="教学设备、课桌椅等购置维护费"
/>
<el-table-column prop="TRAIN_COST" label="培训活动费" />
<el-table-column prop="ENTRUST_COST" label="委托培训费" />
<el-table-column prop="OTHER_COST" label="其他与培训有关的直接支出" />
</el-table-column>
<el-table-column prop="BALANCE" label="余额" />
</layout-table>
<div class="flex mt">
<div>制表人:</div>
<div>编制日期:</div>
<div>审核人:</div>
<div>审核日期:</div>
</div>
<div class="mt">
填表说明:1.将实际发生的费用金额记录在费用项目栏内2.培训提取比例按职工工资1.5%可按季或月提取
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesCapitalList,
downloadFundmanageword,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesCapitalList({
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
watchEffect(() => {
if (props.type === 105) fnGetData();
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadFundmanageword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,137 @@
<template>
<el-dialog
:title="title"
:model-value="type === 104"
width="1100px"
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ year }}年度安全培训教育管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="TRAINING_DATE" label="培训时间" />
<el-table-column prop="TRAINING_OBJECT" label="培训对象" />
<el-table-column prop="TRAINING_TYPE" label="培训类型">
<template #default="{ row }">
<span v-if="row.TRAINLEVEL_NAME"
>{{ row.TRAINING_TYPE }}-{{ row.TRAINLEVEL_NAME }}</span
>
<span v-else>{{ row.TRAINING_TYPE }}</span>
</template>
</el-table-column>
<el-table-column prop="TRAINING_CONTENT" label="培训内容" />
<el-table-column prop="PERSON_NUMBER" label="参加人数" />
<el-table-column prop="CLASS_HOURS" label="培训学时" />
<el-table-column prop="TRAINING_PLACE" label="培训地点">
<span>{{ name }}</span>
</el-table-column>
<el-table-column prop="TRAINING_TEACHERS" label="培训教师" />
<el-table-column prop="ASSESSMENT_METHOD" label="考核方式">
<span>线上考核</span>
</el-table-column>
<el-table-column prop="ASSESSMENT" label="汇总考核情况">
<template #default="{ row }">
<span>
参与人数:{{ row.PERSON_NUMBER }},<br />
通过人数:{{ row.GETPASS_NUMBER }},<br />
通过率:{{
!row.GETPASS_NUMBER
? 0
: ((row.GETPASS_NUMBER / row.PERSON_NUMBER) * 100).toFixed(2)
}}%
</span>
</template>
</el-table-column>
</layout-table>
<div class="flex mt">
<div>档案管理人员:</div>
<div>更新日期:</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesManagerList,
downloadEdumanageword,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesManagerList({
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
watchEffect(() => {
if (props.type === 104) fnGetData();
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadEdumanageword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,154 @@
<template>
<el-dialog
:title="title"
:model-value="type === 103"
width="1100px"
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
<el-button type="primary" @click="data.dialogForFile = true"
>上传文件</el-button
>
</div>
<div class="tc">
<h3>{{ year }}年度安全培训教育计划</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="START_TIME" label="开始时间" />
<el-table-column prop="END_TIME" label="结束时间" />
<el-table-column prop="TRAINING_OBJECT" label="培训对象" />
<el-table-column prop="TRAINING_MATERIALS" label="培训内容" />
<el-table-column prop="TRAINING_METHODS" label=" 培训方式">
<span>线上培训</span>
</el-table-column>
<el-table-column prop="ASSESSMENT_METHOD" label="考核方式">
<span>线上考核</span>
</el-table-column>
<el-table-column prop="CLASSHOUR" label="学时" />
<el-table-column prop="PLACE" label="地点">
<span>{{ name }}</span>
</el-table-column>
<el-table-column prop="TRAINING_TEACHERS" label="培训教师" />
<el-table-column prop="FUND_GUARANTEE" label="经费保障">
<span>安全生产投入</span>
</el-table-column>
<el-table-column prop="QUALITY_ASSESSMENT" label="质量评估">
<span>问卷调查</span>
</el-table-column>
</layout-table>
<div class="flex mt">
<div>档案管理人员:</div>
<div>更新日期:</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
<el-dialog
v-model:visible="data.dialogForFile"
:title="'安全培训教育计划'"
top="50px"
width="1200px"
append-to-body
>
<file
v-if="data.dialogForFile"
:id="CORPINFO_ID"
:year="year"
:type="103"
/>
<template #footer>
<el-button @click="data.dialogForFile = false">关闭</el-button>
</template>
</el-dialog>
<pdf
v-if="data.dialogForFile"
:title="'安全培训教育计划'"
:type="103"
:year="year"
/>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesPlanList,
downloadTrainingplanword,
} from "@/request/training_archive_management.js";
import Pdf from "./pdf.vue";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
id: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
dialogForFile: false,
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesPlanList({
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
ENTERPRISE_ID: props.ENTERPRISE_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
watchEffect(() => {
if (props.type === 103) fnGetData();
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadTrainingplanword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
ENTERPRISE_ID: props.ENTERPRISE_ID,
NAME: props.name,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,165 @@
<template>
<el-dialog
:title="title"
:model-value="
type === 1 || type === 2 || type === 3 || type === 4 || type === 103
"
width="1100px"
@close="fnClose"
>
<div class="content-flex">
<div class="content-left">
<el-scrollbar style="height: 600px">
<layout-table
:data="data.list"
:show-header="false"
:show-pagination="false"
:border="false"
:stripe="false"
:highlight-current-row="true"
@row-click="fnRowClick"
>
<el-table-column prop="FILE_NAME" />
</layout-table>
</el-scrollbar>
</div>
<div class="content-right">
<div v-if="!data.pdfSrc" class="content-tip">
<div class="box">
<div class="icon">
<icon-file-pdf-one
theme="filled"
size="60"
fill="#fff"
:stroke-width="3"
/>
</div>
<div class="info">
<div class="h1">PDF文件预览</div>
<div class="p1">请点击左侧列表显示PDF文件预览</div>
</div>
</div>
</div>
<el-scrollbar style="height: 600px">
<div v-if="data.pdfSrc">
<vue-pdf
v-for="page in data.numOfPages"
:key="page"
:src="data.pdfSrc"
:page="page"
/>
</div>
</el-scrollbar>
</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { nextTick, reactive, watchEffect } from "vue";
import { VuePdf, createLoadingTask } from "vue3-pdfjs/esm";
import { getArchivesfilesList } from "@/request/training_archive_management.js";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
pdfSrc: "",
numOfPages: 0,
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesfilesList({
TYPE: props.type,
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
MODULE: "corp",
});
data.list = resData.varList;
};
watchEffect(() => {
if (
props.type === 1 ||
props.type === 2 ||
props.type === 3 ||
props.type === 4 ||
props.type === 103
)
fnGetData();
});
const fnRowClick = async (row) => {
data.pdfSrc = "";
await nextTick();
data.pdfSrc = FILE_URL + row.FILE_PATH;
const loadingTask = createLoadingTask(FILE_URL + row.FILE_PATH);
loadingTask.promise.then((pdf) => {
data.numOfPages = pdf.numPages;
});
};
const fnClose = () => {
data.pdfSrc = "";
data.numOfPages = 0;
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.content-flex {
margin-top: 10px;
display: flex;
height: 600px;
.content-left {
padding-left: 25px;
width: 240px;
}
.content-right {
position: relative;
flex: 1;
.content-tip {
position: absolute;
border: 1px dashed #ccc;
width: 98%;
height: 100%;
left: 2%;
text-align: center;
.box {
display: flex;
justify-content: center;
align-items: center;
position: relative;
top: 230px;
.info {
text-align: left;
color: #a6a6a6;
}
}
}
}
}
</style>

View File

@ -0,0 +1,125 @@
<template>
<el-dialog
:title="title"
:model-value="type === 101"
width="1100px"
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ year }}年度三岗人员管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="NAME" label="姓名" />
<el-table-column prop="POST" label="岗位/操作项目" />
<el-table-column prop="PHONE" label="电话" />
<el-table-column prop="img" label="照片">
<template #default="{ row }">
<viewer v-if="row.FILEPATH">
<img
:src="FILE_URL + row.FILEPATH"
style="width: 50px; height: 50px"
/>
</viewer>
</template>
</el-table-column>
<el-table-column prop="CARD_ID" label="证书号" />
<el-table-column prop="EFFECTIVE_DATE" label="证书有效期限" />
<el-table-column prop="RETRAINING" label="复训日期" />
<el-table-column prop="RETRAINING" label="操作" align="center">
<template #default="{ row }">
<el-button type="primary" @click="handleEdit(row)"></el-button>
</template>
</el-table-column>
</layout-table>
<div class="flex mt">
<div>档案管理人员:</div>
<div>更新日期:</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesPostmanList,
downloadPersonmanage,
} from "@/request/training_archive_management.js";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesPostmanList({
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
watchEffect(() => {
if (props.type === 101) fnGetData();
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadPersonmanage({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<el-dialog
:title="title"
:model-value="type === 102"
width="1100px"
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ year }}年度本单位师资管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="NAME" label="姓名" />
<el-table-column prop="WORKYEAR" label="从事本专业工作年限" />
<el-table-column prop="OCCUPATION" label="专/兼职">
<span>兼职</span>
</el-table-column>
<el-table-column prop="CARD_ID" label="证书编号" />
<el-table-column prop="ASSESSMENTDEPARTMENT" label="考核部门" />
<el-table-column prop="ASSESSMENTTIME" label="考核日期" />
<el-table-column prop="ASSESSMENTRESULT" label="考核结果" />
<el-table-column prop="DESCR" label="备注" />
</layout-table>
<div class="flex mt">
<div>档案管理人员:</div>
<div>更新日期:</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesTeacherList,
downloadTeacherword,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesTeacherList({
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
watchEffect(() => {
if (props.type === 102) fnGetData();
});
const fnExport = debounce(
1000,
async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadTeacherword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,203 @@
<template>
<div>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<layout-table
ref="tableRef"
row-key="TYPE"
:data="data.list"
:show-pagination="false"
>
<el-table-column reserve-selection type="selection" width="55" />
<el-table-column prop="NAME" label="目录" />
<el-table-column prop="" label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" text link @click="fnView(row)">
编辑
</el-button>
</template>
</el-table-column>
</layout-table>
<component
:is="data.component"
v-if="data.component"
v-model:type="data.type"
:title="data.title"
:clazz-id="CLASS_ID"
:post-id="POST_ID"
:corp-info-id="CORPINFO_ID"
:corp-name="CORP_NAME"
:post-name="POST_NAME"
/>
<el-dialog
:model-value="data.delayDialog.visible"
title="设置"
width="500px"
append-to-body
>
<el-form
ref="delayDialogForm"
:model="data.delayDialog.form"
:rules="data.delayDialog.rules"
label-width="80px"
>
<el-form-item label="编制日期" prop="TIME">
<el-date-picker
v-model="data.delayDialog.form.TIME"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="submit"> </el-button>
<el-button @click="data.delayDialog.visible = false"> </el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import TrainingSchedule from "./components/training_schedule.vue";
import Image from "./components/image.vue";
import Report from "./components/report.vue";
import Results from "./components/results.vue";
import SignatureForm from "./components/signature_form.vue";
import { markRaw, reactive, ref } from "vue";
import { useRoute, useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import {
getClassPapers,
downloadArchiveDirectory,
} from "@/request/training_archive_management.js";
const router = useRouter();
const route = useRoute();
const { CLASS_ID, CORP_NAME, CLASS_NAME, CORPINFO_ID, POST_ID, POST_NAME } =
route.query;
const tableRef = ref(null);
const data = reactive({
list: [
{
NAME: "安全培训教材会审表",
TYPE: 100,
component: "",
url: "/archives_management/semester/archives/review_list",
},
{
NAME: "培训日程安排通知/也可称为培训计划",
TYPE: 101,
component: markRaw(TrainingSchedule),
},
{
NAME: "安全培训教材或课程讲义",
TYPE: 106,
component: "",
url: "/archives_management/semester/archives/handout_list",
},
{
NAME: "安全培训教育记录及签字表",
TYPE: 102,
component: markRaw(SignatureForm),
},
{ NAME: "培训影像资料", TYPE: 107, component: markRaw(Image) },
{
NAME: "培训考核试卷",
TYPE: 103,
component: "",
url: "/archives_management/semester/archives/paper_list",
},
{ NAME: "学员考核成绩统计表", TYPE: 104, component: markRaw(Results) },
{ NAME: "本期综合考评报告", TYPE: 105, component: markRaw(Report) },
],
type: 0,
title: "",
component: "",
delayDialog: {
visible: false,
form: {
TIME: "",
},
rules: {
TIME: [{ required: true, message: "请选择日期", trigger: "blur" }],
},
},
});
const fnView = ({ TYPE, NAME, component, url }) => {
if (!component && url) {
router.push({
path: url,
query: {
...route.query,
},
});
} else {
data.type = TYPE;
data.title = NAME;
data.component = component;
}
};
const fnExport = async () => {
let setDateFlag = false;
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选中要导出的项");
return;
}
for (let i = 0; i < selectionData.length; i++) {
if (JSON.stringify(selectionData[i].TYPE) === "101") {
setDateFlag = true;
}
}
if (setDateFlag) {
await ElMessageBox.confirm("导出前,请设置培训计划表中的编制日期", {
type: "warning",
});
data.delayDialog.visible = true;
} else {
submit();
}
};
const submit = async () => {
data.delayDialog.visible = false;
const selectionData = tableRef.value.getSelectionRows();
//
if (
selectionData.length === 1 &&
JSON.stringify(selectionData[0].TYPE) === "103"
) {
const resData = await getClassPapers({ CLASS_ID });
if (resData.varList.length === 0) {
ElMessage.error("培训考核试卷没有数据!");
} else {
recordDownLoad(selectionData);
}
} else {
recordDownLoad(selectionData);
}
};
const recordDownLoad = async (selectionData) => {
const archiveDirectory = [];
for (let i = 0; i < selectionData.length; i++) {
archiveDirectory.push({
NAME: selectionData[i].NAME,
TYPE: selectionData[i].TYPE,
});
}
await ElMessageBox.confirm("确认要导出吗?", { type: "warning" });
await downloadArchiveDirectory({
CLASS_NAME,
CLASS_ID,
CORPINFO_ID,
typeList: JSON.stringify(archiveDirectory),
UPDATE_DATE: data.delayDialog.form.TIME,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
tableRef.value.clearSelection();
};
</script>
<style scoped></style>

View File

@ -0,0 +1,115 @@
<template>
<el-dialog
:title="title"
:model-value="type === 106"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<dl v-for="(item, index) in data.list" :key="index">
<h2 class="tc">
{{ item.CURRICULUMNAME }}
</h2>
<div
v-for="(cha, i) in item.chapterList"
:key="i"
style="padding-bottom: 20px"
>
<div v-if="item.CATALOGUELEVEL === '1'">
<dt>{{ i + 1 }}.{{ cha.CHAPTER_NAME }}</dt>
<dd>课件描述 {{ cha.COURSEWAREINTRODUCE }}</dd>
</div>
<div v-else-if="item.CATALOGUELEVEL === '2'">
<dt>{{ i + 1 }}.{{ cha.CHAPTER_NAME }}</dt>
<div v-for="(video, j) in cha.nodes" :key="j">
<dd>{{ j + 1 }}.{{ video.CHAPTER_NAME }}</dd>
<dd>课件描述 {{ video.COURSEWAREINTRODUCE }}</dd>
</div>
</div>
</div>
</dl>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getCoursewares,
downloadTeachingMaterial,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
curriculumId: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getCoursewares({
CLASS_ID: props.clazzId,
CURRICULUM_ID: props.curriculumId,
});
data.list = resData.curList;
};
watchEffect(() => {
if (props.type === 106) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadTeachingMaterial({
CLASS_ID: props.clazzId,
CURRICULUM_ID: props.curriculumId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
dd,
dt {
line-height: 24px;
}
</style>

View File

@ -0,0 +1,191 @@
<template>
<el-dialog
:title="title"
:model-value="type === 107"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="flex mb">
<p>班级名称:{{ data.info.NAME }}</p>
</div>
<table>
<tr>
<td width="5%">序号</td>
<td width="10%">学员姓名</td>
<td width="15%">身份证号</td>
<td width="10%">手机</td>
<td width="10%">头像</td>
<td colspan="5">认证照片</td>
</tr>
<template v-for="(item, index) in data.list" :key="index">
<tr style="height: 75px">
<td width="5%">{{ index + 1 }}</td>
<td width="10%">{{ item.NAME }}</td>
<td width="15%">{{ item.USER_ID_CARD }}</td>
<td width="10%">{{ item.PHONE }}</td>
<td width="10%">
<viewer v-if="item.PORTRAIT">
<img
:src="FILE_URL + item.PORTRAIT"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
<td width="10%">
<viewer v-if="item.FACES[0]">
<img
:src="FILE_URL + item.FACES[0]"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
<td width="10%">
<viewer v-if="item.FACES[1]">
<img
:src="FILE_URL + item.FACES[1]"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
<td width="10%">
<viewer v-if="item.FACES[2]">
<img
:src="FILE_URL + item.FACES[2]"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
<td width="10%">
<viewer v-if="item.FACES[3]">
<img
:src="FILE_URL + item.FACES[3]"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
<td width="10%">
<viewer v-if="item.FACES[4]">
<img
:src="FILE_URL + item.FACES[4]"
style="width: 50px; height: 50px"
/>
</viewer>
</td>
</tr>
</template>
</table>
<div class="mt">备注仅限用于线上学习证明材料其他使用无效</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getClassGoEdit,
getStudentFaces,
downloadImagedata,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
});
const data = reactive({
info: {},
list: [],
});
const emits = defineEmits(["update:type"]);
const FILE_URL = import.meta.env.VITE_FILE_URL;
const fnGetData = async () => {
const resData = await getClassGoEdit({
TYPE: props.type,
CLASS_ID: props.clazzId,
});
data.info = resData.pd;
};
const fnStudentFaces = async () => {
const resData = await getStudentFaces({
CLASS_ID: props.clazzId,
});
data.list = resData.studentList;
data.list.forEach((item) => {
if (item.FACES) {
item.FACES = item.FACES.split(",");
} else {
item.FACES = [];
}
});
};
fnStudentFaces();
watchEffect(() => {
if (props.type === 107) {
fnGetData();
fnStudentFaces();
}
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadImagedata({
CLASS_ID: props.clazzId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
text-align: center;
}
}
</style>

View File

@ -0,0 +1,180 @@
<template>
<el-dialog
:title="title"
:model-value="type === 103"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div
class="title"
style="text-align: center; font-size: 28px; color: #000000"
>
{{ data.info.EXAMNAME }}
</div>
<div class="tc mt">(满分:{{ data.info.EXAMSCORE || 0 }})</div>
<dl v-for="(item, index) in data.questionList" :key="item.QUESTION_ID">
<dt>
<el-tag v-if="item.QUESTIONTYPE === '1'" type="success">
(单选题)
</el-tag>
<el-tag v-if="item.QUESTIONTYPE === '2'"> () </el-tag>
<el-tag v-if="item.QUESTIONTYPE === '3'" type="warning">
(判断题)
</el-tag>
<el-tag v-if="item.QUESTIONTYPE === '4'" type="danger">
(填空题)
</el-tag>
{{ index + 1 }}.{{ item.QUESTIONDRY }}
<span class="ml">
(题目分值{{ item.SCORE }} 正确答案{{ item.ANSWER }})
</span>
</dt>
<el-radio-group
v-if="item.QUESTIONTYPE === '1'"
v-model="item.ANSWER"
:disabled="true"
>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio label="C">C.{{ item.OPTIONC }}</el-radio>
<el-radio label="D">D.{{ item.OPTIOND }}</el-radio>
</el-radio-group>
<el-checkbox-group
v-if="item.QUESTIONTYPE === '2'"
v-model="item.checkList"
:disabled="true"
>
<el-checkbox label="A">A.{{ item.OPTIONA }}</el-checkbox>
<el-checkbox label="B">B.{{ item.OPTIONB }}</el-checkbox>
<el-checkbox label="C">C.{{ item.OPTIONC }}</el-checkbox>
<el-checkbox label="D">D.{{ item.OPTIOND }}</el-checkbox>
</el-checkbox-group>
<el-radio-group
v-if="item.QUESTIONTYPE === '3'"
v-model="item.ANSWER"
:disabled="true"
class="panduan"
>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<div class="el-radio"></div>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
<div class="el-radio"></div>
</el-radio-group>
</dl>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getClassPaper,
downloadExaminationpaper,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
stageexampaperinputId: {
type: String,
required: true,
},
});
const data = reactive({
questionList: [],
info: {},
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getClassPaper({
STAGEEXAMPAPERINPUT_ID: props.stageexampaperinputId,
});
data.info = resData.paper;
data.questionList = resData.questionList;
for (let i = 0; i < data.questionList.length; i++) {
if (
data.questionList[i].QUESTIONTYPE === "2" &&
data.questionList[i].ANSWER
) {
data.questionList[i].checkList = data.questionList[i].ANSWER.split("");
}
}
};
watchEffect(() => {
if (props.type === 103) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadExaminationpaper({
CLASS_ID: props.clazzId,
STAGEEXAMPAPERINPUT_ID: props.stageexampaperinputId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
dl {
width: 100%;
}
:deep {
.el-radio__input.is-disabled + span.el-radio__label {
white-space: break-spaces;
word-break: break-all;
line-height: 20px;
}
.el-checkbox__input.is-disabled + span.el-checkbox__label {
white-space: break-spaces;
word-break: break-all;
line-height: 20px;
}
.el-radio-group {
width: 90%;
margin: 0 5%;
justify-content: space-between;
flex-wrap: wrap;
.el-radio {
width: 25%;
margin-right: 0;
height: auto;
min-height: 30px;
}
}
.el-checkbox-group {
width: 90%;
margin: 0 5%;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.el-checkbox {
flex-basis: 25%;
margin-right: 0;
height: auto;
min-height: 30px;
line-height: 10px;
}
}
}
</style>

View File

@ -0,0 +1,181 @@
<template>
<el-dialog
:title="title"
:model-value="type === 105"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<h2 class="tc mb">{{ data.clazz.NAME }}培训综合考评报告</h2>
<table>
<tr class="tab_tr">
<td class="tc">培训班名称</td>
<td class="tc">{{ data.clazz.NAME }}</td>
<td class="tc">培训组织部门</td>
<td />
</tr>
<tr class="tab_tr">
<td class="tc">评估日期</td>
<td class="tc">
{{ dayjs(data.clazz.END_TIME).format("YYYY年MM月DD日") }}
</td>
<td class="tc">评估方式</td>
<td class="tc">问卷调查</td>
</tr>
<tr class="tab_tr" style="height: 127px">
<td class="tc">本次工作培训描述</td>
<td colspan="3">
本次培训的主要内容是:{{ data.info.CURRICULUMNAMES }}共应参加人数为{{
data.students.length
}},实际参加培训人数为{{ data.joinStudent }}, 参加率为{{
data.students.length > 0
? ((data.joinStudent / data.students.length) * 100).toFixed(2)
: 0
}}%
</td>
</tr>
<tr class="tab_tr" style="height: 127px">
<td class="tc">本次培训考评结论</td>
<td
v-if="data.clazz.TRAINTYPE === '9cbe83925bbb4d84bc057b5eb5607a53'"
colspan="3"
>
本次培训不进行考试
</td>
<td v-else colspan="3">
本次通过笔试的方式进行了培训效果考核,考核人数为{{
data.students.length
}},考核合格人数为{{ data.passStudent }}, 合格率为{{
data.students.length > 0
? ((data.passStudent / data.students.length) * 100).toFixed(2)
: 0
}}%
</td>
</tr>
<tr class="tab_tr" style="height: 127px">
<td class="tc">改进意见建议</td>
<td colspan="3">
<div>1.本次培训的讲师</div>
<div>非常满意</div>
<div>2.本次培训的课程</div>
<div>非常满意</div>
</td>
</tr>
<tr class="tab_tr">
<td class="tc">评估负责人</td>
<td />
<td class="tc">参加评估人</td>
<td />
</tr>
</table>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getStudentSigns,
downloadEvaluationreport,
} from "@/request/training_archive_management.js";
import dayjs from "dayjs";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
});
const data = reactive({
info: {},
clazz: {},
joinStudent: 0,
unpassStudent: 0,
passStudent: 0,
students: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getStudentSigns({
CORPINFO_ID: props.corpInfoId,
CLASS_ID: props.clazzId,
});
data.info = resData.rpd;
data.clazz = resData.clazz;
data.students = resData.studentList;
data.passStudent = 0;
data.unpassStudent = 0;
data.joinStudent = 0;
resData.studentList.forEach((item) => {
if (
item.STAGEEXAMSTATE === "3" ||
(item.STAGEEXAMSTATE === "0" && item.STUDYSTATE === "3")
) {
data.passStudent++;
}
if (item.STUDYSTATE > 0) {
data.joinStudent++;
}
});
};
watchEffect(() => {
if (props.type === 105) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadEvaluationreport({
CLASS_ID: props.clazzId,
CORPINFO_ID: props.corpInfoId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
line-height: 1.6;
}
}
</style>

View File

@ -0,0 +1,265 @@
<template>
<el-dialog
:title="title"
:model-value="type === 104"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div id="printContent">
<h2 class="tc">学员考核成绩统计表</h2>
<div class="flex mt mb">
<span>平台名称:{{ data.info.CORPINFO_NAME }}</span>
<span
>报表日期:{{ dayjs(data.clazz.END_TIME).format("YYYY-MM-DD") }}</span
>
</div>
<table>
<tr>
<td colspan="2">公司名称</td>
</tr>
<tr>
<td colspan="2">{{ data.clazz.CORP_INFO }}</td>
</tr>
<tr>
<td>培训时间</td>
<td>任务名称</td>
</tr>
<tr>
<td>
{{ dayjs(data.clazz.START_TIME).format("YYYY-MM-DD") }}
{{ dayjs(data.clazz.END_TIME).format("YYYY-MM-DD") }}
</td>
<td>{{ data.clazz.NAME }}</td>
</tr>
<tr>
<td>应参加培训人数</td>
<td>实际参加培训人数</td>
</tr>
<tr>
<td>{{ data.passStudent.length + data.unPassStudent.length }}</td>
<td>{{ data.passStudent.length }}</td>
</tr>
<tr>
<td colspan="6">合格学员名单</td>
</tr>
<tr>
<td colspan="6" style="padding: 0">
<table>
<tr>
<td class="title" style="width: 5%">序号</td>
<td class="title" style="width: 15%">姓名</td>
<td class="title" style="width: 20%">身份证</td>
<td class="title" style="width: 15%">手机号</td>
<td class="title" style="width: 10%">性别</td>
<td class="title" style="width: 10%">完成学时</td>
<td class="title" style="width: 10%">结业考试成绩</td>
</tr>
<template v-for="(item, index) in data.passStudent" :key="index">
<tr>
<td>{{ index + 1 }}</td>
<td>{{ item.NAME }}</td>
<td>{{ item.USER_ID_CARD }}</td>
<td>{{ item.PHONE }}</td>
<td>{{ item.SEX_NAME }}</td>
<td>
{{
item.COMPLETE_CLASSHOUR === "0" ||
item.COMPLETE_CLASSHOUR === "0.0"
? 0
: parseFloat(item.COMPLETE_CLASSHOUR).toFixed(1)
}}
</td>
<td>
{{
item.STAGEEXAMSCORE > -1 ? item.STAGEEXAMSCORE : "不考试"
}}
</td>
</tr>
</template>
</table>
</td>
</tr>
<tr>
<td colspan="6">未合格学员名单</td>
</tr>
<tr>
<td colspan="6" style="padding: 0">
<table>
<tr>
<td class="title" style="width: 5%">序号</td>
<td class="title" style="width: 15%">姓名</td>
<td class="title" style="width: 20%">身份证</td>
<td class="title" style="width: 15%">手机号</td>
<td class="title" style="width: 10%">性别</td>
<td class="title" style="width: 10%">完成学时</td>
<td class="title" style="width: 10%">结业考试成绩</td>
</tr>
<template
v-for="(item, index) in data.unPassStudent"
:key="index"
>
<tr>
<td>{{ index + 1 }}</td>
<td>{{ item.NAME }}</td>
<td>{{ item.USER_ID_CARD }}</td>
<td>{{ item.PHONE }}</td>
<td>{{ getGenderByIdNumber(item.USER_ID_CARD) }}</td>
<td>
{{
item.COMPLETE_CLASSHOUR === "0" ||
item.COMPLETE_CLASSHOUR === "0.0"
? 0
: parseFloat(item.COMPLETE_CLASSHOUR).toFixed(1)
}}
</td>
<td v-if="data.clazz.EXAMINATION === 0">
{{
item.STAGEEXAMSCORE > -1 ? item.STAGEEXAMSCORE : "不考试"
}}
</td>
<template v-if="data.clazz.EXAMINATION === 1">
<td v-if="item.examnum > '0'">
{{
item.STAGEEXAMSCORE > -1 ? item.STAGEEXAMSCORE : "0分"
}}
</td>
<td v-else>
{{
item.STAGEEXAMSCORE > -1
? item.STAGEEXAMSCORE
: "未参加"
}}
</td>
</template>
</tr>
</template>
</table>
</td>
</tr>
</table>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {
getStudentSigns,
downloadStudentsumtable,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
});
const data = reactive({
info: {},
clazz: {},
passStudent: [],
unPassStudent: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getStudentSigns({
CORPINFO_ID: props.corpInfoId,
CLASS_ID: props.clazzId,
});
data.passStudent = [];
data.unPassStudent = [];
data.info = resData.rpd;
data.clazz = resData.clazz;
if (resData.clazz.EXAMINATION !== 0) {
resData.studentList.forEach((item) => {
if (item.STAGEEXAMSTATE === "3" || item.STAGEEXAMSTATE === "0") {
data.passStudent.push(item);
} else {
data.unPassStudent.push(item);
}
});
} else {
resData.studentList.forEach((item) => {
if (item.STUDYSTATE === "3") {
data.passStudent.push(item);
} else {
data.unPassStudent.push(item);
}
});
}
};
function getGenderByIdNumber(idNumber) {
if (idNumber) {
let genderCode; //
if (idNumber.length === 18) {
// 1817
genderCode = idNumber.charAt(16);
} else if (idNumber.length === 15) {
// 1515
genderCode = idNumber.charAt(14);
}
if (genderCode && !isNaN(genderCode)) {
if (parseInt(genderCode) % 2 === 0) {
return "女";
}
return "男";
}
}
}
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadStudentsumtable({
CLASS_ID: props.clazzId,
CORPINFO_ID: props.corpInfoId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
watchEffect(() => {
if (props.type === 104) fnGetData();
});
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
table {
width: 100%;
border-collapse: collapse;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
text-align: center;
}
}
</style>

View File

@ -0,0 +1,427 @@
<template>
<el-dialog
:title="title"
:model-value="type === 100"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="data.dialogFormEdit = true"
>新增</el-button
>
<el-button type="primary" @click="fnExport"></el-button>
</div>
<el-divider content-position="left">
生产经营单位安全培训教材会审表
</el-divider>
<table>
<tr>
<th>教材名称</th>
<td colspan="3">{{ props.curriculumname }}</td>
<th>出版书号</th>
<td>
<el-input v-model="data.form.BOOK_NUM" style="width: 100%"></el-input>
</td>
</tr>
<tr>
<th>编写单位</th>
<td colspan="3">
<el-input
v-model="data.form.CORP_NAME"
style="width: 100%"
></el-input>
</td>
<th>编写时间</th>
<td>
<el-date-picker
v-model="data.form.CREATTIME"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</td>
</tr>
<tr>
<th>教材类型</th>
<td colspan="5">{{ props.industryAllName }}</td>
</tr>
<tr>
<th width="12%">会审地点</th>
<td width="15%">
<el-input
v-model="data.form.CORP_NAME"
style="width: 100%"
></el-input>
</td>
<th width="12%">主持人</th>
<td width="25%">
<el-input
v-model="data.form.REVIEW_PERSON"
style="width: 100%"
></el-input>
</td>
<th width="12%">会审时间</th>
<td width="24%">
<el-date-picker
v-model="data.form.REVIEW_TIME"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</td>
</tr>
<tr>
<th colspan="6">安全培训教材会审情况</th>
</tr>
<tr>
<td colspan="6" style="padding: 0">
<table>
<tr>
<td class="tc">审查人员</td>
<td class="tc">工作部门</td>
<td class="tc">职务/职称</td>
<td class="tc">审查意见</td>
<td class="tc">本人签字</td>
</tr>
<template v-for="(item, index) in data.reviewRecord" :key="index">
<tr style="height: 40px">
<td class="tc">{{ item.NAME }}</td>
<td class="tc">{{ item.DEPARTMENT_NAME }}</td>
<td class="tc">{{ item.DUTIES }}</td>
<td class="tc">{{ item.CHECK_OPINION }}</td>
<td class="tc">
<viewer v-if="item.SIGN_PICTURE">
<img
:src="FILE_URL + item.SIGN_PICTURE"
alt=""
width="100"
height="25"
/>
</viewer>
</td>
</tr>
</template>
</table>
</td>
</tr>
<tr style="height: 200px">
<th>会审意见</th>
<td colspan="5">此教材符合相关文件要求同意使用</td>
</tr>
</table>
<div class="footer">
<div>
单位盖章
<img :src="data.info.OFFICIAL_SEAL_PATH" />
</div>
<div>档案编号{{ data.info.CODE }}</div>
<div>
归档日期{{ dayjs(data.info.END_TIME).format("YYYY年MM月DD日") }}
</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
<el-dialog
v-if="data.dialogFormEdit"
v-model:visible="data.dialogFormEdit"
:append-to-body="true"
:title="data.dialogType === 'edit' ? '修改' : '新增'"
width="600px"
>
<el-form
ref="form"
:model="data.review.reviewform"
:rules="data.review.rules"
label-width="120px"
style="width: 500px"
>
<el-form-item label="审查人员" prop="REVIEW_USER">
<el-input
id="REVIEW_USER"
ref="REVIEW_USER"
v-model="reviewform.REVIEW_USER"
maxlength="255"
placeholder="这里输入审查人员..."
title="会审人员"
/>
</el-form-item>
<el-form-item label="工作部门" prop="DEPARTMENT">
<el-input
id="DEPARTMENT"
ref="DEPARTMENT"
v-model="data.review.reviewform.DEPARTMENT"
maxlength="255"
placeholder="这里输入工作部门..."
title="工作部门"
/>
</el-form-item>
<el-form-item label="职务/职称" prop="DUTIES">
<el-input
id="DUTIES"
ref="DUTIES"
v-model="data.review.reviewform.DUTIES"
maxlength="255"
placeholder="这里输入职务/职称..."
title="职务/职称"
/>
</el-form-item>
<el-form-item label="审查意见" prop="CHECK_OPINION">
<el-input
id="CHECK_OPINION"
ref="CHECK_OPINION"
v-model="data.review.reviewform.CHECK_OPINION"
maxlength="255"
placeholder="这里输入审查意见..."
title="审查意见"
/>
</el-form-item>
<el-form-item
v-show="data.review.reviewform.SIGN_PATH"
:span="24"
label="本人签字"
prop="SIGN_PATH"
>
<template #default="{}">
<img
:src="FILE_URL + data.review.reviewform.SIGN_PATH"
alt=""
width="300"
height="100"
/>
</template>
</el-form-item>
<el-form-item
v-show="!data.review.reviewform.SIGN_PATH"
:span="24"
label="本人签字"
prop="SIGN_PATH"
>
<el-select
v-model="data.review.reviewform.SIGNTYPE"
style="width: 100%"
>
<el-option
v-for="idx in options"
:key="idx.value"
:label="idx.label"
:value="idx.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="data.review.reviewform.SIGNTYPE === '0'"
prop="SIGN_PICTURE"
>
<vue-esign
ref="esign"
:width="500"
:height="300"
style="border: 1px dashed #2f0e0e"
>
<span>请在虚线内进行签名...</span>
</vue-esign>
</el-form-item>
<el-form-item v-if="data.review.reviewform.SIGNTYPE === '1'">
<el-upload
:on-preview="handlePreviewSignPicture"
:on-remove="handleRemoveSignPicture"
:on-change="handleChangeSignPicture"
:auto-upload="false"
:file-list="data.review.reviewform.SIGN_PICTURE_2"
:limit="1"
:class="{ hide: signPictureUpload }"
action="#"
accept=".png"
list-type="picture-card"
>
<i class="el-icon-plus" />
</el-upload>
<el-dialog v-model:visible="data.signPictureVisible" append-to-body>
<img :src="data.review.reviewform.SIGN_PATH" width="100%" alt="" />
</el-dialog>
</el-form-item>
</el-form>
<template #footer>
<el-button
v-if="data.review.reviewform.SIGNTYPE === '0'"
@click="
$refs.esign && $refs.esign.reset();
data.review.reviewform.SIGN_PATH = '';
"
>重签</el-button
>
<el-button @click="data.dialogFormEdit = false"> </el-button>
<el-button type="primary" @click="confirm"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import dayjs from "dayjs";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getClassGoEdit,
getReviewGoEdit,
getReviewRecord,
downloadHs,
} from "@/request/training_archive_management.js";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
industryAllName: {
type: String,
required: true,
},
curriculumname: {
type: String,
required: true,
},
curriculumId: {
type: String,
required: true,
},
});
const data = reactive({
info: {},
form: {},
reviewInfo: {},
reviewRecord: {},
ARCHIVES_REVIEW_ID: "",
dialogFormEdit: false,
signPictureVisible: false,
dialogType: "add",
review: {
reviewform: {},
rules: {
REVIEW_USER: [
{ required: true, message: "审查人员不能为空", trigger: "blur" },
],
DEPARTMENT: [
{ required: true, message: "工作部门不能为空", trigger: "blur" },
],
DUTIES: [
{ required: true, message: "职务/职称不能为空", trigger: "blur" },
],
CHECK_OPINION: [
{ required: true, message: "审查意见不能为空", trigger: "blur" },
],
},
},
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getClassGoEdit({
TYPE: props.type,
CLASS_ID: props.clazzId,
});
data.info = resData.pd;
//
const reviewInfo = await getReviewGoEdit({
CLASS_ID: props.clazzId,
CURRICULUM_ID: props.curriculumId,
});
data.reviewInfo = reviewInfo.pd;
if (reviewInfo.pd) {
if (reviewInfo.pd.ARCHIVES_REVIEW_ID) {
data.ARCHIVES_REVIEW_ID = reviewInfo.pd.ARCHIVES_REVIEW_ID;
if (reviewInfo.pd.CORP_NAME) {
data.info.CORP_NAME = reviewInfo.pd.CORP_NAME;
}
if (reviewInfo.pd.CREATTIME) {
data.info.CREATTIME = reviewInfo.pd.CREATTIME;
}
if (reviewInfo.pd.END_TIME) {
data.info.END_TIME = reviewInfo.pd.END_TIME;
}
}
//
const reviewRecord = await getReviewRecord({
ARCHIVES_REVIEW_ID: data.ARCHIVES_REVIEW_ID,
});
data.reviewRecord = reviewRecord.pd;
}
};
watchEffect(() => {
if (props.type === 100) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadHs({
CLASS_ID: props.clazzId,
CORPINFO_ID: props.corpInfoId,
CURRICULUM_ID: props.curriculumId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
line-height: 1.6;
}
th {
background: var(--el-fill-color-light);
border: 1px solid var(--el-border-color);
padding: 8px;
text-align: center;
}
}
.footer {
margin-top: 40px;
display: flex;
align-items: center;
justify-content: space-around;
div:first-child {
position: relative;
img {
width: 120px;
height: 120px;
position: absolute;
top: -41px;
left: -13px;
}
}
}
</style>

View File

@ -0,0 +1,195 @@
<template>
<el-dialog
:title="title"
:model-value="type === 102"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div>
<h2 class="tc">安全培训教育记录及签字表</h2>
<table class="mt">
<tr>
<td class="tc">日期</td>
<td class="tc">
{{ dayjs(data.clazz.START_TIME).format("YYYY年MM月DD日") }}
</td>
<td class="tc">培训地点</td>
<td class="tc">{{ data.clazz.CORP_NAME }}</td>
<td class="tc">人数</td>
<td class="tc">{{ data.students.length }}</td>
</tr>
<tr>
<td class="tc">培训内容</td>
<td class="tc" colspan="3">{{ data.clazz.NAME }}</td>
<td class="tc">学时</td>
<td class="tc">
{{ data.info.SUMCLASSHOUR === 0.0 ? 0 : data.info.SUMCLASSHOUR }}
</td>
</tr>
<tr>
<td class="tc">培训教师</td>
<td colspan="5">{{ data.info.TEACHERS }}</td>
</tr>
<tr>
<td colspan="6" class="tc">受培训人</td>
</tr>
<tr>
<td colspan="6" style="padding: 0">
<table>
<tr>
<td class="tc">姓名</td>
<td class="tc">部门</td>
<td class="tc">签字</td>
<td class="tc">姓名</td>
<td class="tc">部门</td>
<td class="tc">签字</td>
</tr>
<template v-for="(item, index) in data.students">
<tr v-if="index % 2 === 0" :key="index">
<td class="tc">{{ item.NAME }}</td>
<td class="tc">{{ item.DEPARTMENT_NAME }}</td>
<td class="tc">
<viewer v-if="item.SIGNATURE_PATH">
<img
:src="FILE_URL + item.SIGNATURE_PATH"
alt=""
width="80"
height="50"
/>
</viewer>
</td>
<td class="tc">
{{
data.students[index + 1]
? data.students[index + 1].NAME
: ""
}}
</td>
<td class="tc">
{{
data.students[index + 1]
? data.students[index + 1].DEPARTMENT_NAME
: ""
}}
</td>
<td class="tc">
<viewer
v-if="
data.students[index + 1] &&
data.students[index + 1].SIGNATURE_PATH
"
>
<img
:src="
FILE_URL + data.students[index + 1].SIGNATURE_PATH
"
alt=""
width="80"
height="50"
/>
</viewer>
</td>
</tr>
</template>
</table>
</td>
</tr>
</table>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import dayjs from "dayjs";
import {
getStudentSigns,
downloadSign,
} from "@/request/training_archive_management.js";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
});
const FILE_URL = import.meta.env.VITE_FILE_URL;
const data = reactive({
clazz: {},
checkList: [],
info: {},
students: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getStudentSigns({
STUDYTASK_ID: props.studyTaskId,
CORPINFO_ID: props.corpInfoId,
CLASS_ID: props.clazzId,
});
data.info = resData.rpd;
data.students = resData.studentList;
data.clazz = resData.clazz;
};
watchEffect(() => {
if (props.type === 102) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadSign({
CLASS_ID: props.clazzId,
CORPINFO_ID: props.corpInfoId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
line-height: 1.6;
}
}
</style>

View File

@ -0,0 +1,160 @@
<template>
<el-dialog
:title="title"
:model-value="type === 101"
width="1100px"
@close="fnClose"
>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ CORP_NAME }}培训计划</h3>
</div>
<p class="mb">单位名称:{{ CORP_INFO }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="50" />
<el-table-column label="培训人员类型"> 从业人员 </el-table-column>
<el-table-column prop="POST_NAME" label="岗位(工种)" />
<el-table-column prop="TRAINERS_NUMBER" label="培训人数" width="80" />
<el-table-column label="培训时间" width="170">
<template #default="{ row }">
<span v-if="row.START_TIME !== row.END_TIME"
>{{ dayjs(row.START_TIME).format("YYYY-MM-DD") }}{{
dayjs(row.END_TIME).format("YYYY-MM-DD")
}}</span
>
<span v-else>{{ dayjs(row.START_TIME).format("YYYY-MM-DD") }}</span>
</template>
</el-table-column>
<el-table-column label="培训地点(方式)"> 线上培训 </el-table-column>
<el-table-column prop="TRAINING_MATERIALS" label="教学内容" />
<el-table-column prop="CLASS_HOURS" label="课时" width="80" />
<el-table-column prop="TRAINING_TEACHERS" label="授课教师" />
</layout-table>
<div class="flex mt">
<div>编制单位:{{ CORP_NAME }}</div>
<div>编制日期:</div>
</div>
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
<el-dialog
:model-value="data.delayDialog.visible"
title="设置"
width="500px"
append-to-body
>
<el-form
ref="delayDialogForm"
:model="data.delayDialog.form"
:rules="data.delayDialog.rules"
label-width="80px"
>
<el-form-item label="编制日期" prop="TIME">
<el-date-picker
v-model="data.delayDialog.form.TIME"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="submit"> </el-button>
<el-button @click="data.delayDialog.visible = false"> </el-button>
</template>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import {
getTrainingSchedule,
downloadTrainingPlan,
} from "@/request/training_archive_management.js";
import dayjs from "dayjs";
const props = defineProps({
type: {
type: Number,
required: true,
},
title: {
type: String,
required: true,
},
clazzId: {
type: String,
required: true,
},
postId: {
type: String,
required: true,
},
corpInfoId: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
postName: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
delayDialog: {
visible: false,
form: {
TIME: "",
},
rules: {
TIME: [{ required: true, message: "请选择日期", trigger: "blur" }],
},
},
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getTrainingSchedule({
TYPE: props.type,
CLASS_ID: props.clazzId,
});
data.list = resData.pd;
};
watchEffect(() => {
if (props.type === 101) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("导出前,请设置培训计划表中的编制日期", {
type: "warning",
});
data.delayDialog.visible = true;
};
const submit = async () => {
data.delayDialog.visible = false;
await downloadTrainingPlan({
CLASS_ID: props.clazzId,
UPDATE_DATE: data.delayDialog.form.TIME,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
const fnClose = () => {
emits("update:type", 0);
};
</script>
<style scoped lang="scss">
.flex {
width: 80%;
display: flex;
justify-content: space-between;
}
</style>

View File

@ -0,0 +1,111 @@
<template>
<div>
<el-card>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<layout-table
ref="tableRef"
v-model:pagination="data.pagination"
row-key="CURRICULUM_ID"
:data="data.varlist"
@get-data="fnGetData"
>
<el-table-column reserve-selection type="selection" width="55" />
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(data.pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="CURRICULUMNAME" label="教材名称" />
<el-table-column prop="VIDEOCOURSEWARE_COUNT" label="课件数" />
<el-table-column prop="ALL_POST_NAME" label="涉及岗位" />
<el-table-column label="操作" width="80">
<template #default="{ row }">
<el-button type="primary" text link @click="fnView(row)">
详情
</el-button>
</template>
</el-table-column>
</layout-table>
<handout
v-model:type="data.type"
zz
title="安全培训教材或课程讲义"
:clazz-id="CLASS_ID"
:curriculum-id="data.CURRICULUM_ID"
/>
</el-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import Handout from "./components/handout.vue";
import { reactive, ref } from "vue";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getClassCurriculumList,
downloadTeachingMaterialAll,
} from "@/request/training_archive_management.js";
const route = useRoute();
const { CLASS_ID } = route.query;
const tableRef = ref(null);
const data = reactive({
varlist: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0,
},
type: 0,
CURRICULUM_ID: "",
});
const fnView = (row) => {
data.type = 106;
data.CURRICULUM_ID = row.CURRICULUM_ID;
};
const fnGetData = async () => {
const resData = await getClassCurriculumList({
currentPage: data.pagination.currentPage,
pageSize: data.pagination.pageSize,
CLASS_ID,
});
data.varlist = resData.varList;
data.pagination.total = resData.page.totalResult;
};
fnGetData();
const fnExport = debounce(
1000,
async () => {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选中要导出的项");
return;
}
const archiveDirectory = [];
for (let i = 0; i < selectionData.length; i++) {
const info = {};
info.CURRICULUM_ID = selectionData[i].CURRICULUM_ID;
info.CURRICULUMNAME = selectionData[i].CURRICULUMNAME;
archiveDirectory.push(info);
}
await downloadTeachingMaterialAll({
CLASS_ID,
typeList: JSON.stringify(archiveDirectory),
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
tableRef.value.clearSelection();
},
{ atBegin: true }
);
</script>
<style scoped></style>

View File

@ -0,0 +1,115 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="班级名称" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入班级名称"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="状态" prop="STATUS">
<el-select v-model="searchForm.STATUS">
<el-option
v-for="item in data.statusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="NAME" label="班级名称" width="250" />
<el-table-column prop="START_TIME" label="培训开始时间" width="200" />
<el-table-column prop="END_TIME" label="培训结束时间" width="200" />
<el-table-column prop="STUDENT_NUM" label="学员人员数" width="200" />
<el-table-column prop="STATE" label="班级状态" width="200">
<template #default="{ row }">
<template v-if="row.STATE === '1'"> </template>
<template v-if="row.STATE === '4'"> </template>
<template v-if="row.STATE === '5'"> </template>
<template v-if="row.STATE === '6'"> </template>
</template>
</el-table-column>
<el-table-column prop="POST_NUM" label="涉及工种数" width="200" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/archives_management/semester/archives',
query: {
CLASS_ID: row.CLASS_ID,
CORP_NAME: row.CORP_NAME,
CLASS_NAME: row.NAME,
CORPINFO_ID: row.CORPINFO_ID,
},
})
"
>
档案目录
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { reactive, ref } from "vue";
import { getClassesList } from "@/request/training_archive_management.js";
import router from "@/router/index.js";
const tableRef = ref(null);
const data = reactive({
statusList: [
{ value: 1, label: "未申请" },
{ value: 4, label: "待开班" },
{ value: 5, label: "培训中" },
{ value: 6, label: "培训结束" },
],
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassesList);
</script>
<style scoped></style>

View File

@ -0,0 +1,151 @@
<template>
<div>
<el-card>
<el-form
:model="data.searchForm"
label-width="80px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="试卷名称" prop="KEYWORDS">
<el-input v-model="data.searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
<el-button
v-if="data.varlist.length > 0"
type="primary"
@click="fnExport"
>导出</el-button
>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table
ref="tableRef"
v-model:pagination="data.pagination"
row-key="STAGEEXAMPAPERINPUT_ID"
:data="data.varlist"
@get-data="fnGetData"
>
<el-table-column reserve-selection type="selection" width="55" />
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(data.pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="EXAMNAME" label="试卷名称" />
<el-table-column prop="ALL_POST_NAME" label="涉及岗位" />
<el-table-column prop="STUDENT_SUM" label="人数" />
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnView(row.STAGEEXAMPAPERINPUT_ID)"
>
试卷详情
</el-button>
</template>
</el-table-column>
</layout-table>
<paper
v-model:type="data.type"
title="培训考核试卷"
:clazz-id="CLASS_ID"
:stageexampaperinput-id="data.STAGEEXAMPAPERINPUT_ID"
/>
</el-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import Paper from "./components/paper.vue";
import { reactive, ref } from "vue";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getClassPaperList,
downloadArchivePapers,
} from "@/request/training_archive_management.js";
const route = useRoute();
const { CLASS_ID, CLASS_NAME } = route.query;
const tableRef = ref(null);
const data = reactive({
varlist: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0,
},
searchForm: {},
type: 0,
STAGEEXAMPAPERINPUT_ID: "",
});
const fnView = (STAGEEXAMPAPERINPUT_ID) => {
data.type = 103;
data.STAGEEXAMPAPERINPUT_ID = STAGEEXAMPAPERINPUT_ID;
};
const fnGetData = async () => {
const resData = await getClassPaperList({
currentPage: data.pagination.currentPage,
pageSize: data.pagination.pageSize,
CLASS_ID,
...data.searchForm,
});
data.varlist = resData.varList;
data.pagination.total = resData.page.totalResult;
};
fnGetData();
const fnResetPagination = () => {
data.pagination = {
currentPage: 1,
pageSize: 10,
total: 0,
};
tableRef.value.clearSelection();
fnGetData();
};
const fnExport = debounce(
1000,
async () => {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选中要导出的项");
return;
}
const paperList = [];
for (let i = 0; i < selectionData.length; i++) {
const info = {};
info.CLASS_ID = selectionData[i].CLASS_ID;
info.CLASS_NAME = CLASS_NAME;
info.EXAMNAME = selectionData[i].EXAMNAME;
info.STAGEEXAMPAPERINPUT_ID = selectionData[i].STAGEEXAMPAPERINPUT_ID;
paperList.push(info);
}
await downloadArchivePapers({
paperList: JSON.stringify(paperList),
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
tableRef.value.clearSelection();
},
{ atBegin: true }
);
</script>
<style scoped></style>

View File

@ -0,0 +1,111 @@
<template>
<div>
<el-card>
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
row-key="CLASS_ID"
:data="list"
@get-data="fnGetData"
>
<el-table-column reserve-selection type="selection" width="55" />
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="CURRICULUMNAME" label="教材名称" />
<el-table-column prop="ALL_POST_NAME" label="涉及岗位" />
<el-table-column prop="INDUSTRY_ALL_NAME" label="教材类型" />
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button type="primary" text link @click="tiao(row)"
>编辑</el-button
>
</template>
</el-table-column>
</layout-table>
<component
:is="data.component"
v-if="data.component"
v-model:type="data.type"
:title="data.title"
:clazz-id="CLASS_ID"
:corp-info-id="CORPINFO_ID"
:corp-name="CORP_NAME"
:post-name="POST_NAME"
:industry-all-name="data.INDUSTRY_ALL_NAME"
:curriculumname="data.CURRICULUMNAME"
:curriculum-id="data.CURRICULUM_ID"
/>
</el-card>
</div>
</template>
<script setup>
import {
downloadHsAll,
getClassCurriculumList,
} from "@/request/training_archive_management";
import Review from "./components/review.vue";
import { markRaw, reactive, ref } from "vue";
import { serialNumber } from "@/assets/js/utils";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import useListData from "@/assets/js/useListData.js";
const route = useRoute();
const tableRef = ref(null);
const { CLASS_ID, CORP_NAME, CORPINFO_ID, POST_NAME } = route.query;
const data = reactive({
fold: false,
type: 100,
title: "",
component: "",
INDUSTRY_ALL_NAME: "",
CURRICULUMNAME: "",
CURRICULUM_ID: "",
});
const { list, pagination, fnGetData } = useListData(getClassCurriculumList, {
otherParams: { CLASS_ID },
});
const tiao = (row) => {
data.type = 100;
data.NAME = "安全培训教材会审表";
data.component = markRaw(Review);
data.CURRICULUM_ID = row.CURRICULUM_ID;
data.CURRICULUMNAME = row.CURRICULUMNAME;
data.INDUSTRY_ALL_NAME = row.INDUSTRY_ALL_NAME;
};
const fnExport = async () => {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选中要导出的项");
return;
}
const typeList = [];
for (let i = 0; i < selectionData.length; i++) {
const info = {};
info.CURRICULUM_ID = selectionData[i].CURRICULUM_ID;
info.CURRICULUMNAME = selectionData[i].CURRICULUMNAME;
typeList.push(info);
}
await downloadHsAll({
CLASS_ID,
CORPINFO_ID,
typeList: JSON.stringify(typeList),
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
</script>
<style scoped></style>

View File

@ -0,0 +1,106 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="班级编码" prop="CODE">
<el-input
v-model="searchForm.CODE"
placeholder="请输入班级编码"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="班级名称" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入班级名称"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="NAME" label="班级名称" width="200" />
<el-table-column prop="CODE" label="班级编码" width="150" />
<el-table-column
prop="TRAININGTYPE_NAME"
label="培训类型"
width="200"
/>
<el-table-column prop="POSTTYPE_NAME" label="岗位类型" width="150" />
<el-table-column prop="START_TIME" label="培训开始时间" width="150" />
<el-table-column prop="END_TIME" label="培训结束时间" width="150" />
<el-table-column prop="STUDENT_NUM" label="学员人员数" width="150" />
<el-table-column prop="START_TIME" label="任务状态" width="150">
<template #default="{ row }">
<template v-if="row.STATE === '1'"> </template>
<template v-if="row.STATE === '4'"> </template>
<template v-if="row.STATE === '5'"> </template>
<template v-if="row.STATE === '6'"> </template>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/archives_management/student/index/studentList',
query: {
CLASS_ID: row.CLASS_ID,
},
})
"
>
学员列表
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { ref } from "vue";
import { getClassForHealthList } from "@/request/training_archive_management.js";
import router from "@/router/index.js";
const tableRef = ref(null);
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassForHealthList);
</script>
<style scoped></style>

View File

@ -0,0 +1,102 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="姓名" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入姓名"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="NAME" label="姓名" width="200" />
<el-table-column prop="DEPARTMENT_NAME" label="部门" width="200" />
<el-table-column prop="POST_NAME" label="工种" width="200" />
<el-table-column prop="USER_ID_CARD" label="身份证号" width="200" />
<el-table-column prop="FILE_NUMBER" label="档案编号" width="200" />
<el-table-column prop="AUTHENTICATION" label="人脸认证" width="200">
<template #default="{ row }">
{{ row.AUTHENTICATION === "0" ? "未认证" : "已认证" }}
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button
v-if="
row.STATE === '6' ||
(row.EXAMINATION === 1 && parseInt(row.EXAMSCORE) > -1) ||
(row.EXAMINATION === 0 && parseInt(row.STUDYSTATE) > 1)
"
type="text"
@click="fnDownLoadArchive(row)"
>学员档案下载</el-button
>
<el-button v-else type="text" disabled>学员档案下载</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { ref } from "vue";
import { useRoute } from "vue-router";
import {
downLoadStudentArchive,
getClassForHealthStudentList,
} from "@/request/training_archive_management.js";
import { ElMessageBox } from "element-plus";
const route = useRoute();
const tableRef = ref(null);
const { CLASS_ID } = route.query;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassForHealthStudentList, {
otherParams: { CLASS_ID },
});
const fnDownLoadArchive = async (item) => {
await downLoadStudentArchive({
STUDENT_ID: item.STUDENT_ID,
STUDENT_NAME: item.NAME,
CORPINFO_ID: item.CORPINFO_ID,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
</script>
<style scoped></style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,216 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="8">
<el-form-item label="班级名称" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入班级名称"
/>
</el-form-item>
</el-col>
<el-col v-show="!data.searchFromCollapse" :span="8">
<el-form-item label="开始时间" prop="STARTTIME">
<el-date-picker
v-model="searchForm.STARTTIME"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col v-show="!data.searchFromCollapse" :span="8">
<el-form-item label="结束时间" prop="ENDTIME">
<el-date-picker
v-model="searchForm.ENDTIME"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col v-show="!data.searchFromCollapse" :span="8">
<el-form-item label="状态" prop="STATUS">
<el-select v-model="searchForm.STATUS">
<el-option
v-for="item in data.statusList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
<el-button type="primary" @click="derivedRecord"></el-button>
<el-button
v-if="data.searchFromCollapse"
type="text"
@click="data.searchFromCollapse = false"
>展开 <i class="el-icon-arrow-down"
/></el-button>
<el-button
v-else
type="text"
@click="data.searchFromCollapse = true"
>合并 <i class="el-icon-arrow-up"
/></el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="NAME" label="班级名称" />
<el-table-column prop="DEPARTMENT_NAME" label="部门" />
<el-table-column prop="POST_NAME" label="工种" />
<el-table-column prop="STATE" label="班级状态">
<template #default="{ row }">
<template v-if="row.STATE === '1'"> </template>
<template v-if="row.STATE === '4'"> </template>
<template v-if="row.STATE === '5'"> </template>
<template v-if="row.STATE === '6'"> </template>
</template>
</el-table-column>
<el-table-column prop="TRAININGTYPE_NAME" label="培训类型" />
<el-table-column prop="POSTTYPE_NAME" label="岗位类型" />
<el-table-column prop="TRAINLEVEL_NAME" label="培训级别" />
<el-table-column prop="SUM_CLASSHOUR" label="任务学时" />
<el-table-column prop="COMPLETE_CLASSHOUR" label="已学学时" />
<el-table-column prop="COMPLETE_CLASSHOUR" label="考试结果">
<template #default="{ row }">
<template v-if="row.STAGEEXAMSTATE === '0'"> </template>
<template v-else-if="row.STAGEEXAMSTATE === '1'"> 待考试 </template>
<template v-else-if="row.STAGEEXAMSTATE === '2'">
考试未通过
</template>
<template v-else-if="row.STAGEEXAMSTATE === '3'">
考试通过
</template>
<template v-else-if="row.STAGEEXAMSTATE === '4'"> 未参加 </template>
</template>
</el-table-column>
<el-table-column prop="START_TIME" label="开始时间" />
<el-table-column prop="END_TIME" label="结束时间" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnPersonnelRegistrationForm(row.STUDENT_ID, row.USER_ID)"
>
人员登记表
</el-button>
<el-button
v-if="
row.STATE === '6' ||
(row.EXAMINATION === 1 &&
parseInt(row.STAGEEXAMSCORE) > -1 &&
parseInt(row.STUDYSTATE) !== 5) ||
(row.EXAMINATION === 0 && parseInt(row.STUDYSTATE) > 1)
"
type="primary"
text
link
@click="
router.push({
path: '/archives_management/user/class/archives',
query: {
CLASS_ID: row.CLASS_ID,
CLASS_NAME: row.NAME,
STUDENT_ID: row.STUDENT_ID,
STUDENT_NAME: row.STUDENT_NAME,
CORP_NAME: row.CORP_NAME,
RECORDOR_SIGN: row.RECORDOR_SIGN,
ASSESSOR_SIGN: row.ASSESSOR_SIGN,
SAFETYDEPTOR_SIGN: row.SAFETYDEPTOR_SIGN,
POSTTYPE: row.POSTTYPE,
POSTTYPE_NAME: row.POSTTYPE_NAME,
INDUSTRY_ALL_NAME: row.INDUSTRY_ALL_NAME,
INDUSTRY_ALL_TYPE: row.INDUSTRY_ALL_TYPE,
TRAINLEVEL: row.TRAINLEVEL,
TRAINLEVEL_NAME: row.TRAINLEVEL_NAME,
PERSONNEL_TYPE: row.PERSONNEL_TYPE,
},
})
"
>
档案详情
</el-button>
<el-button v-else disabled type="primary" text link>
档案详情
</el-button>
</template>
</el-table-column>
</layout-table>
<personnel-registration-form
v-model:visible="data.personnelRegistrationFormDialog.visible"
:student-id="data.personnelRegistrationFormDialog.STUDENT_ID"
:user-id="data.personnelRegistrationFormDialog.USER_ID"
/>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { reactive, ref } from "vue";
import PersonnelRegistrationForm from "./components/personnel_registration_form.vue";
import { getUserClassesList } from "@/request/training_archive_management.js";
import { useRoute } from "vue-router";
import router from "@/router/index.js";
const route = useRoute();
const tableRef = ref(null);
const { USER_ID } = route.query;
const data = reactive({
searchFromCollapse: true,
statusList: [
{ value: 1, label: "未申请" },
{ value: 4, label: "待开班" },
{ value: 5, label: "培训中" },
{ value: 6, label: "培训结束" },
],
personnelRegistrationFormDialog: {
visible: false,
STUDENT_ID: "",
USER_ID: "",
},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getUserClassesList, {
otherParams: { USER_ID },
});
const fnPersonnelRegistrationForm = (STUDENT_ID, USER_ID) => {
data.personnelRegistrationFormDialog.STUDENT_ID = STUDENT_ID;
data.personnelRegistrationFormDialog.USER_ID = USER_ID;
data.personnelRegistrationFormDialog.visible = true;
};
</script>
<style scoped></style>

View File

@ -0,0 +1,219 @@
<template>
<el-dialog v-model="visible" title="人员登记表">
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<h2 class="tc">生产经营单位新入职从业人员登记表</h2>
<div class="flex mt mb">
<span>生产经营单位名称(盖章):{{ data.info.CORP_NAME }}</span>
<span>档案编号:{{ data.info.FILE_NUMBER }}</span>
</div>
<table>
<tr>
<td width="20%">姓名</td>
<td width="20%">
{{ data.info.NAME }}
</td>
<td width="20%">性别</td>
<td width="20%">
{{ data.info.SEX_NAME }}
</td>
<td rowspan="4" width="120" class="tc" style="padding: 0">
<div>
<img
v-if="data.info.PORTRAIT"
:src="FILE_URL + data.info.PORTRAIT"
width="100"
height="100"
/>
</div>
</td>
</tr>
<tr>
<td>民族</td>
<td>
{{ data.info.NATION_NAME }}
</td>
<td>政治面貌</td>
<td>
{{ data.info.POLITICAL_OUTLOOK_NAME }}
</td>
</tr>
<tr>
<td>文化程度</td>
<td>
{{ data.info.DEGREE_OF_EDUCATION_NAME }}
</td>
<td>健康状况</td>
<td>
{{ data.info.HEALTH }}
</td>
</tr>
<tr>
<td>出生年月</td>
<td>
{{ data.info.DATE_OF_BIRTH }}
</td>
<td>身份证号</td>
<td>
{{ data.info.USER_ID_CARD }}
</td>
</tr>
<tr>
<td>毕业院校及专业</td>
<td>
{{ data.info.UNIVERSITY }}
</td>
<td>职务/职称</td>
<td colspan="2">
{{ data.info.DUTIES_NAME }}
</td>
</tr>
<tr>
<td>户籍所在地</td>
<td>
{{ data.info.RESIDENCE }}
</td>
<td>参加工作时间</td>
<td colspan="2">
{{ data.info.WORKING_DATE }}
</td>
</tr>
<tr>
<td>进入本单位时间</td>
<td>
{{ data.info.ENTRY_DATE }}
</td>
<td>入职部门</td>
<td colspan="2">
{{ data.info.DEPARTMENT_NAME }}
</td>
</tr>
<tr>
<td>岗位名称</td>
<td>
{{ data.info.POST_NAME }}
</td>
<td>之前从事本岗位时间</td>
<td colspan="2">
{{ data.info.PREVIOUS_POST_DATE }}
</td>
</tr>
<tr style="height: 100px">
<td>主要工作经历</td>
<td colspan="4">
{{ data.info.WORK_EXPERIENCE }}
</td>
</tr>
<tr style="height: 100px">
<td>入职前接受安全培训和考核以及取得安全培训有关的岗位证书等情况</td>
<td colspan="4">
{{ data.info.CERTIFICATES }}
</td>
</tr>
<tr style="height: 100px">
<td>入职前受过何种有关安全生产的处罚以及是否受到刑事处罚</td>
<td colspan="4">
{{ data.info.PUNISH }}
</td>
</tr>
<tr>
<td>入职统计表相关信息核定情况</td>
<td colspan="4">
<p>
入职人承诺:以上信息已经本人核实信息真实有效完整如有虚假或欺骗等行为自愿承担相应的法律责任.
</p>
<div class="flex mt" style="padding: 0">
<p>入职人(签字并按指纹)</p>
<p>
承诺日期<span>&emsp;&emsp;</span><span>&emsp;</span
><span>&emsp;</span>
</p>
</div>
<p class="mt">生产经营单位核查意见</p>
<div class="flex mt" style="padding: 0">
<p>核查人员(签字)</p>
<p>
核查日期<span>&emsp;&emsp;</span><span>&emsp;</span
><span>&emsp;</span>
</p>
</div>
</td>
</tr>
</table>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { ElMessageBox } from "element-plus";
import { reactive, watchEffect } from "vue";
import {
getArchivesStudentEdit,
downloadRegisterform,
} from "@/request/training_archive_management.js";
const props = defineProps({
visible: {
type: Boolean,
request: true,
},
studentId: {
type: String,
request: true,
},
userId: {
type: String,
request: true,
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
const FILE_URL = import.meta.env.VITE_FILE_URL;
const data = reactive({
info: {},
});
const fnGetData = async () => {
const response = await getArchivesStudentEdit({
STUDENT_ID: props.studentId,
USER_ID: props.userId,
});
data.info = response.pd;
};
watchEffect(() => {
if (visible.value) fnGetData();
});
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadRegisterform({
STUDENT_ID: props.studentId,
STUDENT_NAME: data.info.NAME,
USER_ID: props.userId,
});
await ElMessageBox.confirm("导出后请前往档案下载中下载该档案!", "温馨提示", {
type: "info",
});
};
</script>
<style scoped lang="scss">
.flex {
display: flex;
align-items: center;
justify-content: space-between;
}
table {
border-collapse: collapse;
width: 100%;
td {
border: 1px solid var(--el-border-color);
padding: 8px;
font-size: 14px;
line-height: 1.6;
}
}
</style>

View File

@ -0,0 +1,94 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="姓名" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入姓名"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="USERNAME" label="用户名" width="200" />
<el-table-column prop="NAME" label="姓名" width="200" />
<el-table-column prop="CLASS_COUNT" label="班级数" width="200" />
<el-table-column prop="COMPLETE_COUNT" label="完成班级数" width="200" />
<el-table-column prop="CLIENT" label="是否补充" width="200">
<template #default="{ row }">
<template
v-if="
row.ARCHIVES_AWARD_PUN_LOG_ID || row.ARCHIVES_SPECIAL_WORK_ID
"
></template
>
<template v-else></template>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/archives_management/user/class',
query: {
USER_ID: row.USER_ID,
},
})
"
>
班级详情
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { ref } from "vue";
import { getStudentsList } from "@/request/training_archive_management.js";
import router from "@/router/index.js";
const tableRef = ref(null);
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getStudentsList);
</script>
<style scoped></style>

View File

@ -423,6 +423,7 @@ import { ElMessageBox, ElMessage } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getVerifyDeduplicationUser,
getVerifyDeduplicationUserIdCard,
getVerifyDuplicateEmail,
setUploadImg,
} from "@/request/api.js";
@ -458,6 +459,18 @@ const fnHasUser = async (rule, value, callback) => {
callback();
}
};
const fnHasUserIdCard = async (rule, value, callback) => {
if (value) {
const resData = await getVerifyDeduplicationUserIdCard({
USER_ID_CARD: value,
VERIFYUSER_ID: data.form.USER_ID,
});
if (resData?.pd?.USER_ID) callback(new Error("身份证号重复"));
else callback();
} else {
callback();
}
};
const rules = {
NAME: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
USERNAME: [
@ -527,6 +540,7 @@ const rules = {
message: "请输入正确的身份证号",
trigger: "blur",
},
{ validator: fnHasUserIdCard, trigger: "blur" },
],
SHIFTDUTYONE: [{ required: true, message: "请选择排班", trigger: "change" }],
SHIFTDUTYTWO: [{ required: true, message: "请选择排班", trigger: "change" }],

View File

@ -249,7 +249,7 @@ import { useVModels } from "@vueuse/core";
import useListData from "@/assets/js/useListData.js";
import {
getPreviewingVideo,
getSelectCourseManagementList,
getVideoCoursewareList,
} from "@/request/training_resource_management.js";
import { serialNumber } from "@/assets/js/utils.js";
import { nextTick, reactive, watch } from "vue";
@ -289,13 +289,7 @@ const props = defineProps({
const emits = defineEmits(["update:visible", "confirm"]);
const { visible } = useVModels(props, emits);
const { list, searchForm, pagination, fnGetData, tableRef, fnResetPagination } =
useListData(getSelectCourseManagementList, {
otherParams: {
CANUSE: "1",
STATE: "0",
ISCOMPLETE: "1",
},
});
useListData(getVideoCoursewareList);
let currentValue = {};
const data = reactive({
radioValue: "",