Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	src/views/enterprise_management/department/components/add.vue
dev
WenShiJun 2024-03-20 16:58:48 +08:00
commit 02a0c7fcae
52 changed files with 7791 additions and 3208 deletions

5466
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@
"axios": "^1.6.3",
"dayjs": "^1.11.10",
"echarts": "^5.4.3",
"element-plus": "^2.4.4",
"element-plus": "^2.6.1",
"html2canvas": "^1.4.1",
"jspdf": "^2.5.1",
"lodash-es": "^4.17.21",
@ -46,7 +46,8 @@
"vue3-pdfjs": "^0.1.6",
"vue3-print-nb": "^0.1.4",
"vue3-puzzle-vcode": "^1.1.5",
"vue3-seamless-scroll": "^2.0.1"
"vue3-seamless-scroll": "^2.0.1",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@our-patches/postcss-px-to-viewport": "^1.2.0",

View File

@ -298,6 +298,7 @@
.el-dialog {
background: transparent !important;
--el-dialog-margin-top: 50px !important;
padding: 0 !important;
.el-dialog__header {
background-image: url("/src/assets/images/public/tctitlebg.png");
@ -321,8 +322,14 @@
}
}
.el-dialog__body, .el-dialog__footer {
.el-dialog__body {
background-color: var(--el-bullet-frame-bg-color);
padding: calc(var(--el-dialog-padding-primary) + 10px) var(--el-dialog-padding-primary);
}
.el-dialog__footer {
background-color: var(--el-bullet-frame-bg-color);
padding: var(--el-dialog-padding-primary);
}
}
@ -418,3 +425,7 @@
.el-color-predefine__color-selector.selected {
--el-color-primary: #fff !important;
}
.el-input-number.is-disabled .el-input-number__decrease, .el-input-number.is-disabled .el-input-number__increase{
border-color: var(--el-border-color) !important;
}

View File

@ -224,12 +224,12 @@ export const layoutFnGetInsuranceCompany = async () => {
// 培训类型
export const layoutFnGetTrainingType = async (params) => {
const resData = await getTrainingType(params);
return ref(resData.trainingtypelist);
return ref(resData.varList);
};
// 行业类型
export const layoutFnGetIndustryType = async (params) => {
const resData = await getIndustryType(params);
return ref(JSON.parse(resData.zTreeNodes));
return ref(resData.zTreeNodes);
};
// 岗位类型
export const layoutFnGetPostType = async (params) => {
@ -241,3 +241,10 @@ export const layoutFnGetTrainingLevel = async (params) => {
const resData = await getTrainingLevel(params);
return ref(resData.varList);
};
// 试题标签
export const layoutFnGetTestQuestionLabels = async () => {
const resData = await getLevels({
DICTIONARIES_ID: "a60ebc858e2c46108bf82bbd8acc8f50",
});
return ref(resData.list);
};

View File

@ -103,11 +103,11 @@
<el-radio-group v-model="form.RECTIFICATIONTYPE">
<el-radio
:disabled="form.HIDDENLEVEL === 'hiddenLevel0002'"
label="1"
value="1"
>
立即整改
</el-radio>
<el-radio label="2">限期整改</el-radio>
<el-radio value="2">限期整改</el-radio>
</el-radio-group>
</el-form-item>
</el-col>

File diff suppressed because it is too large Load Diff

View File

@ -133,7 +133,7 @@ export const getStandardLevels = () =>
});
// 培训类型
export const getTrainingType = (params) =>
post("/trainingtype/privateList", {
post("/trainingtype/listAll", {
loading: false,
...params,
});

View File

@ -1,4 +1,4 @@
import { post } from "@/request/axios.js";
import { post, upload } from "@/request/axios.js";
export const getStudentsList = (params) =>
post("/archives/getStudentsList", params); // 一人一档用户列表
@ -24,6 +24,8 @@ export const getLearningRecord = (params) =>
export const getDict = (params) => post("/dictionaries/getLevels", params); // 获取人员类型
export const downloadFilesdetailword = (params) =>
post("/archives/filesdetailword", params); // 一人一档:档案详情导出
export const downloadAward = (params) =>
post("/archives/batchDownloadWord", params); // 一人一档:补充档案导出
export const getClassPapers = (params) =>
post("/archives/getClassPapers", params); // 一期一档:班级试卷列表
@ -70,12 +72,19 @@ 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 getPostmanView = (params) =>
post("/archivespostman/goEdit", params); // 一企一档:三岗人员管理台账查看
export const setPostmanDelete = (params) =>
post("/archivespostman/delete", params); // 一企一档:三岗人员管理台账删除
export const setPostmanAdd = (params) => upload("/archivespostman/add", params); // 一企一档:三岗人员管理台账添加
export const setPostmanEdit = (params) =>
upload("/archivespostman/edit", params); // 一企一档:三岗人员管理台账修改
export const setPostmanImport = (params) =>
upload("/archivespostman/readExcel", params); // 一企一档:三岗人员管理台账导入
export const getArchivesTeacherList = (params) =>
post("/archivesteacher/list", params); // 一企一档:年度本单位师资管理台账
export const getArchivesPlanList = (params) =>
@ -84,6 +93,18 @@ export const getArchivesManagerList = (params) =>
post("/archivesedumanager/list", params); // 一企一档:年度安全培训教育管理台账
export const getArchivesCapitalList = (params) =>
post("/archivescapital/list", params); // 一企一档:年度培训资金提取和使用情况管理台账
export const setCapitalDelete = (params) =>
post("/archivescapital/delete", params); // 一企一档:年度培训资金提取和使用情况管理台账删除
export const getCapitalView = (params) =>
post("/archivescapital/goEdit", params); // 一企一档:年度培训资金提取和使用情况管理台账查看
export const setCapitalAdd = (params) => post("/archivescapital/add", params); // 一企一档:年度培训资金提取和使用情况管理台账添加
export const setCapitalEdit = (params) => post("/archivescapital/edit", params); // 一企一档:年度培训资金提取和使用情况管理台账修改
export const setArchivesFilesUpload = (params) =>
upload("/archivesfiles/add", params); // 一企一档上传pdf文件
export const getArchivesFilesList = (params) =>
post("/archivesfiles/listAll", params); // 一企一档:获取附件
export const setArchivesFilesDelete = (params) =>
post("/archivesfiles/delete", params); // 一企一档:删除附件
export const downloadFundmanageword = (params) =>
post("/archivescapital/fundmanageword", params); // 一企一档:年度培训资金提取和使用情况管理台账导出
export const downloadTrainingplanword = (params) =>
@ -96,3 +117,12 @@ export const downloadTeacherword = (params) =>
export const getPdffileList = (params) => post("/archivespdffile/list", params); // 档案下载重新下载
export const redownLoad = (params) =>
post("/archivespdffile/redownload", params); // 档案下载重新下载
export const getClassStrengthenDetailsList = (params) =>
post("/class/strengthenlist", params); // 效果评估:班级列表
export const getStudentStrengthenDetailsList = (params) =>
post("/class/strengthenstudentlist", params); // 效果评估:学员列表
export const getClassEvaluation = (params) =>
post("/class/getEvaluation", params); // 获取班级效果评估表信息
export const getStudentEvaluation = (params) =>
post("/student/getEvaluation", params); // 获取个人效果评估表信息
export const downloadClassEvaluation = (params) => post("class/hs", params); // 导出班级效果评估表信息

View File

@ -1,4 +1,48 @@
import { post } from "@/request/axios.js";
import { post, upload } from "@/request/axios.js";
export const setExamPaperManagementDelete = (params) =>
post("/stageexampaperinput/delete", params); // 试卷管理删除
export const setExamPaperManagementAdd = (params) =>
upload("/stageexampaperinput/add", params); // 试卷管理添加
export const setExamPaperManagementEdit = (params) =>
upload("/stageexampaperinput/edit", params); // 试卷管理修改
export const setExamPaperManagementInherit = (params) =>
post("/stageexampaperinput/inherit", params); // 试卷管理继承
export const setExamPaperManagementAddToDraft = (params) =>
upload("/stageexampaperCache/add", params); // 试卷管理保存到草稿
export const setExamPaperManagementTestQuestionsDelete = (params) =>
post("/paperQuestion/delete", params); // 试卷管理试题删除
export const setExamPaperManagementTestQuestionsAdd = (params) =>
post("/paperQuestion/add", params); // 试卷管理试题新增
export const setExamPaperManagementTestQuestionsEdit = (params) =>
post("/paperQuestion/edit", params); // 试卷管理试题修改
export const getAssociatedCoursewareNameList = (params) =>
post("/videocourseware/getCourseWareName", params); // 关联课件名称
export const getClassManagementList = (params) => post("/class/list", params); // 班级管理列表
export const setClassManagementDelete = (params) =>
post("/class/delete", params); // 班级管理删除
export const setClassManagementDelay = (params) =>
post("/class/postpone", params); // 班级管理延期
export const getPersonnelList = (params) =>
post("/trainedusersign/listByEnt", { loading: false, params }); // 班级管理添加人员
export const getClassManagementView = (params) => post("/class/goEdit", params); // 班级管理查看
export const setClassManagementAdd = (params) => post("/class/add", params); // 班级管理添加
export const setClassManagementEdit = (params) => post("/class/edit", params); // 班级管理修改
export const setClassManagementModifyExamTimes = (params) =>
post("/class/editNumberofexams", params); // 班级管理修改考试次数
export const getClassManagementStudentList = (params) =>
post("/student/classStudentList", params); // 班级管理学员列表
export const getClassManagementExportLearningRecords = (params) =>
post("/student/exportStudentList", params); // 班级管理导出学员学习记录
export const setClassManagementStudentDelete = (params) =>
post("/student/deleteStudent", params); // 班级管理学员删除
export const getClassManagementSelectStudentList = (params) =>
post("/user/studentList", params); // 班级管理新增学员列表
export const getClassManagementSelectStudentAdd = (params) =>
post("/student/add", params); // 班级管理新增学员保存
export const getClassManagementStudentLearningRecordsList = (params) =>
post("/coursestudyvideorecord/getAllByuserInfo", params); // 班级管理学员学习记录列表
export const getClassManagementStudentExamRecordsList = (params) =>
post("/stageexam/list", params); // 班级管理学员考试记录列表
export const getClassManagementStudentExamRecordsView = (params) =>
post("/stageexam/findExam", params); // 班级管理学员考试记录查看

View File

@ -34,6 +34,7 @@
v-if="data.component"
v-model:type="data.type"
:title="data.title"
:corp-name="data.corp_name"
:year="data.YEAR"
/>
</el-card>
@ -53,6 +54,7 @@ import Eduplan from "./components/eduplan";
import Edumanager from "./components/edumanager";
import Capital from "./components/capital";
import { downloadAllwordzip } from "@/request/training_archive_management.js";
import { getEnterpriseInfo } from "@/request/enterprise_management.js";
const data = reactive({
list: [
@ -81,8 +83,14 @@ const data = reactive({
YEAR: dayjs().format("YYYY"),
component: "",
type: "",
corp_name: "",
title: "",
});
const fnGetData = async () => {
const resData = await getEnterpriseInfo();
data.corp_name = resData.pd.CORP_NAME;
};
fnGetData();
const fnExport = debounce(
1000,
async () => {

View File

@ -6,13 +6,22 @@
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="list.push({})"></el-button>
<el-button type="danger" @click="fnDelete"></el-button>
<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">
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table
:data="list"
:show-pagination="false"
:stripe="false"
:highlight-current-row="true"
@row-click="fnRowClick"
@row-dblclick="fnRowDblclick"
>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="DATE" label="日期" />
<el-table-column label="费用项目">
@ -32,6 +41,43 @@
</el-table-column>
<el-table-column prop="BALANCE" label="余额" />
</layout-table>
<table class="print_use dn">
<thead>
<tr>
<td rowspan="2">序号</td>
<td rowspan="2">日期</td>
<td colspan="9">费用项目</td>
<td rowspan="2">余额</td>
</tr>
<tr>
<td>提取金额</td>
<td>培训教材教具费</td>
<td>师资费</td>
<td>试卷印制费</td>
<td>外出培训费</td>
<td>教学设备课桌椅等购置维护费</td>
<td>培训活动费</td>
<td>委托培训费</td>
<td>其他与培训有关的直接支出</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.DATE }}</td>
<td>{{ item.AMOUNT }}</td>
<td>{{ item.MATERIAL_COST }}</td>
<td>{{ item.TEACHER_COST }}</td>
<td>{{ item.PAPER_COST }}</td>
<td>{{ item.OUTSIDE_COST }}</td>
<td>{{ item.EQUIPMENT_COST }}</td>
<td>{{ item.TRAIN_COST }}</td>
<td>{{ item.ENTRUST_COST }}</td>
<td>{{ item.OTHER_COST }}</td>
<td>{{ item.BALANCE }}</td>
</tr>
</tbody>
</table>
<div class="flex mt">
<div>制表人:</div>
<div>编制日期:</div>
@ -45,17 +91,28 @@
<el-button @click="fnClose"></el-button>
</template>
</el-dialog>
<capital-add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
:year="year"
@get-data="fnGetData"
/>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { nextTick, reactive, watchEffect } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesCapitalList,
downloadFundmanageword,
setCapitalDelete,
getCapitalView,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.js";
import capitalAdd from "./capital_add.vue";
const props = defineProps({
type: {
@ -66,31 +123,44 @@ const props = defineProps({
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
ARCHIVESCAPITAL_ID: "",
addOrEditDialog: {
visible: false,
type: "",
form: {
DATE: "",
AMOUNT: "",
MATERIAL_COST: "",
TEACHER_COST: "",
PAPER_COST: "",
OUTSIDE_COST: "",
EQUIPMENT_COST: "",
TRAIN_COST: "",
ENTRUST_COST: "",
OTHER_COST: "",
BALANCE: "",
},
},
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesCapitalList({
const { list, fnGetData } = useListData(getArchivesCapitalList, {
otherParams: {
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
},
usePagination: false,
immediate: false,
});
watchEffect(() => {
if (props.type === 105) fnGetData();
});
@ -100,8 +170,7 @@ const fnExport = debounce(
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadFundmanageword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
NAME: props.corpName,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
@ -111,6 +180,35 @@ const fnExport = debounce(
},
{ atBegin: true }
);
const fnRowClick = (row) => {
data.ARCHIVESCAPITAL_ID = row.ARCHIVESCAPITAL_ID;
};
const fnRowDblclick = async (row) => {
data.addOrEditDialog.visible = true;
await nextTick();
if (row.ARCHIVESCAPITAL_ID) {
const resData = await getCapitalView({
ARCHIVESCAPITAL_ID: row.ARCHIVESCAPITAL_ID,
});
data.addOrEditDialog.form = resData.pd;
data.addOrEditDialog.type = "edit";
} else data.addOrEditDialog.type = "add";
};
const fnDelete = debounce(
1000,
async () => {
if (data.ARCHIVESCAPITAL_ID) {
await ElMessageBox.confirm("确定要删除吗?", { type: "warning" });
await setCapitalDelete({
ARCHIVESCAPITAL_ID: data.ARCHIVESCAPITAL_ID,
});
ElMessage.success("删除成功");
}
data.ARCHIVESCAPITAL_ID = "";
fnGetData();
},
{ atBegin: true }
);
const fnClose = () => {
emits("update:type", 0);
};

View File

@ -0,0 +1,153 @@
<template>
<el-dialog
v-model="visible"
:append-to-body="true"
:title="type === 'edit' ? '修改' : '新增'"
:on-close="fnClose"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="220px">
<el-form-item label="日期" prop="DATE">
<el-date-picker
v-model="form.DATE"
type="date"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="提取金额 " prop="AMOUNT">
<el-input v-model="form.AMOUNT" />
</el-form-item>
<el-form-item label="项目类型 " prop="ITEM_TYPE">
<el-input v-model="form.ITEM_TYPE" />
</el-form-item>
<el-form-item label="培训教材教具费" prop="MATERIAL_COST">
<el-input v-model="form.MATERIAL_COST" />
</el-form-item>
<el-form-item label="师资费 " prop="TEACHER_COST">
<el-input v-model="form.TEACHER_COST" />
</el-form-item>
<el-form-item label="试卷印制费 " prop="PAPER_COST">
<el-input v-model="form.PAPER_COST" />
</el-form-item>
<el-form-item label="外出培训费 " prop="OUTSIDE_COST">
<el-input v-model="form.OUTSIDE_COST" />
</el-form-item>
<el-form-item label="教学设备、课桌椅等购置维护费 " prop="EQUIPMENT_COST">
<el-input v-model="form.EQUIPMENT_COST" />
</el-form-item>
<el-form-item label="培训活动费 " prop="TRAIN_COST">
<el-input v-model="form.TRAIN_COST" />
</el-form-item>
<el-form-item label="委托培训费 " prop="ENTRUST_COST">
<el-input v-model="form.ENTRUST_COST" />
</el-form-item>
<el-form-item label="其他与培训有关的直接支出" prop="OTHER_COST">
<el-input v-model="form.OTHER_COST" />
</el-form-item>
<el-form-item label="余额" prop="BALANCE">
<el-input v-model="form.BALANCE" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { ref } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import {
setCapitalAdd,
setCapitalEdit,
} from "@/request/training_archive_management.js";
import { ElMessage } from "element-plus";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
year: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const rules = {
DATE: [{ required: true, message: "请选择日期", trigger: "blur" }],
AMOUNT: [{ required: true, message: "提取金额不能为空", trigger: "blur" }],
ITEM_TYPE: [{ required: true, message: "项目类型不能为空", trigger: "blur" }],
MATERIAL_COST: [
{ required: true, message: "培训教材教具费不能为空", trigger: "blur" },
],
TEACHER_COST: [
{ required: true, message: "师资费不能为空", trigger: "blur" },
],
PAPER_COST: [
{ required: true, message: "试卷印制费不能为空", trigger: "blur" },
],
OUTSIDE_COST: [
{ required: true, message: "外出培训费不能为空", trigger: "blur" },
],
EQUIPMENT_COST: [
{
required: true,
message: "教学设备、课桌椅等购置维护费不能为空",
trigger: "blur",
},
],
TRAIN_COST: [
{ required: true, message: "培训活动费不能为空", trigger: "blur" },
],
ENTRUST_COST: [
{ required: true, message: "委托培训费不能为空", trigger: "blur" },
],
OTHER_COST: [
{
required: true,
message: "其他与培训有关的直接支出不能为空",
trigger: "blur",
},
],
BALANCE: [{ required: true, message: "余额不能为空", trigger: "blur" }],
};
const formRef = ref(null);
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
props.type === "add"
? await setCapitalAdd({ ...props.form, YEAR: props.year })
: await setCapitalEdit({ ...props.form });
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{
atBegin: true,
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -11,8 +11,8 @@
<div class="tc">
<h3>{{ year }}年度安全培训教育管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table :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="培训对象" />
@ -27,9 +27,7 @@
<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="CORP_NAME" label="培训地点" />
<el-table-column prop="TRAINING_TEACHERS" label="培训教师" />
<el-table-column prop="ASSESSMENT_METHOD" label="考核方式">
<span>线上考核</span>
@ -60,13 +58,14 @@
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesManagerList,
downloadEdumanageword,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.js";
const props = defineProps({
type: {
@ -77,11 +76,7 @@ const props = defineProps({
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
corpName: {
type: String,
required: true,
},
@ -90,19 +85,15 @@ const props = defineProps({
required: true,
},
});
const data = reactive({
list: [],
});
const emits = defineEmits(["update:type"]);
const fnGetData = async () => {
const resData = await getArchivesManagerList({
const { list, fnGetData } = useListData(getArchivesManagerList, {
otherParams: {
TYPE: props.type,
CORPINFO_ID: props.CORPINFO_ID,
YEAR: props.year,
});
data.list = resData.varList;
};
},
usePagination: false,
immediate: false,
});
watchEffect(() => {
if (props.type === 104) fnGetData();
});
@ -112,8 +103,7 @@ const fnExport = debounce(
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadEdumanageword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
NAME: props.corpName,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",

View File

@ -7,15 +7,13 @@
>
<div class="tr">
<el-button type="primary" @click="fnExport"></el-button>
<el-button type="primary" @click="data.dialogForFile = true"
>上传文件</el-button
>
<el-button type="primary" @click="fnImport"></el-button>
</div>
<div class="tc">
<h3>{{ year }}年度安全培训教育计划</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table :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="结束时间" />
@ -28,9 +26,7 @@
<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="CORP_NAME" label="地点" />
<el-table-column prop="TRAINING_TEACHERS" label="培训教师" />
<el-table-column prop="FUND_GUARANTEE" label="经费保障">
<span>安全生产投入</span>
@ -43,28 +39,9 @@
<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>
<template #footer> <el-button @click="fnClose"></el-button> </template>
<pdf
v-if="data.dialogForFile"
v-model:visible="data.dialogForFile.visible"
:title="'安全培训教育计划'"
:type="103"
:year="year"
@ -82,6 +59,7 @@ import {
downloadTrainingplanword,
} from "@/request/training_archive_management.js";
import Pdf from "./pdf.vue";
import useListData from "@/assets/js/useListData.js";
const props = defineProps({
type: {
@ -92,11 +70,7 @@ const props = defineProps({
type: String,
required: true,
},
id: {
type: String,
required: true,
},
name: {
corpName: {
type: String,
required: true,
},
@ -106,19 +80,16 @@ const props = defineProps({
},
});
const data = reactive({
list: [],
dialogForFile: false,
dialogForFile: {
visible: 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;
};
const { list, fnGetData } = useListData(getArchivesPlanList, {
otherParams: { TYPE: props.type, YEAR: props.year },
usePagination: false,
immediate: false,
});
watchEffect(() => {
if (props.type === 103) fnGetData();
});
@ -128,8 +99,6 @@ const fnExport = debounce(
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(
@ -140,6 +109,9 @@ const fnExport = debounce(
},
{ atBegin: true }
);
const fnImport = () => {
data.dialogForFile.visible = !data.dialogForFile.visible;
};
const fnClose = () => {
emits("update:type", 0);
};

View File

@ -1,17 +1,30 @@
<template>
<el-dialog
v-model="visible"
:title="title"
:model-value="
type === 1 || type === 2 || type === 3 || type === 4 || type === 103
type === 1 || type === 2 || type === 3 || type === 4 || visible
"
width="1100px"
@close="fnClose"
>
<div>
<layout-upload
:file-list="[]"
auto-upload
:http-request="fnUpload"
accept=".pdf"
:show-file-list="false"
:limit="999"
>
<template #tip>只能上传pdf文件</template>
</layout-upload>
</div>
<div class="content-flex">
<div class="content-left">
<el-scrollbar style="height: 600px">
<layout-table
:data="data.list"
:data="list"
:show-header="false"
:show-pagination="false"
:border="false"
@ -20,16 +33,26 @@
@row-click="fnRowClick"
>
<el-table-column prop="FILE_NAME" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" text link @click.stop="fnDelete(row)">
<el-icon color="red" class="mr-10">
<delete />
</el-icon>
删除
</el-button>
</template>
</el-table-column>
</layout-table>
</el-scrollbar>
</div>
<div class="content-right">
<div v-if="!data.pdfSrc" class="content-tip">
<div v-if="!pdfSrc" class="content-tip">
<div class="box">
<div class="icon">
<icon-file-pdf-one
theme="filled"
size="60"
size="50"
fill="#fff"
:stroke-width="3"
/>
@ -40,16 +63,7 @@
</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>
<layout-pdf v-if="pdfSrc" :src="pdfSrc" model="normal" />
</div>
</div>
<template #footer>
@ -59,13 +73,26 @@
</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";
import {
getArchivesFilesList,
setArchivesFilesDelete,
setArchivesFilesUpload,
} from "@/request/training_archive_management.js";
import LayoutUpload from "@/components/upload/index.vue";
import LayoutPdf from "@/components/pdf/index.vue";
import { ref, watchEffect } from "vue";
import { Delete } from "@element-plus/icons-vue";
import useListData from "@/assets/js/useListData.js";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import { useVModels } from "@vueuse/core";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const props = defineProps({
visible: {
type: Boolean,
required: false,
default: false,
},
type: {
type: Number,
required: true,
@ -74,7 +101,7 @@ const props = defineProps({
type: String,
required: true,
},
CORPINFO_ID: {
corpName: {
type: String,
required: true,
},
@ -83,21 +110,14 @@ const props = defineProps({
required: true,
},
});
const data = reactive({
list: [],
pdfSrc: "",
numOfPages: 0,
const emits = defineEmits(["update:visible", "update:type"]);
const { visible } = useVModels(props, emits);
const pdfSrc = ref("");
const { list, fnGetData } = useListData(getArchivesFilesList, {
otherParams: { TYPE: props.type, YEAR: props.year },
usePagination: false,
immediate: false,
});
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 ||
@ -106,21 +126,38 @@ watchEffect(() => {
props.type === 4 ||
props.type === 103
)
fnGetData();
fnGetData({ TYPE: props.type, YEAR: props.year });
});
const fnUpload = async (item) => {
const formData = new FormData();
formData.append("FFILE", item.file);
formData.append("TYPE", props.type);
formData.append("YEAR", props.year);
await setArchivesFilesUpload(formData);
fnGetData({ TYPE: props.type, YEAR: props.year });
};
const fnDelete = debounce(
1000,
async ({ ARCHIVESFILES_ID, FILE_PATH }) => {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
await setArchivesFilesDelete({
ARCHIVESFILES_ID,
FILE_PATH,
});
ElMessage.success("删除成功");
fnGetData({ TYPE: props.type, YEAR: props.year });
},
{ atBegin: true }
);
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;
});
pdfSrc.value = row.FILE_PATH;
};
const fnClose = () => {
data.pdfSrc = "";
data.numOfPages = 0;
pdfSrc.value = "";
emits("update:type", 0);
visible.value = false;
};
</script>

View File

@ -6,13 +6,23 @@
@close="fnClose"
>
<div class="tr">
<el-button type="primary" @click="list.push({})"></el-button>
<el-button type="danger" @click="fnDelete"></el-button>
<el-button type="primary" @click="fnImport"></el-button>
<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">
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table
:data="list"
:show-pagination="false"
:stripe="false"
:highlight-current-row="true"
@row-click="fnRowClick"
@row-dblclick="fnRowDblclick"
>
<el-table-column type="index" label="序号" width="60" />
<el-table-column prop="NAME" label="姓名" />
<el-table-column prop="POST" label="岗位/操作项目" />
@ -30,12 +40,31 @@
<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>
<table class="print_use dn">
<thead>
<tr>
<td>序号</td>
<td>姓名</td>
<td>岗位/操作项目</td>
<td>电话</td>
<td>证书号</td>
<td>证书有效期限</td>
<td>复训日期</td>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in list" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ item.NAME }}</td>
<td>{{ item.POST }}</td>
<td>{{ item.PHONE }}</td>
<td>{{ item.CARD_ID }}</td>
<td>{{ item.EFFECTIVE_DATE }}</td>
<td>{{ item.RETRAINING }}</td>
</tr>
</tbody>
</table>
<div class="flex mt">
<div>档案管理人员:</div>
<div>更新日期:</div>
@ -43,18 +72,36 @@
<template #footer>
<el-button @click="fnClose"></el-button>
</template>
<postman-add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
:year="year"
@get-data="fnGetData"
/>
<layout-import-file
v-model:visible="data.importDialogVisible"
template-url="/TrafficFile/template/post.xls"
@submit="fnSubmitImport"
/>
</el-dialog>
</template>
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { nextTick, reactive, watchEffect } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesPostmanList,
downloadPersonmanage,
getPostmanView,
setPostmanDelete,
setPostmanImport,
} from "@/request/training_archive_management.js";
import PostmanAdd from "./postman_add.vue";
import LayoutImportFile from "@/components/import_file/index.vue";
import useListData from "@/assets/js/useListData.js";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const props = defineProps({
@ -66,31 +113,37 @@ const props = defineProps({
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
year: {
type: String,
required: true,
},
name: {
corpName: {
type: String,
required: true,
},
});
const data = reactive({
list: [],
importDialogVisible: false,
ARCHIVES_POSTMAN_ID: "",
addOrEditDialog: {
visible: false,
type: "",
form: {
NAME: "",
POST: "",
PHONE: "",
CARD_ID: "",
EFFECTIVE_DATE: "",
RETRAINING: "",
},
},
});
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;
};
const { list, fnGetData } = useListData(getArchivesPostmanList, {
otherParams: { TYPE: props.type, YEAR: props.year },
usePagination: false,
immediate: false,
});
watchEffect(() => {
if (props.type === 101) fnGetData();
});
@ -100,8 +153,7 @@ const fnExport = debounce(
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadPersonmanage({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
NAME: props.corpName,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
@ -111,6 +163,42 @@ const fnExport = debounce(
},
{ atBegin: true }
);
const fnRowClick = (row) => {
data.ARCHIVES_POSTMAN_ID = row.ARCHIVES_POSTMAN_ID;
};
const fnRowDblclick = async (row) => {
data.addOrEditDialog.visible = true;
await nextTick();
if (row.ARCHIVES_POSTMAN_ID) {
const resData = await getPostmanView({
ARCHIVES_POSTMAN_ID: row.ARCHIVES_POSTMAN_ID,
});
data.addOrEditDialog.form = resData.pd;
data.addOrEditDialog.type = "edit";
} else data.addOrEditDialog.type = "add";
};
const fnDelete = debounce(
1000,
async () => {
if (data.ARCHIVES_POSTMAN_ID) {
await ElMessageBox.confirm("确定要删除吗?", { type: "warning" });
await setPostmanDelete({
ARCHIVES_POSTMAN_ID: data.ARCHIVES_POSTMAN_ID,
});
ElMessage.success("删除成功");
}
data.ARCHIVES_POSTMAN_ID = "";
fnGetData();
},
{ atBegin: true }
);
const fnImport = () => {
data.importDialogVisible = !data.importDialogVisible;
};
const fnSubmitImport = async (formData) => {
const resData = await setPostmanImport(formData);
ElMessage.success(resData.msg);
};
const fnClose = () => {
emits("update:type", 0);
};

View File

@ -0,0 +1,141 @@
<template>
<el-dialog
v-model="visible"
:append-to-body="true"
:title="type === 'edit' ? '修改' : '新增'"
:on-close="fnClose"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="姓名" prop="NAME">
<el-input v-model="form.NAME" />
</el-form-item>
<el-form-item label="岗位/操作项目" prop="POST">
<el-input v-model="form.POST" />
</el-form-item>
<el-form-item label="手机号" prop="PHONE">
<el-input v-model="form.PHONE" />
</el-form-item>
<el-form-item label="照片" prop="hideUpload">
<layout-upload
v-model:file-list="form.hideUpload"
accept=".jpg,.jpeg,.png"
list-type="picture-card"
:limit="1"
delete-to-server
/>
</el-form-item>
<el-form-item label="证书号" prop="CARD_ID">
<el-input v-model="form.CARD_ID" />
</el-form-item>
<el-form-item label="证书有效期限" prop="EFFECTIVE_DATE">
<el-date-picker
v-model="form.EFFECTIVE_DATE"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="date"
/>
</el-form-item>
<el-form-item label="复训日期" prop="RETRAINING">
<el-date-picker
v-model="form.RETRAINING"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="date"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { ref } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import {
setPostmanAdd,
setPostmanEdit,
} from "@/request/training_archive_management.js";
import { ElMessage } from "element-plus";
import LayoutUpload from "@/components/upload/index.vue";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
year: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const rules = {
NAME: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
POST: [{ required: true, message: "岗位/操作项目不能为空", trigger: "blur" }],
PHONE: [
{ required: true, message: "手机号不能为空", trigger: "blur" },
{
pattern:
/^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
message: "请输入正确的手机号",
trigger: "blur",
},
],
hideUpload: [{ required: true, message: "照片不能为空", trigger: "blur" }],
CARD_ID: [{ required: true, message: "证书号不能为空", trigger: "blur" }],
EFFECTIVE_DATE: [
{ required: true, message: "请选择证书有效期限", trigger: "change" },
],
RETRAINING: [
{ required: true, message: "请选择复训日期", trigger: "change" },
],
};
const formRef = ref(null);
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
const formData = new FormData();
Object.keys(props.form).forEach((key) => {
formData.append(key, props.form[key]);
});
if (props.form.hideUpload[0].raw) {
formData.append("FFILE", props.form.hideUpload[0].raw);
}
formData.append("YEAR", props.year);
props.type === "add"
? await setPostmanAdd(formData)
: await setPostmanEdit(formData);
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{
atBegin: true,
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -11,8 +11,8 @@
<div class="tc">
<h3>{{ year }}年度本单位师资管理台账</h3>
</div>
<p class="mb">单位名称:{{ name }}</p>
<layout-table :data="data.list" :show-pagination="false">
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table :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="从事本专业工作年限" />
@ -37,13 +37,14 @@
<script setup>
import LayoutTable from "@/components/table/index";
import { reactive, watchEffect } from "vue";
import { watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
import {
getArchivesTeacherList,
downloadTeacherword,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.js";
const props = defineProps({
type: {
@ -54,11 +55,7 @@ const props = defineProps({
type: String,
required: true,
},
CORPINFO_ID: {
type: String,
required: true,
},
name: {
corpName: {
type: String,
required: true,
},
@ -67,18 +64,12 @@ const props = defineProps({
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;
};
const { list, fnGetData } = useListData(getArchivesTeacherList, {
otherParams: { TYPE: props.type, YEAR: props.year },
usePagination: false,
immediate: false,
});
watchEffect(() => {
if (props.type === 102) fnGetData();
});
@ -88,8 +79,7 @@ const fnExport = debounce(
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
await downloadTeacherword({
YEAR: props.year,
CORPINFO_ID: props.CORPINFO_ID,
NAME: props.name,
NAME: props.corpName,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",

View File

@ -37,20 +37,20 @@
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 value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio value="C">C.{{ item.OPTIONC }}</el-radio>
<el-radio value="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 value="A">A.{{ item.OPTIONA }}</el-checkbox>
<el-checkbox value="B">B.{{ item.OPTIONB }}</el-checkbox>
<el-checkbox value="C">C.{{ item.OPTIONC }}</el-checkbox>
<el-checkbox value="D">D.{{ item.OPTIOND }}</el-checkbox>
</el-checkbox-group>
<el-radio-group
v-if="item.QUESTIONTYPE === '3'"
@ -58,9 +58,9 @@
:disabled="true"
class="panduan"
>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<div class="el-radio"></div>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
<div class="el-radio"></div>
</el-radio-group>
</dl>

View File

@ -11,7 +11,7 @@
<div id="printContent">
<h2 class="tc">学员考核成绩统计表</h2>
<div class="flex mt mb">
<span>平台名称:{{ data.info.CORPINFO_NAME }}</span>
<span>平台名称:{{ corpName }}</span>
<span
>报表日期:{{ dayjs(data.clazz.END_TIME).format("YYYY-MM-DD") }}</span
>
@ -21,7 +21,7 @@
<td colspan="2">公司名称</td>
</tr>
<tr>
<td colspan="2">{{ data.clazz.CORP_INFO }}</td>
<td colspan="2">{{ corpName }}</td>
</tr>
<tr>
<td>培训时间</td>
@ -173,6 +173,10 @@ const props = defineProps({
type: String,
required: true,
},
corpName: {
type: String,
required: true,
},
});
const data = reactive({
info: {},

View File

@ -9,9 +9,9 @@
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div class="tc">
<h3>{{ CORP_NAME }}培训计划</h3>
<h3>{{ corpName }}培训计划</h3>
</div>
<p class="mb">单位名称:{{ CORP_INFO }}</p>
<p class="mb">单位名称:{{ corpName }}</p>
<layout-table :data="data.list" :show-pagination="false">
<el-table-column type="index" label="序号" width="50" />
<el-table-column label="培训人员类型"> 从业人员 </el-table-column>
@ -33,7 +33,7 @@
<el-table-column prop="TRAINING_TEACHERS" label="授课教师" />
</layout-table>
<div class="flex mt">
<div>编制单位:{{ CORP_NAME }}</div>
<div>编制单位:{{ corpName }}</div>
<div>编制日期:</div>
</div>
<template #footer>

View File

@ -6,15 +6,15 @@
</div>
<layout-table
ref="tableRef"
v-model:pagination="data.pagination"
v-model:pagination="pagination"
row-key="CURRICULUM_ID"
:data="data.varlist"
:data="list"
@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) }}
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="CURRICULUMNAME" label="教材名称" />
@ -50,17 +50,12 @@ import {
getClassCurriculumList,
downloadTeachingMaterialAll,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.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: "",
});
@ -68,16 +63,9 @@ 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 { list, pagination, fnGetData } = useListData(getClassCurriculumList, {
otherParams: { CLASS_ID },
});
const fnExport = debounce(
1000,
async () => {

View File

@ -2,14 +2,14 @@
<div>
<el-card>
<el-form
:model="data.searchForm"
:model="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-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
@ -18,10 +18,7 @@
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
<el-button
v-if="data.varlist.length > 0"
type="primary"
@click="fnExport"
<el-button v-if="list.length > 0" type="primary" @click="fnExport"
>导出</el-button
>
</el-form-item>
@ -30,15 +27,15 @@
</el-form>
<layout-table
ref="tableRef"
v-model:pagination="data.pagination"
v-model:pagination="pagination"
row-key="STAGEEXAMPAPERINPUT_ID"
:data="data.varlist"
:data="list"
@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) }}
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="EXAMNAME" label="试卷名称" />
@ -78,18 +75,12 @@ import {
getClassPaperList,
downloadArchivePapers,
} from "@/request/training_archive_management.js";
import useListData from "@/assets/js/useListData.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: "",
});
@ -97,26 +88,8 @@ 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 { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassPaperList, { otherParams: { CLASS_ID } });
const fnExport = debounce(
1000,
async () => {

View File

@ -727,16 +727,16 @@
:disabled="true"
>
<dd>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
</dd>
<dd>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
</dd>
<dd>
<el-radio label="C">C.{{ item.OPTIONC }}</el-radio>
<el-radio value="C">C.{{ item.OPTIONC }}</el-radio>
</dd>
<dd>
<el-radio label="D">D.{{ item.OPTIOND }}</el-radio>
<el-radio value="D">D.{{ item.OPTIOND }}</el-radio>
</dd>
</el-radio-group>
<el-checkbox-group
@ -745,16 +745,16 @@
:disabled="true"
>
<dd>
<el-checkbox label="A">A.{{ item.OPTIONA }}</el-checkbox>
<el-checkbox value="A">A.{{ item.OPTIONA }}</el-checkbox>
</dd>
<dd>
<el-checkbox label="B">B.{{ item.OPTIONB }}</el-checkbox>
<el-checkbox value="B">B.{{ item.OPTIONB }}</el-checkbox>
</dd>
<dd>
<el-checkbox label="C">C.{{ item.OPTIONC }}</el-checkbox>
<el-checkbox value="C">C.{{ item.OPTIONC }}</el-checkbox>
</dd>
<dd>
<el-checkbox label="D">D.{{ item.OPTIOND }}</el-checkbox>
<el-checkbox value="D">D.{{ item.OPTIOND }}</el-checkbox>
</dd>
</el-checkbox-group>
<el-radio-group
@ -763,10 +763,10 @@
:disabled="true"
>
<dd>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
</dd>
<dd>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
</dd>
</el-radio-group>
<div class="flex">

View File

@ -15,7 +15,7 @@
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-col :span="4">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
@ -23,6 +23,14 @@
</el-button>
</el-form-item>
</el-col>
<el-form-item label-width="10px">
<el-button type="primary" @click="fnBatchDownload">
下载补充档案
</el-button>
</el-form-item>
<el-form-item label-width="10px">
<el-button type="primary"> 班级档案 </el-button>
</el-form-item>
</el-row>
</el-form>
</el-card>
@ -83,12 +91,42 @@ 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 {
downloadAward,
getStudentsList,
} from "@/request/training_archive_management.js";
import router from "@/router/index.js";
import { ElMessage, ElMessageBox } from "element-plus";
import { debounce } from "throttle-debounce";
const tableRef = ref(null);
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getStudentsList);
</script>
const fnBatchDownload = debounce(
1000,
async () => {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选中要下载的学员补充档案...");
return;
}
const ids = selectionData
.map((item) => {
return item.USER_ID;
})
.join(",");
await downloadAward({
ids,
});
await ElMessageBox.confirm(
"导出后请前往档案下载中下载该档案!",
"温馨提示",
{ type: "info" }
);
tableRef.value.clearSelection();
},
{ atBegin: true }
);
</script>
<style scoped></style>

View File

@ -0,0 +1,211 @@
<template>
<el-dialog v-model="visible" width="1100px" title="效果评估表">
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div id="printContent">
<h1 style="text-align: center; margin-left: 60px">
安全生产教育培训动态评估报告
</h1>
<p class="p1" style="width: 100%; text-align: center">
企业名称:
{{ data.evaluationDialogForm.CORP_NAME }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
评估日期:
{{ data.evaluationDialogForm.END_TIME }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
<h3>评估概述</h3>
<p class="p1">
本报告旨在对{{ data.evaluationDialogForm.CORP_NAME }}公司
的安全生产培训进行动态评估安全生产培训的目标是提高员工的安全意识和技能促进工作场所的安全管理和事故预防本报告将对培训的实施情况培训效果参与度员工考试通过率知识盲点以及可能的改进措施进行评估和分析
</p>
<h3>评估内容</h3>
<p class="p1">
贵公司于{{ data.evaluationDialogForm.START_TIME }}时间 -
{{ data.evaluationDialogForm.END_TIME }}时间进行了{{
data.evaluationDialogForm.CLASS_NAME
}}培训培训内容如下{{ data.evaluationDialogForm.coursewareName }}
</p>
<h3>考试结果</h3>
<p class="p1">
<b
>本次考试共{{
data.evaluationDialogForm.EXMA_COUNT
}}人参加合格人数{{
data.evaluationDialogForm.PASS_COUNT
}}未合格人数{{
data.evaluationDialogForm.NO_PASS_COUNT
}}通过率{{
data.evaluationDialogForm.passRate
}}%具体情况如下</b
>
</p>
<div id="chart" ref="chart" style="width: 900px; height: 320px" />
<p class="p1"><b>评估结果和分析</b></p>
<p class="p1">
基于评估结果和培训过程中的观察我们对员工的知识盲点进行分析指出可能存在的理解不足或需要加强的知识领域主要知识盲点体现为
</p>
<p class="p1">{{ data.evaluationDialogForm.error }}</p>
<table class="table">
<tr>
<td>标签名称</td>
<td>错误率</td>
</tr>
<tr
v-for="(value, key) in data.evaluationDialogForm.ratioMap"
:key="key"
>
<td>{{ key }}</td>
<td>{{ value }}%</td>
</tr>
</table>
<p class="p1">知识盲点对应课件为</p>
<p class="p1">{{ data.evaluationDialogForm.errorVideoName }}</p>
<p class="p1"><b>评估建议</b></p>
<p class="p1">
存在的知识盲点需要进一步加强和补充我们建议您将重点放在弥补这些盲点上通过进一步学习参与讨论或与安全专家交流弥补知识盲区
</p>
<h3>强化培训记录</h3>
<p class="p1"><b>强化培训考试记录</b></p>
<table class="table">
<tr>
<td colspan="3">班级名称</td>
<td colspan="3">培训时间</td>
</tr>
<tr>
<td colspan="3">{{ data.evaluationDialogForm.CLASS_NAME }}</td>
<td colspan="3">
{{
dayjs(data.evaluationDialogForm.START_TIME).format(
"YYYY年MM月DD日"
)
}}
-
{{
dayjs(data.evaluationDialogForm.END_TIME).format("YYYY年MM月DD日")
}}
</td>
</tr>
<tr>
<td colspan="3">培训人数</td>
<td colspan="3">合格人数</td>
</tr>
<tr>
<td colspan="3">{{ data.evaluationDialogForm.STR_EXMA_COUNT }}</td>
<td colspan="3">{{ data.evaluationDialogForm.STR_PASS_COUNT }}</td>
</tr>
<tr>
<td colspan="6">合格学员名单</td>
</tr>
<tr>
<td style="width: 10%">序号</td>
<td style="width: 15%">姓名</td>
<td style="width: 25%">身份证号</td>
<td style="width: 20%">手机号</td>
<td style="width: 10%">性别</td>
<td style="width: 25%">效果评估成绩</td>
</tr>
<tr
v-for="(value, key) in data.evaluationDialogForm.PASS_List"
:key="key"
>
<td style="width: 10%">{{ key + 1 }}</td>
<td style="width: 15%">{{ value.NAME }}</td>
<td style="width: 25%">{{ value.USER_ID_CARD }}</td>
<td style="width: 20%">{{ value.PHONE }}</td>
<td style="width: 10%">{{ value.SEX }}</td>
<td style="width: 25%">{{ value.STRENGTHENEXAMSCORE }}</td>
</tr>
<tr>
<td colspan="6">未合格学员名单</td>
</tr>
<tr>
<td style="width: 10%">序号</td>
<td style="width: 15%">姓名</td>
<td style="width: 25%">身份证号</td>
<td style="width: 20%">手机号</td>
<td style="width: 10%">性别</td>
<td style="width: 25%">效果评估成绩</td>
</tr>
<tr
v-for="(value, key) in data.evaluationDialogForm.NO_PASS_List"
:key="key"
>
<td style="width: 10%">{{ key + 1 }}</td>
<td style="width: 15%">{{ value.NAME }}</td>
<td style="width: 25%">{{ value.USER_ID_CARD }}</td>
<td style="width: 20%">{{ value.PHONE }}</td>
<td style="width: 10%">{{ value.SEX }}</td>
<td style="width: 25%">{{ value.STRENGTHENEXAMSCORE }}</td>
</tr>
</table>
</div>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { getClassEvaluation } from "@/request/training_archive_management.js";
import { useVModel } from "@vueuse/core";
import dayjs from "dayjs";
const props = defineProps({
classId: {
type: String,
required: true,
},
visible: {
type: Boolean,
default: false,
},
});
const visible = useVModel(props, "visible");
const data = reactive({
evaluationDialogForm: {},
count1: "",
count2: "",
count3: "",
});
const fnGetData = async () => {
const resData = await getClassEvaluation({
CLASS_ID: props.classId,
});
data.evaluationDialogForm = resData.pageData;
data.count1 = data.pageData.count1;
data.count2 = data.pageData.count2;
data.count3 = data.pageData.count3;
};
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
window.location.href =
import.meta.env[import.meta.env.DEV ? "VITE_PROXY" : "VITE_BASE_URL"] +
"class/hs?CLASS_ID=" +
props.classId;
};
watchEffect(() => {
if (visible.value) fnGetData();
});
</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,283 @@
<template>
<el-dialog v-model="visible" width="1100px" title="效果评估表">
<div class="tr mb">
<el-button type="primary" @click="fnExport"></el-button>
</div>
<div id="printContent">
<h1 style="text-align: center; margin-left: 60px">
安全生产教育培训动态评估报告
</h1>
<p class="p1" style="width: 100%; text-align: center">
姓名: {{ data.evaluationDialogForm.NAME }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
身份证号:
{{
data.evaluationDialogForm.USER_ID_CARD
}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 评估日期:
{{ data.evaluationDialogForm.OPERATTIME }}
</p>
<h3>评估概述</h3>
<p class="p1">
本报告旨在评估您在最近接受的安全培训中的个人效果并提供课程考试结果以及指出可能存在的知识盲点安全培训的目标是提高您在工作环境中的安全意识和行为以减少事故和伤害的发生本报告将对您的培训参与度知识掌握程度课程考试成绩以及可能存在的知识盲点进行评估
</p>
<h3>学员基本情况</h3>
<table
align="center"
border="1"
cellspacing="0"
width="100%"
class="table"
>
<tr>
<td style="width: 70px">姓名</td>
<td style="width: 60px">{{ data.evaluationDialogForm.NAME }}</td>
<td style="width: 55px">性别</td>
<td style="width: 80px">{{ data.evaluationDialogForm.SEX }}</td>
<td style="width: 60px">身份证号</td>
<td style="width: 150px">
{{ data.evaluationDialogForm.USER_ID_CARD }}
</td>
<td style="width: 60px">学历</td>
<td style="width: 200px">
{{ data.evaluationDialogForm.DEGREE_OF_EDUCATION }}
</td>
<td style="width: 60px">专业</td>
<td>{{ data.evaluationDialogForm.MAJOR }}</td>
</tr>
<tr>
<td>职务/职称</td>
<td>{{ data.evaluationDialogForm.DUTIES }}</td>
<td>部门</td>
<td>{{ data.evaluationDialogForm.DEPARTMENT_NAME }}</td>
<td>工种</td>
<td>{{ data.evaluationDialogForm.POST_NAME }}</td>
<td>行业类别</td>
<td>{{ data.evaluationDialogForm.INDUSTRY_ALL_NAME }}</td>
<td>联系电话</td>
<td>{{ data.evaluationDialogForm.PHONE }}</td>
</tr>
<tr>
<td>人员类型</td>
<td colspan="9">{{ data.evaluationDialogForm.PERSONNEL_TYPE }}</td>
</tr>
</table>
<h3>评估内容</h3>
<p class="p1">
您在 {{ data.evaluationDialogForm.START_TIME }} -
{{ data.evaluationDialogForm.END_TIME }} 进行了
{{ data.evaluationDialogForm.CLASS_NAME }} 培训内容如下
{{ data.evaluationDialogForm.coursewareName }}
</p>
<p class="p1">
您参加了培训后的课程考试并取得了以下成绩{{
data.evaluationDialogForm.STAGEEXAMSCORE
}}
</p>
<h3>评估结果</h3>
<p class="p1">根据我们的评估您的个人培训效果如下</p>
<p class="p1">
<b
>您在培训期间表现出积极的参与度完成了所有的培训课程和活动</b
>
</p>
<p class="p1">
<b
><span v-if="data.evaluationDialogForm.correct !== ''"
>您对 {{ data.evaluationDialogForm.correct }} 知识掌握得很好</span
>在评估过程中我们发现您可能存在以下知识盲点{{
data.evaluationDialogForm.error
}}</b
>
</p>
<p class="p1">知识盲点对应课件为</p>
<p class="p1">{{ data.evaluationDialogForm.errorVideoName }}</p>
<p class="p1"><b>评估建议</b></p>
<p class="p1">
存在的知识盲点需要进一步加强和补充我们建议您将重点放在弥补这些盲点上通过进一步学习参与讨论或与安全专家交流弥补知识盲区
</p>
<h3>强化培训记录</h3>
<p class="p1"><b>强化培训考试记录</b></p>
<div
v-if="data.evaluationDialogForm.STRENGTHEN_EXAMNAME !== '0'"
class="page-break"
>
<div class="levelup no-print">
<h1>考卷详情</h1>
</div>
<div class="paper-details chapter_box">
<div class="chapter_right_img" />
<h1 style="text-align: center">
{{ data.evaluationDialogForm.STRENGTHEN_EXAMNAME }}
</h1>
<div style="text-align: center">
(满分:{{ data.evaluationDialogForm.STRENGTHEN_EXAMSCORE }})
</div>
<div class="subflex">
<span>班级名称:{{ data.evaluationDialogForm.CLASS_NAME }}</span>
<span>姓名:{{ data.evaluationDialogForm.NAME }}</span>
</div>
<div class="subflex">
<span
>考试时间:{{
data.evaluationDialogForm.STRENGTHEN_OPERATTIME
}}</span
>
<span
>分数:{{ data.evaluationDialogForm.STRENGTHENEXAMSCORE }}</span
>
</div>
<div class="study-papg">
<dl
v-for="(row, key) in data.evaluationDialogForm
.strengthenexamrecord"
:key="key"
>
<dt>
<span v-if="row.QUESTIONTYPE === '1'" class="mark mark-green"
>(单选题)
</span>
<span v-if="row.QUESTIONTYPE === '2'" class="mark mark-blue"
>(多选题)</span
>
<span v-if="row.QUESTIONTYPE === '3'" class="mark mark-orange"
>(判断题)</span
>
<span v-if="row.QUESTIONTYPE === '4'" class="mark mark-purple"
>(填空题)</span
>
{{ key + 1 }}.{{ row.QUESTIONDRY }}
<span class="ml-10">(题目分值{{ row.SCORE }})</span>
</dt>
<el-radio-group
v-if="row.QUESTIONTYPE === '1'"
v-model="row.ANSWER"
:disabled="true"
>
<dd>
<el-radio value="A">A.{{ row.OPTIONA }}</el-radio>
</dd>
<dd>
<el-radio value="B">B.{{ row.OPTIONB }}</el-radio>
</dd>
<dd>
<el-radio value="C">C.{{ row.OPTIONC }}</el-radio>
</dd>
<dd>
<el-radio value="D">D.{{ row.OPTIOND }}</el-radio>
</dd>
</el-radio-group>
<el-checkbox-group
v-if="row.QUESTIONTYPE === '2'"
v-model="row.checkList"
:disabled="true"
>
<dd>
<el-checkbox value="A">A.{{ row.OPTIONA }}</el-checkbox>
</dd>
<dd>
<el-checkbox value="B">B.{{ row.OPTIONB }}</el-checkbox>
</dd>
<dd>
<el-checkbox value="C">C.{{ row.OPTIONC }}</el-checkbox>
</dd>
<dd>
<el-checkbox value="D">D.{{ row.OPTIOND }}</el-checkbox>
</dd>
</el-checkbox-group>
<el-radio-group
v-if="row.QUESTIONTYPE === '3'"
v-model="row.ANSWER"
:disabled="true"
>
<dd>
<el-radio value="A">A.{{ row.OPTIONA }}</el-radio>
</dd>
<dd>
<el-radio value="B">B.{{ row.OPTIONB }}</el-radio>
</dd>
</el-radio-group>
<div class="flex-layout space-between">
<div>
<div v-if="row.QUESTIONTYPE === '4'" class="mb-10">
学员答案{{ row.ANSWER }}
</div>
<div class="mb-10">参考答案{{ row.ANSWERRIGHT }}</div>
<div>答案解析{{ row.DESCR }}</div>
</div>
</div>
</dl>
</div>
</div>
</div>
</div>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { reactive, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { getStudentEvaluation } from "@/request/training_archive_management.js";
import { useVModel } from "@vueuse/core";
const props = defineProps({
studentId: {
type: String,
required: true,
},
visible: {
type: Boolean,
default: false,
},
});
const visible = useVModel(props, "visible");
const data = reactive({
evaluationDialogForm: {},
count1: "",
count2: "",
count3: "",
});
const fnGetData = async () => {
const resData = await getStudentEvaluation({
STUDENT_ID: props.studentId,
});
data.evaluationDialogForm = resData.pageData;
data.count1 = data.pageData.count1;
data.count2 = data.pageData.count2;
data.count3 = data.pageData.count3;
};
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
window.location.href =
import.meta.env[import.meta.env.DEV ? "VITE_PROXY" : "VITE_BASE_URL"] +
"student/hs?STUDENT_ID=" +
props.studentId;
};
watchEffect(() => {
if (visible.value) fnGetData();
});
</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,126 @@
<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="NAME">
<el-input
v-model="searchForm.NAME"
placeholder="请输入班级名称"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年份" prop="YEAR">
<el-date-picker
v-model="searchForm.YEAR"
value-format="YYYY"
type="year"
style="width: 100%"
/>
</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="200" />
<el-table-column prop="TRAINTYPENAME" label="培训类型" width="200" />
<el-table-column prop="POSTTYPENAME" label="岗位类型" width="200" />
<el-table-column
prop="PASSSTUDENTCOUNT"
label="效果评估通过人数"
width="200"
/>
<el-table-column
prop="ALLSTUDENTCOUNT"
label="效果评估总人数"
width="200"
/>
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/effect_appraisal/enterprise_effect/index/studentStrengthenDetailsList',
query: {
CLASS_ID: row.CLASS_ID,
},
})
"
>
学员详情
</el-button>
<el-button
type="primary"
text
link
@click="goClassStrengthenInfo(row.CLASS_ID)"
>
班级效果评估表
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<class-strengthen
v-model:visible="data.evaluationDialog.visible"
:class-id="data.evaluationDialog.CLASS_ID"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { reactive, ref } from "vue";
import { getClassStrengthenDetailsList } from "@/request/training_archive_management.js";
import router from "@/router/index.js";
import ClassStrengthen from "./components/classStrengthen.vue";
const data = reactive({
evaluationDialog: {
visible: false,
CLASS_ID: "",
},
});
const tableRef = ref(null);
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassStrengthenDetailsList);
const goClassStrengthenInfo = (class_id) => {
data.evaluationDialog.visible = true;
data.evaluationDialog.CLASS_ID = class_id;
};
</script>
<style scoped></style>

View File

@ -0,0 +1,128 @@
<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="STUDENTNAME">
<el-input v-model="searchForm.NAME" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年份" prop="YEAR">
<el-date-picker
v-model="searchForm.YEAR"
value-format="YYYY"
type="year"
style="width: 100%"
/>
</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="STUDENTNAME" label="姓名" width="200" />
<el-table-column prop="USERIDCARD" label="身份证号" width="200" />
<el-table-column prop="PHONE" label="手机号" width="200" />
<el-table-column
prop="STRENGTHENEXAMSTATE"
label="效果评估状态"
width="200"
>
<template #default="{ row }">
<span>
{{ row.STRENGTHENEXAMSTATE === "3" ? "通过" : "未通过" }}
</span>
</template>
</el-table-column>
<el-table-column
prop="STRENGTHENEXAMSCORE"
label="效果评估最高分"
width="200"
>
<template #default="{ row }">
<span>
{{
row.STRENGTHENEXAMSCORE
? row.STRENGTHENEXAMSCORE
: "未进行评估考试"
}}
</span>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="goStudentStrengthenInfo(row.STUDENT_ID)"
>
查看个人效果评估
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<student-strengthen
v-model:visible="data.evaluationDialog.visible"
:student-id="data.evaluationDialog.STUDENT_ID"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { reactive, ref } from "vue";
import { getStudentStrengthenDetailsList } from "@/request/training_archive_management.js";
import { useRoute } from "vue-router";
import StudentStrengthen from "./components/studentStrengthen.vue";
const route = useRoute();
const { CLASS_ID } = route.query;
const tableRef = ref(null);
const data = reactive({
evaluationDialog: {
visible: false,
STUDENT_ID: "",
},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getStudentStrengthenDetailsList, {
otherParams: { CLASS_ID },
});
const goStudentStrengthenInfo = (student_id) => {
data.evaluationDialog.visible = true;
data.evaluationDialog.STUDENT_ID = student_id;
};
</script>
<style scoped></style>

View File

@ -45,14 +45,14 @@
v-model="form.ISSUPERVISE"
@change="fnChangeRegulatoryAuthorities"
>
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否外来人员部门" prop="FOREIGNPERSONNEL">
<el-radio-group v-model="form.FOREIGNPERSONNEL">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="0"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item

View File

@ -23,8 +23,8 @@
</el-form-item>
<el-form-item label="状态" prop="STATUS">
<el-radio-group v-model="form.STATUS">
<el-radio label="0">启用</el-radio>
<el-radio label="1">禁用</el-radio>
<el-radio value="0">启用</el-radio>
<el-radio value="1">禁用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="告知卡" prop="files">

View File

@ -178,16 +178,16 @@
<el-col :span="24">
<el-form-item label="是否主要负责人" prop="ISHEAD">
<el-radio-group v-model="data.form.ISHEAD">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="是否部门领导" prop="ISLEADER">
<el-radio-group v-model="data.form.ISLEADER">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="0"></el-radio>
</el-radio-group>
<el-tooltip
content="温馨提示:部门领导可以审核离岗申请,查看同部门清单数据"

View File

@ -12,8 +12,8 @@
<el-col :span="24">
<el-form-item label="是否合格" prop="ISQUALIFIED">
<el-radio-group v-model="data.form.ISQUALIFIED">
<el-radio label="1"></el-radio>
<el-radio label="2"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="2"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>

View File

@ -21,8 +21,8 @@
:model-value="data.form.IS_NORMAL"
@change="fnIsNormalChange"
>
<el-radio label="1"></el-radio>
<el-radio label="2"></el-radio>
<el-radio value="1"></el-radio>
<el-radio value="2"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -168,7 +168,7 @@
<el-col :span="24">
<el-form-item label="整改方案" prop="HAVESCHEME">
<el-radio-group v-model="data.form.HAVESCHEME">
<el-radio label="1" value="1"></el-radio>
<el-radio value="1"></el-radio>
<el-radio :disabled="data.info.ISCONFIRM === '1'" label="0">
</el-radio>
@ -245,7 +245,7 @@
<el-col :span="24">
<el-form-item label="整改计划" prop="HAVEPLAN">
<el-radio-group v-model="data.form.HAVEPLAN">
<el-radio label="1" value="1"></el-radio>
<el-radio value="1"></el-radio>
<el-radio :disabled="data.info.ISCONFIRM === '1'" label="0">
</el-radio>

View File

@ -0,0 +1,57 @@
<template>
<layout-card>
<el-tabs v-model="active" @tab-change="fnTabChange">
<el-tab-pane
label="基本信息"
:name="
type === 'add'
? '/training_process_management/class_management/add'
: type === 'edit'
? '/training_process_management/class_management/edit'
: '/training_process_management/class_management/view'
"
lazy
:disabled="!CLASS_ID"
>
<basic-info />
</el-tab-pane>
<el-tab-pane
label="学员"
name="/training_process_management/class_management/student"
lazy
:disabled="!CLASS_ID"
>
<student />
</el-tab-pane>
<el-tab-pane
label="课程"
name="/training_process_management/class_management/curriculum"
lazy
:disabled="!CLASS_ID"
>
<curriculum />
</el-tab-pane>
</el-tabs>
</layout-card>
</template>
<script setup>
import BasicInfo from "./components/basic_info.vue";
import Student from "./components/student.vue";
import Curriculum from "./components/curriculum.vue";
import { ref } from "vue";
import { useRoute, useRouter } from "vue-router";
const router = useRouter();
const route = useRoute();
const { CLASS_ID, type } = route.query;
const active = ref(route.path);
const fnTabChange = (path) => {
router.replace({
path,
query: { ...route.query },
});
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,170 @@
<template>
<el-dialog v-model="visible" title="添加学员">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="发布类型" prop="releaseType">
<el-radio-group v-model="form.releaseType">
<el-radio value="1">按身份发布</el-radio>
<el-radio value="2">按人员发布</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="从业身份" prop="personnelTypes">
<el-checkbox-group
v-model="form.personnelTypes"
@change="fnGetDataTransfer"
>
<el-checkbox
v-for="item in personnelTypeList"
:key="item.DICTIONARIES_ID"
:label="item.NAME"
:value="item.DICTIONARIES_ID"
/>
</el-checkbox-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table
ref="tableRef"
:data="list"
:show-pagination="false"
max-height="500"
row-key="USER_ID"
>
<el-table-column
v-if="form.releaseType === '2'"
reserve-selection
type="selection"
width="55"
/>
<el-table-column label="序号" width="60" type="index" />
<el-table-column prop="NAME" label="姓名" />
<el-table-column prop="DEPARTMENT_NAME" label="部门" />
<el-table-column prop="POST_NAME" label="岗位" />
<el-table-column prop="USER_ID_CARD" label="身份证号" />
<el-table-column prop="PERSONNEL_TYPE_NAME" label="从业身份" />
</layout-table>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import useListData from "@/assets/js/useListData.js";
import {
getClassManagementSelectStudentAdd,
getClassManagementSelectStudentList,
} from "@/request/training_process_management.js";
import { layoutFnGetPersonnelType } from "@/assets/js/data_dictionary.js";
import { ref, watch } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
import { useRoute } from "vue-router";
const route = useRoute();
const { CLASS_ID, EXAMINATION } = route.query;
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
selectList: {
type: Array,
required: true,
default: () => [],
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const { list, fnGetData, tableRef } = useListData(
getClassManagementSelectStudentList,
{
usePagination: false,
key: "userList",
immediate: false,
callbackFn: (list) => {
for (let i = 0; i < props.selectList.length; i++) {
for (let j = 0; j < list.length; j++) {
if (list[j].USER_ID === props.selectList[i].USER_ID) {
list.splice(j, 1);
break;
}
}
}
},
}
);
const rules = {
releaseType: [{ required: true, message: "请选择发布类型", trigger: "blur" }],
personnelTypes: [
{ required: true, message: "请选择从业身份", trigger: "blur" },
],
};
const formRef = ref(null);
const fnGetDataTransfer = () => {
fnGetData({
PERSONNEL_TYPES: form.value.personnelTypes.join(","),
});
};
watch(
() => visible.value,
() => {
if (visible.value) {
if (form.value.personnelTypes.length > 0) fnGetDataTransfer();
}
}
);
const personnelTypeList = await layoutFnGetPersonnelType();
const fnClose = () => {
formRef.value.resetFields();
tableRef.value.clearSelection();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
if (list.value.length === 0) {
ElMessage.warning("当前从业身份没有学习人员,请重新选择");
return;
}
let currentIds = "";
if (form.value.releaseType === "1") {
currentIds = list.value.map((item) => item.USER_ID).join(",");
} else {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选择学员");
return;
}
currentIds = selectionData.map((item) => item.USER_ID).join(",");
}
await getClassManagementSelectStudentAdd({
RELEASE_TYPE: form.value.releaseType,
PERSONNEL_TYPES: form.value.personnelTypes.join(","),
CLASS_ID,
EXAMINATION,
userIds: currentIds,
});
ElMessage.success("添加成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,370 @@
<template>
<el-form ref="formRef" :model="data.form" :rules="rules" label-width="160px">
<el-row>
<el-col :span="24">
<el-divider content-position="left">基本信息</el-divider>
</el-col>
<el-col :span="12">
<el-form-item label="班级名称" prop="NAME">
<el-input
v-model="data.form.NAME"
placeholder="请输入班级名称"
:disabled="isEdit"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="培训日期" prop="TIME">
<el-date-picker
v-model="data.form.TIME"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
:disabled="isEdit"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="培训类型" prop="TRAINTYPE">
<layout-learning-train-type
ref="trainingTypeRef"
v-model="data.form.TRAINTYPE"
type="trainingType"
:disabled="isEdit"
@update:model-value="
data.form.POSTTYPE = '';
data.form.TRAINLEVEL = '';
"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="岗位类型" prop="POSTTYPE">
<layout-learning-train-type
ref="postTypeRef"
v-model="data.form.POSTTYPE"
type="postType"
:search-value="data.form.TRAINTYPE"
:disabled="isEdit"
@update:model-value="data.form.TRAINLEVEL = ''"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item
label="培训级别"
prop="TRAINLEVEL"
:rules="[
{
required: data.trainingLevelList.length !== 0,
message: '请选择培训级别',
trigger: 'change',
},
]"
>
<layout-learning-train-type
ref="trainingLevelRef"
v-model="data.form.TRAINLEVEL"
type="trainingLevel"
:search-value="data.form.POSTTYPE"
:disabled="isEdit"
@throw-data="data.trainingLevelList = $event"
/>
</el-form-item>
</el-col>
<template
v-if="
data.form.TRAINTYPE &&
data.form.TRAINTYPE !== 'c70bf859512241579a8a30fc5d1ae153'
"
>
<el-col :span="12">
<el-form-item label="记录人员" prop="RECORDOR">
<el-select
v-model="data.form.RECORDOR"
filterable
:disabled="isEdit"
>
<el-option
v-for="item in data.recordingPersonnelList"
:key="item.USERSIGNID"
:value="item.USERSIGNID"
:label="item.USERNAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="考核人员" prop="ASSESSOR">
<el-select
v-model="data.form.ASSESSOR"
filterable
:disabled="isEdit"
>
<el-option
v-for="item in data.assessorsList"
:key="item.USERSIGNID"
:value="item.USERSIGNID"
:label="item.USERNAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="安全管理部门负责人" prop="SAFETYDEPTOR">
<el-select
v-model="data.form.SAFETYDEPTOR"
filterable
:disabled="isEdit"
>
<el-option
v-for="item in data.headOfSafetyManagementDepartmentList"
:key="item.USERSIGNID"
:value="item.USERSIGNID"
:label="item.USERNAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人" prop="PRINCIPAL">
<el-input
v-model="data.form.PRINCIPAL"
placeholder="请输入负责人"
:disabled="isEdit"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="负责人电话" prop="PRINCIPAL_PHONE">
<el-input
v-model="data.form.PRINCIPAL_PHONE"
placeholder="请输入负责人电话"
:disabled="isEdit"
/>
</el-form-item>
</el-col>
</template>
<el-col :span="24">
<el-divider content-position="left">基本设置</el-divider>
</el-col>
<el-col :span="12">
<el-form-item label="是否开启考试" prop="EXAMINATION">
<el-radio-group v-model="data.form.EXAMINATION" :disabled="isEdit">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
</el-radio-group>
<span class="ml-10">
不考试的班级学员学习完所有课程即为完成学业
</span>
</el-form-item>
</el-col>
<el-col v-if="data.form.EXAMINATION === 1" :span="12">
<el-form-item label="考试次数" prop="NUMBEROFEXAMS">
<div style="flex: 1; display: flex">
<el-input-number
v-model="data.form.NUMBEROFEXAMS"
:min="1"
:max="2147483600"
:disabled="isEdit"
/>
<el-button
v-if="STATE && STATE !== '1' && STATE !== '6'"
type="primary"
class="ml-10"
@click="fnModifyExamTimes"
>
修改考试次数
</el-button>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="是否人脸识别" prop="ISFACE">
<el-radio-group v-model="data.form.ISFACE" :disabled="isEdit">
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="data.form.EXAMINATION === 1" :span="12">
<el-form-item label="是否效果评估" prop="ISSTRENGTHEN">
<el-radio-group v-model="data.form.ISSTRENGTHEN" :disabled="isEdit">
<el-radio label="2">强制</el-radio>
<el-radio label="1"></el-radio>
<el-radio label="0"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div v-if="!isEdit" class="mt-10 tc">
<el-button type="primary" @click="fnSubmit">
{{ !CLASS_ID ? "保存并下一步" : "保存" }}
</el-button>
</div>
<modify-exam-times
:id="CLASS_ID"
v-model:visible="data.modifyExamTimesDialog.visible"
v-model:form="data.modifyExamTimesDialog.form"
@get-data="fnGetData"
/>
</template>
<script setup>
import { nextTick, reactive, ref } from "vue";
import LayoutLearningTrainType from "@/components/learning_train_type/index.vue";
import {
getClassManagementView,
getPersonnelList,
setClassManagementAdd,
setClassManagementEdit,
} from "@/request/training_process_management.js";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
import { useRoute, useRouter } from "vue-router";
import ModifyExamTimes from "./modify_exam_times.vue";
const route = useRoute();
const router = useRouter();
const { STATE, CLASS_ID, type } = route.query;
const isEdit = STATE && STATE !== "1";
const formRef = ref(null);
const trainingTypeRef = ref(null);
const postTypeRef = ref(null);
const trainingLevelRef = ref(null);
const data = reactive({
recordingPersonnelList: [],
assessorsList: [],
headOfSafetyManagementDepartmentList: [],
trainingLevelList: [],
form: {
NAME: "",
TIME: "",
TRAINTYPE: "",
POSTTYPE: "",
TRAINLEVEL: "",
RECORDOR: "",
ASSESSOR: "",
SAFETYDEPTOR: "",
PRINCIPAL: "",
PRINCIPAL_PHONE: "",
EXAMINATION: 1,
NUMBEROFEXAMS: 1,
ISFACE: "1",
ISSTRENGTHEN: "1",
},
modifyExamTimesDialog: {
visible: false,
form: { NUMBEROFEXAMS: 1, source: 1 },
},
});
const rules = {
NAME: [{ required: true, message: "请输入班级名称", trigger: "blur" }],
TIME: [{ required: true, message: "请选择培训日期", trigger: "change" }],
TRAINTYPE: [{ required: true, message: "请选择培训类型", trigger: "change" }],
POSTTYPE: [{ required: true, message: "请选择岗位类型", trigger: "change" }],
RECORDOR: [{ required: true, message: "请选择记录人员", trigger: "change" }],
ASSESSOR: [{ required: true, message: "请选择考核人员", trigger: "change" }],
SAFETYDEPTOR: [
{ required: true, message: "请选择安全管理部门负责人", trigger: "change" },
],
PRINCIPAL: [{ required: true, message: "请输入负责人", trigger: "blur" }],
PRINCIPAL_PHONE: [
{ required: true, message: "请输入负责人电话", trigger: "blur" },
{
pattern:
/^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/,
message: "请输入正确的手机号码",
},
],
EXAMINATION: [
{ required: true, message: "请选择是否开启考试", trigger: "change" },
],
ISFACE: [
{ required: true, message: "请选择是否人脸识别", trigger: "change" },
],
ISSTRENGTHEN: [
{ required: true, message: "请选择是否效果评估", trigger: "change" },
],
NUMBEROFEXAMS: [
{ required: true, message: "请输入考试次数", trigger: "blur" },
],
};
const fnGetData = async () => {
if (!CLASS_ID) return;
const resData = await getClassManagementView({ CLASS_ID });
resData.pd.TIME = [resData.pd.START_TIME, resData.pd.END_TIME];
data.form = resData.pd;
};
fnGetData();
const fnGetPersonnelList = async () => {
const { varList: recordingPersonnelList } = await getPersonnelList({
USERSIGNTYPE: "854c77daf3734384807a638dfafe04d5",
});
const { varList: assessorsList } = await getPersonnelList({
USERSIGNTYPE: "f2726f92987d4f77be1c3f0460669418",
});
const { varList: headOfSafetyManagementDepartmentList } =
await getPersonnelList({
USERSIGNTYPE: "5f4794189cf24fc2a7e12fa47b70139e",
});
data.recordingPersonnelList = recordingPersonnelList;
data.assessorsList = assessorsList;
data.headOfSafetyManagementDepartmentList =
headOfSafetyManagementDepartmentList;
};
fnGetPersonnelList();
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
const params = {
...data.form,
ISSTRENGTHEN: data.form.EXAMINATION === 1 ? data.form.ISSTRENGTHEN : "0",
START_TIME: data.form.TIME[0],
END_TIME: data.form.TIME[1],
SAMPLINGNUMBER: "0",
TRAINTYPE_NAME: trainingTypeRef.value.getCurrentNode().NAME,
POSTTYPE_NAME: postTypeRef.value.getCurrentNode().NAME,
TRAINLEVEL_NAME: trainingLevelRef.value.getCurrentNode().NAME || "",
trainAllName:
trainingTypeRef.value.getCurrentNode().NAME +
"-" +
postTypeRef.value.getCurrentNode().NAME,
};
let resData;
!CLASS_ID
? (resData = await setClassManagementAdd(params))
: await setClassManagementEdit(params);
ElMessage.success("提交成功");
await router.replace({
path: !CLASS_ID
? "/training_process_management/class_management/student"
: type === "add"
? "/training_process_management/class_management/add"
: "/training_process_management/class_management/edit",
query: {
...route.query,
CLASS_ID: !CLASS_ID ? resData.CLASS_ID : CLASS_ID,
TRAINTYPE: data.form.TRAINTYPE,
EXAMINATION: data.form.EXAMINATION,
ISSTRENGTHEN: data.form.ISSTRENGTHEN,
},
});
},
{ atBegin: true }
);
const fnModifyExamTimes = async () => {
data.modifyExamTimesDialog.visible = true;
await nextTick();
data.modifyExamTimesDialog.form.NUMBEROFEXAMS = data.form.NUMBEROFEXAMS;
data.modifyExamTimesDialog.form.source = data.form.NUMBEROFEXAMS;
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,28 @@
<template>
<div>
<div v-if="!isEdit" class="mt-10 tc">
<el-button
@click="
router.replace({
path: '/training_process_management/class_management/student',
query: { ...route.query },
})
"
>
上一步
</el-button>
<el-button type="primary"> 完成 </el-button>
</div>
</div>
</template>
<script setup>
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
const { STATE } = route.query;
const isEdit = STATE && STATE !== "1";
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,61 @@
<template>
<el-dialog v-model="visible" title="延期" :on-close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="60px">
<el-form-item label="日期" prop="TIME">
<el-date-picker
v-model="form.TIME"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
:disabled-date="fnDisabledDate"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { ref } from "vue";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { setClassManagementDelay } from "@/request/training_process_management.js";
import { ElMessage } from "element-plus";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => {},
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const formRef = ref(null);
const rules = {
TIME: [{ required: true, message: "请选择日期", trigger: "change" }],
};
const fnDisabledDate = (time) => {
return time.getTime() <= new Date(form.value.TIME).getTime();
};
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = async () => {
await useFormValidate(formRef);
await setClassManagementDelay({ ...form.value });
ElMessage.success("延期成功");
fnClose();
emits("get-data");
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,107 @@
<template>
<el-dialog v-model="visible" title="考试详情" width="70%">
<el-divider content-position="left">考试学员信息</el-divider>
<div style="display: flex; justify-content: space-around">
<div>学员名字{{ info.USERNAME }}</div>
<div>考试时间{{ info.EXAMTIMEBEGIN + "至" + info.EXAMTIMEEND }}</div>
<div>得分{{ info.EXAMSCORE }}</div>
</div>
<el-divider content-position="left">试卷基本信息</el-divider>
<div style="display: flex; justify-content: space-around">
<div>试卷名称{{ info.EXAMNAME }}</div>
<div>试卷总分{{ info.PAPEREXAMSCORE }}</div>
<div>考试时长{{ info.ANSWERSHEETTIME }}分钟</div>
<div>通过分数{{ info.PASSSCORE }}</div>
</div>
<el-divider content-position="left">试卷内容信息</el-divider>
<div class="items mt-20 p-20">
<div
v-for="(item, index) in info.QUESTIONLIST"
:key="item.PAPER_QUESTION_ID"
class="item ptb-20"
>
<div class="mt-10">
{{ index + 1 }}.
<span v-if="item.QUESTIONTYPE === '1'"> () </span>
<span v-if="item.QUESTIONTYPE === '2'"> () </span>
<span v-if="item.QUESTIONTYPE === '3'"> () </span>
{{ item.QUESTIONDRY }}
<span class="ml-10">(题目分值{{ item.SCORE }})</span>
</div>
<div class="mt-10 ml-30">
<el-radio-group
v-if="item.QUESTIONTYPE === '1'"
disabled
:model-value="item.ANSWER"
>
<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'"
disabled
:model-value="item.ANSWER?.split('')"
>
<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'"
disabled
:model-value="item.ANSWER"
>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
</el-radio-group>
</div>
<div class="mt-10">答案{{ item.ANSWER }}</div>
<div class="mt-10">答案解析{{ item.DESCR }}</div>
<div class="mt-10">关联课件名称{{ item.COURSEWARENAME }}</div>
</div>
</div>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
info: {
type: Object,
required: true,
default: () => ({}),
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
</script>
<style scoped lang="scss">
.items {
border: 1px solid var(--el-border-color);
.item {
border-bottom: 1px dashed #ebeef5;
&:first-child {
padding-top: 0;
}
&:last-child {
border-bottom: none;
}
}
}
</style>

View File

@ -0,0 +1,102 @@
<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" />
</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
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60" fixed="left">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column label="试卷名称" prop="EXAMNAME" />
<el-table-column label="成绩" prop="EXAMSCORE" width="100" />
<el-table-column label="是否通过" width="100">
<template #default="{ row }">
{{ row.RESULT === "0" ? "未通过" : "" }}
{{ row.RESULT === "1" ? "通过" : "" }}
</template>
</el-table-column>
<el-table-column label="正确题数" prop="EXAMQUESTIONRIGHT" width="100" />
<el-table-column label="错误题数" prop="EXAMQUESTIONWRONG" width="100" />
<el-table-column label="正确率(%)" prop="ACCURACY" width="100" />
<el-table-column label="考试时间" width="300">
<template #default="{ row }">
{{ row.EXAMTIMEBEGIN + "至" + row.EXAMTIMEEND }}
</template>
</el-table-column>
<el-table-column label="操作" width="80px">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnExamDetails(row.STAGEEXAM_ID)"
>
考试详情
</el-button>
</template>
</el-table-column>
</layout-table>
<exam-details
v-model:visible="data.examDetailsDialog.visible"
:info="data.examDetailsDialog.info"
/>
</div>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import {
getClassManagementStudentExamRecordsList,
getClassManagementStudentExamRecordsView,
} from "@/request/training_process_management.js";
import { useRoute } from "vue-router";
import { serialNumber } from "@/assets/js/utils.js";
import { reactive } from "vue";
import ExamDetails from "./exam_details.vue";
const route = useRoute();
const { STUDENT_ID, CLASS_ID } = route.query;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassManagementStudentExamRecordsList, {
otherParams: { STUDENT_ID, CLASS_ID },
});
const data = reactive({
examDetailsDialog: {
visible: false,
info: {},
},
});
const fnExamDetails = async (STAGEEXAM_ID) => {
const resData = await getClassManagementStudentExamRecordsView({
STAGEEXAM_ID,
});
data.examDetailsDialog.info = resData.pd;
data.examDetailsDialog.visible = true;
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,74 @@
<template>
<div>
<el-form :model="searchForm" label-width="80px" @submit.prevent="fnGetData">
<el-row>
<el-col :span="6">
<el-form-item label="课程名称" prop="CURRICULUMNAME">
<el-input v-model="searchForm.CURRICULUMNAME" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="小节名称" prop="CHAPTERNAME">
<el-input v-model="searchForm.CHAPTERNAME" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="学习状态" prop="STATE">
<el-select v-model="searchForm.STATE">
<el-option
v-for="item in stateList"
: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="fnGetData"> </el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table :data="list" :show-pagination="false">
<el-table-column label="序号" width="60" type="index" />
<el-table-column label="课程名称" prop="CURRICULUMNAME" />
<el-table-column label="小节名称" prop="CHAPTERNAME" />
<el-table-column label="学习情况" width="150">
<template #default="{ row }">
<span v-if="row.FINISHTIME"></span>
<span v-else-if="row.CREATTIME">学习中</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="开始学习时间" prop="CREATTIME" width="150" />
<el-table-column label="完成时间" prop="FINISHTIME" width="150" />
<el-table-column label="最近观看时间" prop="OPERATTIME" width="150" />
</layout-table>
</div>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import { getClassManagementStudentLearningRecordsList } from "@/request/training_process_management.js";
import { useRoute } from "vue-router";
const route = useRoute();
const { STUDENT_ID, CLASS_ID } = route.query;
const stateList = [
{ ID: "-1", NAME: "未学习" },
{ ID: "0", NAME: "学习中" },
{ ID: "1", NAME: "已完成" },
];
const { list, searchForm, fnGetData } = useListData(
getClassManagementStudentLearningRecordsList,
{
otherParams: { STUDENT_ID, CLASS_ID },
usePagination: false,
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,70 @@
<template>
<el-dialog v-model="visible" title="修改考试次数" :on-close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="原考试次数" prop="source">
<el-input-number v-model="form.source" disabled />
</el-form-item>
<el-form-item label="新考试次数" prop="NUMBEROFEXAMS">
<el-input-number v-model="form.NUMBEROFEXAMS" :min="+form.source + 1" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { ref } from "vue";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { setClassManagementModifyExamTimes } from "@/request/training_process_management.js";
import { ElMessage, ElMessageBox } from "element-plus";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => {},
},
id: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const formRef = ref(null);
const rules = {
NUMBEROFEXAMS: [
{ required: true, message: "请填写考试次数", trigger: "blur" },
],
};
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = async () => {
await useFormValidate(formRef);
await ElMessageBox.confirm(
"确定要修改该班级的考试次数吗?考试已通过的学员不受影响",
{ type: "warning" }
);
await setClassManagementModifyExamTimes({
...form.value,
CLASS_ID: props.id,
});
ElMessage.success("修改成功");
fnClose();
emits("get-data");
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,358 @@
<template>
<div>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnGetDataTransfer"
>
<el-row>
<el-col :span="6">
<el-form-item label="姓名" prop="NAME">
<el-input v-model="searchForm.NAME" placeholder="请输入姓名" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="部门" prop="DEPARTMENT_ID">
<layout-department
v-model="searchForm.DEPARTMENT_ID"
@update:model-value="fnGetPost"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="岗位" prop="POST_ID">
<el-select v-model="searchForm.POST_ID">
<el-option
v-for="item in data.postList"
:key="item.POST_ID"
:label="item.NAME"
:value="item.POST_ID"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="学习状态" prop="STUDYSTATE">
<el-select v-model="searchForm.STUDYSTATE">
<el-option
v-for="item in learningStatus"
: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="STAGEEXAMSTATE">
<el-select v-model="searchForm.STAGEEXAMSTATE">
<el-option
v-for="item in examStatus"
: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="TIME">
<el-date-picker
v-model="searchForm.TIME"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-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="fnGetDataTransfer">
重置
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px" class="end">
<el-button
v-if="!isEdit"
type="primary"
@click="data.addStudentDialog.visible = true"
>
新增学员
</el-button>
<el-button
v-if="isEdit"
type="primary"
@click="fnGetLearningRecords"
>
导出学员学习记录
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<layout-table :data="list" :show-pagination="false" max-height="500">
<el-table-column label="序号" width="60" type="index" fixed="left" />
<el-table-column fixed width="100" prop="NAME" label="姓名" />
<el-table-column width="200" prop="DEPARTMENT_NAME" label="部门" />
<el-table-column width="200" prop="POST_NAME" label="岗位" />
<el-table-column width="200" prop="USER_ID_CARD" label="身份证号" />
<el-table-column width="200" prop="FILE_NUMBER" label="档案编号" />
<el-table-column width="100" label="人脸认证">
<template #default="{ row }">
{{ row.AUTHENTICATION === "0" ? "未认证" : "已认证" }}
</template>
</el-table-column>
<el-table-column width="100" prop="ALL_CLASSHOUR" label="要求学时" />
<el-table-column width="100" label="已完成学时">
<template #default="{ row }">
<template v-if="row.COMPLETE_CLASSHOUR">
{{
row.COMPLETE_CLASSHOUR === "0.0"
? 0
: parseFloat(row.COMPLETE_CLASSHOUR).toFixed(1)
}}
</template>
</template>
</el-table-column>
<el-table-column width="100" label="考试状态">
<template #default="{ row }">
{{ translationStatus(row.STAGEEXAMSTATE, examStatus) }}
</template>
</el-table-column>
<el-table-column width="100" label="学习状态">
<template #default="{ row }">
{{ translationStatus(row.STUDYSTATE, learningStatus) }}
</template>
</el-table-column>
<el-table-column prop="OPERATORNAME" label="操作人" />
<el-table-column width="150" prop="CREATTIME" label="入班时间" />
<el-table-column label="操作" width="150" fixed="right">
<template #default="{ row }">
<el-button
v-if="!isEdit"
type="primary"
text
link
@click="fnDelete(row.STUDENT_ID)"
>
从本班移除
</el-button>
<el-button
v-if="isEdit"
type="primary"
text
link
@click="
router.push({
path: '/training_process_management/class_management/student/learning_records',
query: { STUDENT_ID: row.STUDENT_ID, CLASS_ID },
})
"
>
学习记录
</el-button>
</template>
</el-table-column>
</layout-table>
<div v-if="!isEdit" class="mt-10 tc">
<el-button
@click="
router.replace({
path:
type === 'add'
? '/training_process_management/class_management/add'
: '/training_process_management/class_management/edit',
query: { ...route.query },
})
"
>
上一步
</el-button>
<el-button
type="primary"
@click="
router.replace({
path: '/training_process_management/class_management/curriculum',
query: { ...route.query },
})
"
>
下一步
</el-button>
</div>
<add-student
v-model:visible="data.addStudentDialog.visible"
v-model:form="data.addStudentDialog.form"
:select-list="list"
@get-data="fnGetDataTransfer"
/>
</div>
</template>
<script setup>
import LayoutDepartment from "@/components/department/index.vue";
import { getPostListAll } from "@/request/data_dictionary.js";
import { reactive } from "vue";
import { translationStatus } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import {
getClassManagementExportLearningRecords,
getClassManagementStudentList,
setClassManagementStudentDelete,
} from "@/request/training_process_management.js";
import { useRoute, useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import * as XLSX from "xlsx";
import { debounce } from "throttle-debounce";
import AddStudent from "./add_student.vue";
const route = useRoute();
const router = useRouter();
const { CLASS_ID, STATE, type } = route.query;
const isEdit = STATE && STATE !== "1";
const learningStatus = [
{ ID: "0", NAME: "未学习" },
{ ID: "1", NAME: "学习中" },
{ ID: "2", NAME: "已学完" },
{ ID: "3", NAME: "已完成" },
{ ID: "4", NAME: "未完成" },
{ ID: "5", NAME: "待评估" },
{ ID: "6", NAME: "评估未合格" },
];
const examStatus = [
{ ID: "0", NAME: "不考试" },
{ ID: "1", NAME: "待考试" },
{ ID: "2", NAME: "考试未通过" },
{ ID: "3", NAME: "考试通过" },
{ ID: "4", NAME: "未参加" },
];
const data = reactive({
postList: [],
addStudentDialog: {
visible: false,
form: {
releaseType: "",
personnelTypes: [],
},
},
});
const { list, searchForm, fnGetData } = useListData(
getClassManagementStudentList,
{
otherParams: { CLASS_ID },
usePagination: false,
callbackFn: (list, resData) => {
data.addStudentDialog.form.releaseType =
resData.classInfo.RELEASE_TYPE || "";
data.addStudentDialog.form.personnelTypes = resData.classInfo
.PERSONNEL_TYPES
? resData.classInfo.PERSONNEL_TYPES.split(",")
: [];
},
}
);
const fnGetDataTransfer = () => {
fnGetData({
START_TIME: searchForm.value.TIME?.[0],
END_TIME: searchForm.value.TIME?.[1],
});
};
const fnGetPost = async (DEPARTMENT_ID) => {
data.postList = [];
searchForm.value.POST_ID = "";
if (!DEPARTMENT_ID) return;
const resData = await getPostListAll({ DEPARTMENT_ID });
data.postList = resData.postList;
};
const fnGetLearningRecords = async () => {
await ElMessageBox.confirm("确定要导出查询出来所有的学习记录?", {
type: "warning",
});
const resData = await getClassManagementExportLearningRecords({
CLASS_ID,
...searchForm.value,
START_TIME: searchForm.value.TIME?.[0],
END_TIME: searchForm.value.TIME?.[1],
});
if (resData.varList.length > 0) fnExportLearningRecords(resData.varList);
else ElMessage.warning("没有学习记录");
};
const fnExportLearningRecords = (list) => {
const tableData = [
[
"序号",
"身份证",
"姓名",
"性别",
"手机号",
"部门",
"岗位",
"要求总学时",
"已完成学时",
"是否考试通过",
"考试分数",
"学习状态",
"班级名称",
],
];
list.forEach((item, index) => {
for (let i = 0; i < learningStatus.length; i++) {
if (learningStatus[i].ID === item.STUDYSTATE) {
item.STUDYSTATE = learningStatus[i].NAME;
break;
}
}
for (let i = 0; i < examStatus.length; i++) {
if (learningStatus[i].ID === item.STAGEEXAMSTATE) {
item.STAGEEXAMSTATE = learningStatus[i].NAME;
break;
}
}
if (item.ALL_CLASSHOUR === "0.0") item.ALL_CLASSHOUR = "0";
const COMPLETE_CLASSHOUR =
item.COMPLETE_CLASSHOUR === "0.0"
? 0
: parseFloat(item.COMPLETE_CLASSHOUR).toFixed(1);
tableData.push([
index + 1,
item.USER_ID_CARD,
item.NAME,
item.SEX,
item.PHONE,
item.DEPARTMENT_NAME,
item.POST_NAME,
item.ALL_CLASSHOUR,
COMPLETE_CLASSHOUR,
item.STAGEEXAMSTATE,
item.EXAMSCORE,
item.STUDYSTATE,
item.CLASS_NAME,
]);
});
const ws = XLSX.utils.aoa_to_sheet(tableData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "学员统计");
XLSX.writeFile(wb, "学员统计表.xlsx");
ElMessage.success("导出成功");
};
const fnDelete = debounce(
1000,
async (STUDENT_ID) => {
await ElMessageBox.confirm("确定要从本班移除该学员吗?", {
type: "warning",
});
await setClassManagementStudentDelete({ STUDENT_ID });
ElMessage.success("移除成功");
fnGetDataTransfer();
},
{ atBegin: type }
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,344 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPaginationTransfer"
>
<el-row>
<el-col :span="6">
<el-form-item label="班级编码" prop="CODE">
<el-input v-model="searchForm.CODE" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="班级名称" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="培训类型" prop="TRAINTYPE">
<layout-learning-train-type
v-model="searchForm.TRAINTYPE"
type="trainingType"
@update:model-value="
searchForm.POSTTYPE = '';
searchForm.TRAINLEVEL = '';
"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="行业类型" prop="INDUSTRY_END_ID">
<layout-learning-train-type
v-model="searchForm.INDUSTRY_END_ID"
type="industryType"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="岗位类型" prop="POSTTYPE">
<layout-learning-train-type
v-model="searchForm.POSTTYPE"
type="postType"
:search-value="searchForm.TRAINTYPE"
@update:model-value="searchForm.TRAINLEVEL = ''"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="培训级别" prop="TRAINLEVEL">
<layout-learning-train-type
v-model="searchForm.TRAINLEVEL"
type="trainingLevel"
:search-value="searchForm.POSTTYPE"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="班级状态" prop="STATE">
<el-select v-model="searchForm.STATE">
<el-option
v-for="item in classStatusList"
:key="item.ID"
:value="item.ID"
:label="item.NAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="开班时间" prop="TIME">
<el-date-picker
v-model="searchForm.TIME"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="结束时间" prop="TIME1">
<el-date-picker
v-model="searchForm.TIME1"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-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="fnResetPaginationTransfer">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<div class="mb-10">
<span class="mr-10">
班级总数<i>{{ data.clsNum }}</i>
</span>
<span>
班级总人次<i>{{ data.stuNum }}</i>
</span>
</div>
<layout-table
v-model:pagination="pagination"
:data="list"
@get-data="fnGetDataTransfer"
>
<el-table-column label="序号" width="60" fixed="left">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
label="班级名称"
prop="NAME"
show-overflow-tooltip
fixed="left"
/>
<el-table-column
label="班级编码"
prop="CODE"
width="150"
fixed="left"
/>
<el-table-column
label="培训类型"
prop="TRAININGTYPE_NAME"
width="150"
/>
<el-table-column label="行业类型" prop="POSTTYPE_NAME" width="150" />
<el-table-column
label="岗位类型"
prop="INDUSTRY_ALL_NAME"
width="200"
/>
<el-table-column label="培训等级" prop="TRAINLEVEL_NAME" width="150" />
<el-table-column label="负责人" prop="PRINCIPAL" width="150" />
<el-table-column label="培训开始时间" prop="START_TIME" width="150" />
<el-table-column label="培训结束时间" prop="END_TIME" width="150" />
<el-table-column label="涉及培训岗位数" prop="POSTNUM" width="150" />
<el-table-column label="学员人员数" prop="STUDENT_NUM" width="150" />
<el-table-column label="试卷类型" width="150">
<template #default="{ row }">
{{ translationStatus(row.STATE, classStatusList) }}
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path:
row.STATE === '1'
? '/training_process_management/class_management/edit'
: '/training_process_management/class_management/view',
query: {
STATE: row.STATE,
CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: row.STATE === '1' ? 'edit' : 'view',
},
})
"
>
{{ row.STATE === "1" ? "编辑" : "查看" }}
</el-button>
<el-button
type="primary"
text
link
@click="
router.push({
path: '/training_process_management/class_management/student',
query: {
STATE: row.STATE,
CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: 'edit',
},
})
"
>
学员
</el-button>
<el-button
type="primary"
text
link
@click="
router.push({
path: '/training_process_management/class_management/curriculum',
query: {
STATE: row.STATE,
CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: 'edit',
},
})
"
>
课程
</el-button>
<el-button
v-if="row.STATE === '1' && row.STUDYRECORDCNT === 0"
type="primary"
text
link
@click="fnDelete(row.CLASS_ID)"
>
删除
</el-button>
<el-button
v-if="row.STATE !== '1'"
type="primary"
text
link
@click="fnDelay(row.CLASS_ID, row.END_TIME)"
>
延期
</el-button>
</template>
</el-table-column>
<template #button>
<el-button
type="primary"
@click="
router.push({
path: '/training_process_management/class_management/add',
query: { type: 'add' },
})
"
>
新建培训任务
</el-button>
</template>
</layout-table>
</layout-card>
<delay
v-model:visible="data.delayDialog.visible"
v-model:form="data.delayDialog.form"
@get-data="fnResetPaginationTransfer"
/>
</div>
</template>
<script setup>
import useListData from "@/assets/js/useListData.js";
import { serialNumber, translationStatus } from "@/assets/js/utils.js";
import { useRouter } from "vue-router";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import {
getClassManagementList,
setClassManagementDelete,
} from "@/request/training_process_management.js";
import LayoutLearningTrainType from "@/components/learning_train_type/index.vue";
import { nextTick, reactive } from "vue";
import Delay from "./components/delay.vue";
const classStatusList = [
{ ID: "1", NAME: "未申请" },
{ ID: "4", NAME: "待开班" },
{ ID: "5", NAME: "培训中" },
{ ID: "6", NAME: "培训结束" },
];
const router = useRouter();
const data = reactive({
stuNum: 0,
clsNum: 0,
delayDialog: {
visible: false,
form: {
CLASS_ID: "",
TIME: "",
},
},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getClassManagementList, {
callbackFn: (list, resData) => {
data.stuNum = resData.stuNum;
data.clsNum = resData.clsNum;
},
});
const fnGetDataTransfer = () => {
fnGetData({
STARTTIME: searchForm.value.TIME?.[0],
ENDTIME: searchForm.value.TIME?.[1],
OVERSTARTTIME: searchForm.value.TIME1?.[0],
OVERENDTIME: searchForm.value.TIME1?.[1],
});
};
const fnResetPaginationTransfer = () => {
fnResetPagination({
STARTTIME: searchForm.value.TIME?.[0],
ENDTIME: searchForm.value.TIME?.[1],
OVERSTARTTIME: searchForm.value.TIME1?.[0],
OVERENDTIME: searchForm.value.TIME1?.[1],
});
};
const fnDelete = debounce(
1000,
async (CLASS_ID) => {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
await setClassManagementDelete({ CLASS_ID });
ElMessage.success("删除成功");
fnResetPaginationTransfer();
},
{ atBegin: true }
);
const fnDelay = async (CLASS_ID, END_TIME) => {
data.delayDialog.visible = true;
await nextTick();
data.delayDialog.form.CLASS_ID = CLASS_ID;
data.delayDialog.form.TIME = END_TIME;
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,38 @@
<template>
<div>
<layout-card>
<el-tabs v-model="active" @tab-change="fnTabChange">
<el-tab-pane label="学习记录" name="learning_records" lazy>
<learning-records />
</el-tab-pane>
<el-tab-pane label="考试记录" name="exam_records" lazy>
<exam-records />
</el-tab-pane>
</el-tabs>
</layout-card>
</div>
</template>
<script setup>
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
import { ref } from "vue";
import LearningRecords from "./components/learning_records.vue";
import ExamRecords from "./components/exam_records.vue";
const router = useRouter();
const route = useRoute();
const defaultName = "learning_records";
const active = ref(route.query.active || defaultName);
onBeforeRouteUpdate((to, from, next) => {
active.value = to.query.active || defaultName;
next();
});
const fnTabChange = (active) => {
router.replace({
path: "/training_process_management/class_management/student/learning_records",
query: { ...route.query, active },
});
};
</script>
<style scoped lang="scss"></style>

View File

@ -1,7 +1,382 @@
<template>
<layout-card>11</layout-card>
<layout-card>
<el-divider content-position="left">试卷基本信息</el-divider>
<el-form
ref="formRef"
:model="data.form"
:rules="rules"
label-width="100px"
>
<el-row>
<el-col :span="24">
<el-form-item label="试卷名称" prop="EXAMNAME">
<el-input v-model="data.form.EXAMNAME" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="总分数" prop="EXAMSCORE">
<el-input-number
v-model="data.form.EXAMSCORE"
:disabled="type !== 'add'"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="合格分数" prop="PASSSCORE">
<el-input-number v-model="data.form.PASSSCORE" />
</el-form-item>
</el-col>
<template v-if="type === 'add'">
<el-col :span="12">
<el-form-item label="下载模板">
<el-button type="primary" @click="fnDownloadTemplate">
下载
</el-button>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="上传试题" prop="fileList">
<layout-upload
v-model:file-list="data.form.fileList"
accept=".XLS,.XLSX,.xls,.xlsx"
:size="1"
>
<template #tip>
只能上传.XLS .XLSX格式的单个文件且文件大小不超过1MB
</template>
</layout-upload>
</el-form-item>
</el-col>
</template>
</el-row>
</el-form>
<div v-if="type !== 'add'">
<el-divider content-position="left">试卷题目信息</el-divider>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnGetData"
>
<el-row>
<el-col :span="6">
<el-form-item label="题目内容" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="题目类型" prop="QUESTIONTYPE">
<el-select v-model="searchForm.QUESTIONTYPE">
<el-option
v-for="item in questionTypeOptions"
: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="fnGetData">
重置
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px" class="end">
<el-button type="primary" @click="fnAddOrEdit({}, '')">
新增试题
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="items mt-20 p-20">
<div
v-for="(item, index) in list"
:key="item.PAPER_QUESTION_ID"
class="item ptb-20"
>
<div class="mt-10">
{{ index + 1 }}.
<span v-if="item.QUESTIONTYPE === '1'"> () </span>
<span v-if="item.QUESTIONTYPE === '2'"> () </span>
<span v-if="item.QUESTIONTYPE === '3'"> () </span>
{{ item.QUESTIONDRY }}
<span class="ml-10">(题目分值{{ item.SCORE }})</span>
</div>
<div class="mt-10 ml-30">
<el-radio-group
v-if="item.QUESTIONTYPE === '1'"
disabled
:model-value="item.ANSWER"
>
<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'"
disabled
:model-value="item.ANSWER?.split('')"
>
<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'"
disabled
:model-value="item.ANSWER"
>
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio>
</el-radio-group>
</div>
<div class="flex">
<div>
<div class="mt-10">答案{{ item.ANSWER }}</div>
<div class="mt-10">答案解析{{ item.DESCR }}</div>
<div class="mt-10">关联课件名称{{ item.COURSEWARENAME }}</div>
</div>
<div class="tr">
<el-button @click="fnAddOrEdit(item, index)">编辑</el-button>
<el-button @click="fnDelete(item.PAPER_QUESTION_ID, index)">
删除
</el-button>
</div>
</div>
</div>
</div>
</div>
<div class="mt-10 tc">
<el-button type="primary" @click="fnSubmit('normal')">
{{ buttonTextMap[type] }}
</el-button>
<el-button type="primary" @click="fnSubmit('draft')">
保存到草稿箱
</el-button>
</div>
<add-test-questions
:id="STAGEEXAMPAPERINPUT_ID"
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
:is-inherit="type === 'inherit'"
@get-data="fnGetDataInfo"
@confirm="fnAddTestQuestionsConfirm"
/>
</layout-card>
</template>
<script setup></script>
<script setup>
import { nextTick, reactive, ref } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import LayoutUpload from "@/components/upload/index.vue";
import { useRoute, useRouter } from "vue-router";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import {
setExamPaperManagementAdd,
setExamPaperManagementAddToDraft,
setExamPaperManagementEdit,
setExamPaperManagementInherit,
setExamPaperManagementTestQuestionsDelete,
} from "@/request/training_process_management.js";
import {
getExamPaperManagementTestQuestions,
getExamPaperManagementView,
} from "@/request/training_resource_management.js";
import useListData from "@/assets/js/useListData.js";
import { cloneDeep, sumBy } from "lodash-es";
import AddTestQuestions from "./components/add_test_questions.vue";
<style scoped lang="scss"></style>
const route = useRoute();
const router = useRouter();
const { type, STAGEEXAMPAPERINPUT_ID } = route.query;
const buttonTextMap = {
add: "立即创建",
edit: "保存修改",
inherit: "继承试卷",
};
const questionTypeOptions = [
{ value: "1", label: "单选题" },
{ value: "2", label: "多选题" },
{ value: "3", label: "判断题" },
];
const rules = {
EXAMNAME: [{ required: true, message: "请输入试卷名称", trigger: "blur" }],
EXAMSCORE: [{ required: true, message: "请输入总分数", trigger: "blur" }],
PASSSCORE: [{ required: true, message: "请输入合格分数", trigger: "blur" }],
fileList: [{ required: true, message: "请上传试题", trigger: "change" }],
};
const formRef = ref(null);
const data = reactive({
form: {
EXAMNAME: "",
EXAMSCORE: 0,
PASSSCORE: 0,
fileList: [],
},
addOrEditDialog: {
visible: false,
form: {
QUESTIONTYPE: "",
QUESTIONDRY: "",
OPTIONA: "",
OPTIONB: "",
OPTIONC: "",
OPTIOND: "",
ANSWER: "",
SCORE: 0,
LABEL_TYPE: "",
VIDEOCOURSEWARE_ID: "",
},
type: "",
index: "",
},
});
const { list, searchForm, fnGetData } = useListData(
getExamPaperManagementTestQuestions,
{
otherParams: { STAGEEXAMPAPERINPUT_ID },
immediate: false,
usePagination: false,
}
);
const fnGetDataInfo = async () => {
if (!STAGEEXAMPAPERINPUT_ID) return;
const resData = await getExamPaperManagementView({ STAGEEXAMPAPERINPUT_ID });
resData.pd.EXAMSCORE = +resData.pd.EXAMSCORE;
resData.pd.PASSSCORE = +resData.pd.PASSSCORE;
data.form = resData.pd;
fnGetData();
};
fnGetDataInfo();
const fnDownloadTemplate = async () => {
await ElMessageBox.confirm("确定要下载excel模板吗", {
type: "warning",
});
window.open(
import.meta.env[import.meta.env.DEV ? "VITE_PROXY" : "VITE_BASE_URL"] +
"question/downExcel"
);
};
const fnAddOrEdit = async (row, index) => {
data.addOrEditDialog.visible = true;
await nextTick();
data.addOrEditDialog.type = row.PAPER_QUESTION_ID ? "edit" : "add";
data.addOrEditDialog.index = index;
if (row.PAPER_QUESTION_ID) {
data.addOrEditDialog.form = cloneDeep(row);
data.addOrEditDialog.form.SCORE = +row.SCORE;
}
};
const fnAddTestQuestionsConfirm = (value) => {
if (data.addOrEditDialog.type === "add") list.value.push(value);
else list.value.splice(data.addOrEditDialog.index, 1, value);
data.form.EXAMSCORE = sumBy(list.value, (item) => +item.SCORE);
};
const fnDelete = debounce(
1000,
async (PAPER_QUESTION_ID, index) => {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
if (type === "inherit") {
list.value.splice(index, 1);
data.form.EXAMSCORE = sumBy(list.value, (item) => +item.SCORE);
ElMessage.success("删除成功");
} else {
await setExamPaperManagementTestQuestionsDelete({
PAPER_QUESTION_ID,
STAGEEXAMPAPERINPUT_ID,
});
ElMessage.success("删除成功");
await fnGetDataInfo();
}
},
{ atBegin: true }
);
const fnSubmit = debounce(
1000,
async (submitType) => {
await useFormValidate(formRef);
if (data.form.PASSSCORE > data.form.EXAMSCORE) {
ElMessage.warning("合格分数不能大于总分数");
return;
}
const formData = new FormData();
Object.keys(data.form).forEach((key) => {
formData.append(key, data.form[key]);
});
formData.delete("fileList");
if (data.form.fileList?.length > 0) {
formData.append("FFILENAME", data.form.fileList[0].name);
formData.append("FFILE", data.form.fileList[0].raw);
}
let resData;
if (submitType === "draft") {
resData = await setExamPaperManagementAddToDraft(formData);
} else if (submitType === "normal") {
if (type === "add") {
resData = await setExamPaperManagementAdd(formData);
}
if (type === "edit") {
resData = await setExamPaperManagementEdit(formData);
}
if (type === "inherit") {
await setExamPaperManagementInherit({
...data.form,
queList: JSON.stringify(list.value),
});
router.back();
return;
}
}
if (resData.code === 1) {
ElMessage.success("保存成功");
router.back();
} else {
ElMessage({
dangerouslyUseHTMLString: true,
message: resData.msg,
type: "error",
showClose: true,
duration: 10 * 1000,
});
}
},
{ atBegin: true }
);
</script>
<style scoped lang="scss">
.items {
border: 1px solid var(--el-border-color);
.item {
border-bottom: 1px dashed #ebeef5;
&:first-child {
padding-top: 0;
}
&:last-child {
border-bottom: none;
}
}
}
.flex {
display: flex;
align-items: center;
div {
flex: 1;
}
}
</style>

View File

@ -0,0 +1,248 @@
<template>
<el-dialog
v-model="visible"
:title="type === 'add' ? '新增' : '修改'"
@close="fnClose"
@open="fnQuestionTypeChange"
>
<el-form ref="formRef" :rules="rules" :model="form" label-width="110px">
<el-form-item label="试题类型" prop="QUESTIONTYPE">
<el-select v-model="form.QUESTIONTYPE" @change="fnQuestionTypeChange">
<el-option
v-for="item in questionTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="题干" prop="QUESTIONDRY">
<el-input
v-model="form.QUESTIONDRY"
type="textarea"
:autosize="{ minRows: 3 }"
/>
</el-form-item>
<template v-if="form.QUESTIONTYPE !== '3' && form.QUESTIONTYPE !== '4'">
<el-form-item label="选项A" prop="OPTIONA">
<el-input v-model="form.OPTIONA" />
</el-form-item>
<el-form-item label="选项B" prop="OPTIONB">
<el-input v-model="form.OPTIONB" />
</el-form-item>
<el-form-item label="选项C" prop="OPTIONC">
<el-input v-model="form.OPTIONC" />
</el-form-item>
<el-form-item label="选项D" prop="OPTIOND">
<el-input v-model="form.OPTIOND" />
</el-form-item>
</template>
<el-form-item label="答案" prop="ANSWER">
<el-select v-model="form.ANSWER">
<el-option
v-for="item in answerOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="分值" prop="SCORE">
<el-input-number v-model="form.SCORE" />
</el-form-item>
<el-form-item label="试题标签" prop="LABEL_TYPE">
<el-select v-model="form.LABEL_TYPE">
<el-option
v-for="item in testQuestionLabels"
:key="item.DICTIONARIES_ID"
:label="item.NAME"
:value="item.DICTIONARIES_ID"
/>
</el-select>
</el-form-item>
<el-form-item label="关联课件名称" prop="VIDEOCOURSEWARE_ID">
<el-select-v2
v-model="form.VIDEOCOURSEWARE_ID"
:options="associatedCoursewareName"
filterable
:props="{ label: 'COURSEWARENAME', value: 'VIDEOCOURSEWARE_ID' }"
/>
</el-form-item>
<el-form-item label="答案解析" prop="DESCR">
<el-input
v-model="form.DESCR"
type="textarea"
:autosize="{ minRows: 3 }"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { nextTick, ref } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
import { layoutFnGetTestQuestionLabels } from "@/assets/js/data_dictionary.js";
import {
getAssociatedCoursewareNameList,
setExamPaperManagementTestQuestionsAdd,
setExamPaperManagementTestQuestionsEdit,
} from "@/request/training_process_management.js";
import { cloneDeep } from "lodash-es";
const questionTypeOptions = [
{ value: "1", label: "单选题" },
{ value: "2", label: "多选题" },
{ value: "3", label: "判断题" },
];
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
id: {
type: String,
required: true,
default: "",
},
isInherit: {
type: Boolean,
required: true,
default: false,
},
});
const emits = defineEmits([
"update:visible",
"update:form",
"get-data",
"confirm",
]);
const { visible, form } = useVModels(props, emits);
const formRef = ref(null);
const answerOptions = ref([]);
const associatedCoursewareName = ref([]);
const rules = {
QUESTIONTYPE: [
{ required: true, message: "请选择试题类型", trigger: "change" },
],
QUESTIONDRY: [{ required: true, message: "请输入题干", trigger: "blur" }],
OPTIONA: [{ required: true, message: "请输入选项A", trigger: "blur" }],
OPTIONB: [{ required: true, message: "请输入选项B", trigger: "blur" }],
OPTIONC: [{ required: true, message: "请输入选项C", trigger: "blur" }],
OPTIOND: [{ required: true, message: "请输入选项D", trigger: "blur" }],
ANSWER: [{ required: true, message: "请选择答案", trigger: "change" }],
SCORE: [{ required: true, message: "请输入分值", trigger: "blur" }],
LABEL_TYPE: [
{ required: true, message: "请选择试题标签", trigger: "change" },
],
VIDEOCOURSEWARE_ID: [
{ required: true, message: "请选择关联课件名称", trigger: "change" },
],
};
const testQuestionLabels = await layoutFnGetTestQuestionLabels();
const fnGetAssociatedCoursewareNameList = async () => {
const resData = await getAssociatedCoursewareNameList();
associatedCoursewareName.value = resData.CourseWareNameList;
};
fnGetAssociatedCoursewareNameList();
const fnQuestionTypeChange = async () => {
await nextTick();
if (form.value.QUESTIONTYPE === "1") {
answerOptions.value = [
{ value: "A", label: "A" },
{ value: "B", label: "B" },
{ value: "C", label: "C" },
{ value: "D", label: "D" },
];
} else if (form.value.QUESTIONTYPE === "2") {
answerOptions.value = [
{ value: "AB", label: "AB" },
{ value: "AC", label: "AC" },
{ value: "AD", label: "AD" },
{ value: "BC", label: "BC" },
{ value: "BD", label: "BD" },
{ value: "CD", label: "CD" },
{ value: "ABC", label: "ABC" },
{ value: "ABD", label: "ABD" },
{ value: "ACD", label: "ACD" },
{ value: "BCD", label: "BCD" },
{ value: "ABCD", label: "ABCD" },
];
} else if (form.value.QUESTIONTYPE === "3") {
answerOptions.value = [
{ value: "A", label: "对" },
{ value: "B", label: "错" },
];
} else {
answerOptions.value = [];
}
};
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
if (form.value.QUESTIONTYPE === "3") {
form.value.OPTIONA = "对";
form.value.OPTIONB = "错";
form.value.OPTIONC = "";
form.value.OPTIOND = "";
}
let arr = [];
if (form.value.QUESTIONTYPE === "3") {
arr = ["#" + form.value.OPTIONA + "#", "#" + form.value.OPTIONB + "#"];
} else if (form.value.QUESTIONTYPE !== "4") {
arr = [
"#" + form.value.OPTIONA + "#",
"#" + form.value.OPTIONB + "#",
"#" + form.value.OPTIONC + "#",
"#" + form.value.OPTIOND + "#",
];
}
const s = arr.join(",") + ",";
for (let i = 0; i < arr.length - 1; i++) {
if (s.replace(arr[i] + ",", "").indexOf(arr[i]) > -1) {
ElMessage.warning("试题答案重复:" + arr[i].split("#").join(""));
return;
}
}
if (!props.isInherit) {
props.type === "add"
? await setExamPaperManagementTestQuestionsAdd({
...form.value,
STAGEEXAMPAPERINPUT_ID: props.id,
})
: await setExamPaperManagementTestQuestionsEdit({ ...form.value });
emits("get-data");
} else {
emits("confirm", cloneDeep(form.value));
}
ElMessage.success("操作成功");
fnClose();
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -93,7 +93,7 @@
查看
</el-button>
<el-button
v-if="row.SOURCETYPE === '1' || row.PAPERUSERCOUNT > 0"
v-if="row.SOURCETYPE === '2' || row.PAPERUSERCOUNT === 0"
type="primary"
text
link
@ -126,7 +126,7 @@
继承
</el-button>
<el-button
v-show="row.SOURCETYPE === '1' || row.PAPERUSERCOUNT > 0"
v-if="row.SOURCETYPE === '2' || row.PAPERUSERCOUNT === 0"
type="primary"
text
link

View File

@ -19,6 +19,10 @@
ref="trainingTypeRef"
v-model="data.form.TRAINTYPE"
type="trainingType"
@update:model-value="
data.form.POSTTYPE = '';
data.form.TRAINLEVEL = '';
"
/>
</el-form-item>
</el-col>
@ -38,6 +42,7 @@
v-model="data.form.POSTTYPE"
type="postType"
:search-value="data.form.TRAINTYPE"
@update:model-value="data.form.TRAINLEVEL = ''"
/>
</el-form-item>
</el-col>

View File

@ -30,6 +30,10 @@
<layout-learning-train-type
v-model="searchForm.TRAINTYPE"
type="trainingType"
@update:model-value="
searchForm.POSTTYPE = '';
searchForm.TRAINLEVEL = '';
"
/>
</el-form-item>
</el-col>
@ -47,6 +51,7 @@
v-model="searchForm.POSTTYPE"
type="postType"
:search-value="searchForm.TRAINTYPE"
@update:model-value="searchForm.TRAINLEVEL = ''"
/>
</el-form-item>
</el-col>

View File

@ -17,6 +17,7 @@
<layout-learning-train-type
v-model="searchForm.TRAINTYPE"
type="trainingType"
@update:model-value="searchForm.POSTTYPE = ''"
/>
</el-form-item>
</el-col>