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

dev
WenShiJun 2024-03-22 14:36:07 +08:00
commit 6c66a00624
54 changed files with 3967 additions and 236 deletions

View File

@ -89,6 +89,13 @@ export const layoutFnGetPersonnelType = async () => {
}); });
return ref(resData.list); return ref(resData.list);
}; };
// 签字人员类型
export const layoutFnGetSignUserType = async () => {
const resData = await getLevels({
DICTIONARIES_ID: "e0309e3085f04aa9b0e6a56e88ee8c2f",
});
return ref(resData.list);
};
// 清单类型 // 清单类型
export const layoutFnGetInventoryType = async () => { export const layoutFnGetInventoryType = async () => {
const resData = await getLevels({ const resData = await getLevels({
@ -181,6 +188,13 @@ export const layoutFnGetRiskClassification = async () => {
}); });
return ref(resData.list); return ref(resData.list);
}; };
// 排查项类型
export const layoutFnGetDrivingType = async () => {
const resData = await getLevels({
DICTIONARIES_ID: "5ef3a19edcb2435f8db94487834bbae3",
});
return ref(resData.list);
};
// 部门树 // 部门树
export const layoutFnGetDepartmentTree = async (params) => { export const layoutFnGetDepartmentTree = async (params) => {
const resData = await getDepartmentTree(params); const resData = await getDepartmentTree(params);

View File

@ -0,0 +1,12 @@
import { post } from "@/request/axios.js";
export const getSafetyDrivingCommitmentList = (params) =>
post("/drivingcommitment/listForSafetyDrivingCommitment", params); // 行车日志列表
export const setDrivingCommitmentDelete = (params) =>
post("/drivingcommitment/delete", params); // 行车日志删除
export const getSafetyDrivingCommitmentView = (params) =>
post("/drivingcommitment/goEdit", params); // 安全例会详情
export const setDrivingCommitmentAdd = (params) => post("/drivingcommitment/add", params); // 风险点单元添加
export const setDrivingCommitmentEdit = (params) => post("/drivingcommitment/edit", params); // 风险点单元修改

View File

@ -0,0 +1,12 @@
import { post } from "@/request/axios.js";
export const getSafetyDrivingTypeList = (params) =>
post("/drivingtype/listForSafetyDrivingType", params); // 行车日志列表
export const setDrivingTypeDelete = (params) =>
post("/drivingtype/delete", params); // 行车日志删除
export const getSafetyDrivingTypeView = (params) =>
post("/drivingtype/goEdit", params); // 安全例会详情
export const setDrivingTypeAdd = (params) => post("/drivingtype/add", params); // 风险点单元添加
export const setDrivingTypeEdit = (params) => post("/drivingtype/edit", params); // 风险点单元修改

View File

@ -21,7 +21,6 @@ export const getUserArchives = (params) =>
post("/archives/getUserArchives", params); // 一人一档-档案详情 post("/archives/getUserArchives", params); // 一人一档-档案详情
export const getLearningRecord = (params) => export const getLearningRecord = (params) =>
post("/archives/getLearningRecord", params); post("/archives/getLearningRecord", params);
export const getDict = (params) => post("/dictionaries/getLevels", params); // 获取人员类型
export const downloadFilesdetailword = (params) => export const downloadFilesdetailword = (params) =>
post("/archives/filesdetailword", params); // 一人一档:档案详情导出 post("/archives/filesdetailword", params); // 一人一档:档案详情导出
export const downloadAward = (params) => export const downloadAward = (params) =>
@ -125,4 +124,19 @@ export const getClassEvaluation = (params) =>
post("/class/getEvaluation", params); // 获取班级效果评估表信息 post("/class/getEvaluation", params); // 获取班级效果评估表信息
export const getStudentEvaluation = (params) => export const getStudentEvaluation = (params) =>
post("/student/getEvaluation", params); // 获取个人效果评估表信息 post("/student/getEvaluation", params); // 获取个人效果评估表信息
export const downloadClassEvaluation = (params) => post("class/hs", params); // 导出班级效果评估表信息 export const getReviewUserList = (params) => post("/reviewUser/list", params); // 获取审查人员列表
export const setReviewUserDelete = (params) =>
post("/reviewUser/delete", params); // 审查人员删除
export const setReviewUserAdd = (params) => post("/reviewUser/save", params); // 审查人员添加
export const setReviewUserEdit = (params) => post("/reviewUser/edit", params); // 审查人员编辑
export const getReviewUserGoEdit = (params) =>
post("/reviewUser/goEdit", params); // 获取审查人员编辑信息
export const getSignUserList = (params) =>
post("/trainedusersign/list", params); // 获取签字人员列表
export const setSignUserDelete = (params) =>
post("/trainedusersign/delete", params); // 签字人员删除
export const setSignUserAdd = (params) => post("/trainedusersign/save", params); // 签字人员添加
export const setSignUserEdit = (params) =>
post("/trainedusersign/edit", params); // 签字人员编辑
export const getSignUserGoEdit = (params) =>
post("/trainedusersign/goEdit", params); // 获取签字人员编辑信息

View File

@ -46,3 +46,34 @@ export const getClassManagementStudentExamRecordsList = (params) =>
post("/stageexam/list", params); // 班级管理学员考试记录列表 post("/stageexam/list", params); // 班级管理学员考试记录列表
export const getClassManagementStudentExamRecordsView = (params) => export const getClassManagementStudentExamRecordsView = (params) =>
post("/stageexam/findExam", params); // 班级管理学员考试记录查看 post("/stageexam/findExam", params); // 班级管理学员考试记录查看
export const getClassManagementCurriculumList = (params) =>
post("/classCurriculum/list", params); // 班级管理课程列表
export const setClassManagementCurriculumDelete = (params) =>
post("/classCurriculum/delete", params); // 班级管理课程删除
export const setClassManagementCurriculumAdd = (params) =>
post("/classCurriculum/addClassCurriculum", params); // 班级管理课程新增
export const getClassManagementCurriculumView = (params) =>
post("/classCurriculum/goEdit", params); // 班级管理课程查看
export const getClassManagementInvolvedInTrainingList = (params) =>
post("/curriculumpost/listClassCurPost", params); // 班级管理获取涉及培训岗位
export const getClassManagementInvolvedInTrainingDepartmentList = (params) =>
post("/classpost/listDepByClass", params); // 班级管理获取涉及培训岗位部门列表
export const getClassManagementInvolvedInTrainingPostList = (params) =>
post("/classpost/listPostByClassDep", params); // 班级管理获取涉及培训岗位岗位列表
export const setClassManagementInvolvedInTrainingAdd = (params) =>
post("/curriculumpost/saveClassCurPost", params); // 班级管理涉及培训岗位保存
export const getClassManagementExamPaperList = (params) =>
post("/classpost/listClassPost", params); // 班级管理试卷列表
export const setClassManagementExamPaperEffectEvaluationIsRelatedCourseware = (
params
) => post("/postpaper/verifyStrengthenPaper", params); // 班级管理试卷效果评估时是否关联课件
export const setClassManagementExamPaperAdd = (params) =>
post("/postpaper/addPostPaper", params); // 班级管理试卷添加
export const setClassManagementExamPaperEdit = (params) =>
post("/postpaper/editPostPaper", params); // 班级管理试卷修改
export const getClassManagementExamPaperCount = (params) =>
post("/postpaper/getQuestionCount", params); // 班级管理试卷数量
export const getClassManagementExamPaperHasTestPaper = (params) =>
post("/postpaper/getData", params); // 班级管理试卷获取是否有试卷
export const setClassManagementExamPaperBatchAdd = (params) =>
post("/postpaper/batchAddPostPaper", params); // 班级管理试卷批量添加自动生成试卷

View File

@ -3,7 +3,7 @@
v-model="visible" v-model="visible"
:append-to-body="true" :append-to-body="true"
:title="type === 'edit' ? '修改' : '新增'" :title="type === 'edit' ? '修改' : '新增'"
:on-close="fnClose" @close="fnClose"
> >
<el-form ref="formRef" :model="form" :rules="rules" label-width="220px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="220px">
<el-form-item label="日期" prop="DATE"> <el-form-item label="日期" prop="DATE">

View File

@ -3,7 +3,7 @@
v-model="visible" v-model="visible"
:append-to-body="true" :append-to-body="true"
:title="type === 'edit' ? '修改' : '新增'" :title="type === 'edit' ? '修改' : '新增'"
:on-close="fnClose" @close="fnClose"
> >
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="姓名" prop="NAME"> <el-form-item label="姓名" prop="NAME">

View File

@ -249,7 +249,7 @@
<td colspan="9"> <td colspan="9">
<el-checkbox-group v-model="data.PERSONNEL_TYPE" disabled> <el-checkbox-group v-model="data.PERSONNEL_TYPE" disabled>
<el-checkbox <el-checkbox
v-for="(item, index) in data.personnelTypeList" v-for="(item, index) in personnelTypeList"
:key="index" :key="index"
:label="item.DICTIONARIES_ID" :label="item.DICTIONARIES_ID"
> >
@ -431,7 +431,7 @@
<td colspan="9"> <td colspan="9">
<el-checkbox-group v-model="data.PERSONNEL_TYPE" disabled> <el-checkbox-group v-model="data.PERSONNEL_TYPE" disabled>
<el-checkbox <el-checkbox
v-for="(item, index) in data.personnelTypeList" v-for="(item, index) in personnelTypeList"
:key="index" :key="index"
:label="item.DICTIONARIES_ID" :label="item.DICTIONARIES_ID"
> >
@ -815,10 +815,10 @@ import { ElMessageBox } from "element-plus";
import { import {
getLearningRecord, getLearningRecord,
getUserArchives, getUserArchives,
getDict,
downloadFilesdetailword, downloadFilesdetailword,
} from "@/request/training_archive_management.js"; } from "@/request/training_archive_management.js";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { layoutFnGetPersonnelType } from "@/assets/js/data_dictionary.js";
const route = useRoute(); const route = useRoute();
const { const {
@ -846,13 +846,13 @@ const checkboxList = [
{ sort: 5, label: "培训考核记录" }, { sort: 5, label: "培训考核记录" },
{ sort: 6, label: "学习记录" }, { sort: 6, label: "学习记录" },
]; ];
const personnelTypeList = await layoutFnGetPersonnelType();
const data = reactive({ const data = reactive({
classInfo: {}, classInfo: {},
videoList: [], videoList: [],
official_seal_path: "", official_seal_path: "",
SIGNATURE_PATH: "", SIGNATURE_PATH: "",
PERSONNEL_TYPE: [PERSONNEL_TYPE], PERSONNEL_TYPE: [PERSONNEL_TYPE],
personnelTypeList: [],
paper: {}, paper: {},
learningRecord: {}, learningRecord: {},
faceList: [], faceList: [],
@ -924,15 +924,8 @@ const fnGetLearningRecord = async () => {
data.faceList = []; data.faceList = [];
} }
}; };
const fnGetDict = async () => {
const resData = await getDict({
DICTIONARIES_ID: "0b62f92b0b624aab8e89a77304a64d5e",
});
data.personnelTypeList = resData.list;
};
fnGetData(); fnGetData();
fnGetLearningRecord(); fnGetLearningRecord();
fnGetDict();
const fnExportDialogChangeShow = () => { const fnExportDialogChangeShow = () => {
data.exportDialog.visible = !data.exportDialog.visible; data.exportDialog.visible = !data.exportDialog.visible;
}; };

View File

@ -0,0 +1,75 @@
<template>
<el-dialog
v-model="visible"
:title="type === 'edit' ? '修改' : '新增'"
:before-close="fnClose"
>
<el-form ref="formRef" :rules="rules" :model="form" label-width="100px">
<el-form-item label="问询内容" prop="INQUIRYCONTENT">
<el-input
v-model="form.INQUIRYCONTENT"
type="textarea"
:autosize="{ minRows: 5 }"
/>
</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 { ref } from "vue";
import { useVModels } from "@vueuse/core";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
import {setDrivingCommitmentAdd, setDrivingCommitmentEdit} from "@/request/traffic_driving_commitment.js";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const rules = {
INQUIRYCONTENT: [
{ 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 setDrivingCommitmentAdd({ ...form.value })
: await setDrivingCommitmentEdit({ ...form.value });
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,132 @@
<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="INQUIRYCONTENT">
<el-input v-model="searchForm.INQUIRYCONTENT" />
</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
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
prop="INQUIRYCONTENT"
label="问询内容"
width="330"
/>
<el-table-column prop="INQUIRYCONCLUSION" label="问询结果" width="230" />
<el-table-column prop="CORP_NAME" label="经营企业" width="230" />
<el-table-column prop="TRANSPORTVEHICLE" label="经营类型" width="230" />
<el-table-column prop="CREATTIME" label="创建时间" width="130" />
<el-table-column prop="OPERATTIME" label="修改时间" width="130" />
<el-table-column label="操作" >
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnAddOrEdit(row.DRIVINGCOMMITMENT_ID, 'edit')"
>
修改
</el-button>
<el-button
type="danger"
text
link
@click="deleteItem(row.DRIVINGCOMMITMENT_ID)"
>
删除
</el-button>
</template>
</el-table-column>
<template #button>
<el-button
type="primary"
@click="fnAddOrEdit('', 'add')"
>
新增
</el-button>
</template>
</layout-table>
</layout-card>
<add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
@get-data="fnResetPagination"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import useListData from "@/assets/js/useListData.js";
import { nextTick,reactive } from "vue";
import Add from "./components/add.vue";
import {
getSafetyDrivingCommitmentList, getSafetyDrivingCommitmentView,
setDrivingCommitmentDelete,
} from "@/request/traffic_driving_commitment.js";
import { ElMessage, ElMessageBox } from "element-plus";
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getSafetyDrivingCommitmentList);
const data = reactive({
addOrEditDialog: {
visible: false,
type: "",
form: {
INQUIRYCONTENT: "",
},
},
});
const fnAddOrEdit = async (DRIVINGCOMMITMENT_ID, type) => {
data.addOrEditDialog.visible = true;
await nextTick();
data.addOrEditDialog.type = type;
if (type === "edit") {
const resData = await getSafetyDrivingCommitmentView({ DRIVINGCOMMITMENT_ID });
data.addOrEditDialog.form = resData.pd;
}
};
//
const deleteItem = async (value) => {
await ElMessageBox.confirm(`确定要删除吗?`, {
type: "warning",
});
await setDrivingCommitmentDelete({ DRIVINGCOMMITMENT_ID: value });
ElMessage.success("删除成功");
fnGetData();
};
</script>
<style scoped></style>

View File

@ -0,0 +1,229 @@
<template>
<layout-card>
<el-form
ref="formRef"
:model="data.form"
:rules="rules"
label-width="175px"
>
<el-divider content-position="left">添加</el-divider>
<el-row>
<el-col :span="8">
<el-form-item label="会议标题" prop="MEETING_TITLE">
<el-input
v-model="data.form.MEETING_TITLE"
placeholder="请输入会议标题"
/>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="会议类型" prop="MEETING_TYPE">
<el-select
v-model="data.form.MEETING_TYPE"
placeholder="请选择会议类型"
@change="handleMeetingTypeChange"
>
<el-option
v-for="item in relatedClassificationList"
:key="item.BIANMA"
:label="item.NAME"
:value="item.BIANMA"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="运输企业" prop="TRANSPORTATIONCOMPANY">
<el-input
v-model="data.form.TRANSPORTATIONCOMPANY"
placeholder="请输入运输企业"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="会议地点" prop="MEETING_ADDRESS">
<el-input
v-model="data.form.MEETING_ADDRESS"
placeholder="请输入会议地点"
/>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item prop="MEETING_DATE" label="会议时间">
<el-date-picker
type="daterange"
v-model="data.form.MEETING_DATE"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="主持人" prop="HOST_PERSON">
<el-input
v-model="data.form.HOST_PERSON"
placeholder="请输入主持人"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="记录人" prop="RECORDER">
<el-input v-model="data.form.RECORDER" placeholder="请输入记录人" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="从业身份" prop="PRACTITIONER_TYPE">
<el-checkbox-group
v-model="data.form.PRACTITIONER_TYPE"
@change="handleCheckedCitiesChange"
>
<el-checkbox v-for="city in cities" :key="city" :label="city">{{
city
}}</el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="会议附件" prop="fileList">
<layout-upload
v-model:file-list="data.form.fileList"
accept=".pdf,.mp4"
delete-to-server
:limit="9"
/>
</el-form-item>
</el-col>
<el-col :span="50">
<el-form-item label="会议记要" prop="MEETING_CONTENT">
<layout-editor
v-model="data.form.MEETING_CONTENT"
placeholder="请输入内容"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="tc mt-10">
<el-button type="primary" @click="fnSubmit"> </el-button>
</div>
</layout-card>
</template>
<script setup>
import {
layoutFnGetMEETINGTYPEClassification,
getUserListAll,
} from "@/request/safety_production_related.js";
import { addSafetyMeetingView } from "@/request/traffic_safety_meeting.js";
import { reactive, ref } from "vue";
import LayoutUpload from "@/components/upload/index.vue";
import LayoutEditor from "@/components/editor/index.vue";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
const formRef = ref(null);
const cities = [
"驾驶员",
"押运员",
"安全管理员",
"装卸员",
"安全负责人",
"其他",
"监控员",
];
const handleCheckedCitiesChange = () => {};
const rules = {
MEETING_TITLE: [
{ required: true, message: "请输入会议标题", trigger: "blur" },
],
MEETING_TYPE: [
{ required: true, message: "请选择会议类型", trigger: "change" },
],
TRANSPORTATIONCOMPANY: [
{ required: true, message: "请输入运输企业", trigger: "blur" },
],
MEETING_ADDRESS: [
{ required: true, message: "请输入会议地点", trigger: "blur" },
],
MEETING_DATE: [
{ required: true, message: "请选择会议时间", trigger: "change" },
],
HOST_PERSON: [{ required: true, message: "请输入主持人", trigger: "blur" }],
RECORDER: [{ required: true, message: "请输入记录人", trigger: "blur" }],
MEETING_CONTENT: [
{ required: true, message: "请输入会议记要", trigger: "blur" },
],
};
const fnGetUnitsList = async () => {
const resData = await getUserListAll({});
data.unitsList = resData.varList;
};
fnGetUnitsList();
const relatedClassificationTempList =
await layoutFnGetMEETINGTYPEClassification();
const relatedClassificationList = [];
JSON.parse(relatedClassificationTempList.value.zTreeNodes).forEach((e) => {
relatedClassificationList.push({ name: e.id, BIANMA: e.name });
});
const data = reactive({
form: {
MEETING_TITLE: "",
MEETING_TYPE: "",
TRANSPORTATIONCOMPANY: "",
MEETING_ADDRESS: "",
MEETING_DATE: "",
HOST_PERSON: "",
RECORDER: "",
fileList: [],
PRACTITIONER_TYPE: [],
NOTIFICATIONCONTENT: "",
},
});
const handleMeetingTypeChange = (value) => {
data.form.MEETING_TYPE = value;
};
const fnSubmit = async () => {
await useFormValidate(formRef);
const formData = new FormData();
Object.keys(data.form).forEach((key) => {
formData.append(key, data.form[key]);
});
formData.delete("fileList");
for (let i = 0; i < data.form.fileList.length; i++) {
if (data.form.fileList[i].raw)
formData.append("FFILE", data.form.fileList[i].raw);
}
try {
await addSafetyMeetingView(formData);
ElMessage.success("添加成功");
Object.keys(data.form).forEach((key) => {
if (Array.isArray(data.form[key])) {
data.form[key] = [];
} else {
data.form[key] = "";
}
});
} catch (error) {
ElMessage.error("添加失败");
}
};
</script>
<style scoped lang="scss">
.flexBox {
display: flex;
align-items: flex-end;
.addBtn {
margin-left: 12px;
}
}
</style>

View File

@ -0,0 +1,341 @@
<template>
<div>
<layout-card>
<el-row :gutter="20">
<el-col :span="24">
<el-descriptions :column="2" border>
<el-descriptions-item label="会议标题">
{{ detailItems.WAYBILLNUMBER }}
</el-descriptions-item>
<el-descriptions-item label="运输企业">
{{ detailItems.TRANSPORTATIONCOMPANY }}
</el-descriptions-item>
<el-descriptions-item label="运输任务">
<el-row :gutter="20">
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="运输车辆">
{{ detailItems.TRANSPORTVEHICLE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="运输性能">
{{ detailItems.TRANSPORTNATURE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="发车时间">
{{ detailItems.DEPARTURETIME }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="发车地点">
{{ detailItems.DEPARTUREPLACE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="车架号">
{{ detailItems.FRAMENUMBER }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="从业人员">
{{ detailItems.EMPLOYEES }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="收车时间">
{{ detailItems.ARRIVALTIME }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="收车地点">
{{ detailItems.ARRIVALPLACE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="天气情况">
{{ detailItems.WEATHERCONDITION }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="联系电话">
{{ detailItems.CONTACTPHONE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="额定载荷">
{{ detailItems.RATEDLOAD }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="实际载荷">
{{ detailItems.ACTUALLOAD }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="行车安全问询">
{{ detailItems.DRIVINGSAFETYINQUIRY }}
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="出车前检查">
<el-row :gutter="20">
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查人">
{{ detailItems.PREDEPARTUREINSPECTOR }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查时间">
{{ detailItems.PREDEPARTUREINSPECTIONTIME }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="故障处理">
{{ detailItems.PREDEPARTUREFAULTTREATMENT }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="出车结论">
{{ detailItems.DEPARTURECONCLUSION }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="出车前照片">
{{ detailItems.PREDEPARTUREPHOTO }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="出车前签字">
{{ detailItems.PREDEPARTURESIGNATURE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="行车中检查">
<el-row :gutter="20">
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查人">
{{ detailItems.INDRIVINGINSPECTOR }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查时间">
{{ detailItems.INSPECTIONTIMEWHILEDRIVING }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="故障处理">
{{ detailItems.INDRIVINGFAULTTREATMENT }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="行车中照片">
{{ detailItems.PHOTOSWHILEDRIVING }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="行车中签字">
{{ detailItems.SIGNINGWHILEDRIVING }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="收车后检查">
<el-row :gutter="20">
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查人">
{{ detailItems.POSTARRIVALINSPECTOR }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="检查时间">
{{ detailItems.POSTARRIVALINSPECTIONTIME }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="故障处理">
{{ detailItems.POSTARRIVALFAULTTREATMENT }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="收车后照片">
{{ detailItems.CHECKPHOTOS }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="收车后签字">
{{ detailItems.CHECKSIGNATURE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="交接班记录">
<el-row :gutter="20">
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="驾驶时长">
{{ detailItems.DRIVINGDURATION }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="时间区间">
{{ detailItems.TIMEINTERVAL }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="交接地点">
{{ detailItems.HANDOVERPLACE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="交接班人">
{{ detailItems.HANDOVERPERSON }}
</el-descriptions-item>
</el-descriptions>
</el-col>
<el-col :span="6">
<el-descriptions :column="1" border>
<el-descriptions-item label="接班图片">
{{ detailItems.RELIEFPICTURE }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</el-descriptions-item>
</el-descriptions>
<el-descriptions :column="1" border>
<el-descriptions-item label="安全负责人">
{{ detailItems.SAFETYOFFICER }}
</el-descriptions-item>
</el-descriptions>
</el-col>
</el-row>
</layout-card>
</div>
</template>
<script setup>
import { ref } from "vue";
import { getSafetyDrivingLogView } from "@/request/traffic_driving_log.js";
import { useRoute } from "vue-router";
const route = useRoute();
const { DRIVING_LOG_ID } = route.query;
const detailItems = ref({
WAYBILLNUMBER: "",
TRANSPORTATIONCOMPANY: "",
TRANSPORTVEHICLE: "",
TRANSPORTNATURE: "",
DEPARTURETIME: "",
DEPARTUREPLACE: "",
FRAMENUMBER: "",
EMPLOYEES: "",
ARRIVALTIME: "",
ARRIVALPLACE: "",
WEATHERCONDITION: "",
CONTACTPHONE: "",
ACTUALLOAD: "",
DRIVINGSAFETYINQUIRY: "",
DEPARTURECONCLUSION: "",
PREDEPARTUREINSPECTOR: "",
PREDEPARTUREINSPECTIONTIME: "",
PREDEPARTUREFAULTTREATMENT: "",
INDRIVINGINSPECTOR: "",
INSPECTIONTIMEWHILEDRIVING: "",
INDRIVINGFAULTTREATMENT: "",
POSTARRIVALINSPECTOR: "",
POSTARRIVALINSPECTIONTIME: "",
POSTARRIVALFAULTTREATMENT: "",
DRIVINGDURATION: "",
TIMEINTERVAL: "",
HANDOVERPLACE: "",
HANDOVERPERSON: "",
RELIEFPICTURE: "",
SAFETYOFFICER: "",
PREDEPARTUREPHOTO: "",
PREDEPARTURESIGNATURE: "",
PHOTOSWHILEDRIVING: "",
SIGNINGWHILEDRIVING: "",
CHECKPHOTOS: "",
CHECKSIGNATURE: "",
});
const fnGetData = async () => {
const response = await getSafetyDrivingLogView({ DRIVING_LOG_ID });
detailItems.value = response.pd;
};
fnGetData();
</script>
<style scoped></style>

View File

@ -0,0 +1,136 @@
<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="TRANSPORTCOMPANY">
<el-input v-model="searchForm.TRANSPORTCOMPANY" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="运输车辆" prop="TRANSPORTVEHICLE">
<el-input v-model="searchForm.TRANSPORTVEHICLE" />
</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
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
prop="REGISTRATIONNUMBER"
label="登记编号"
width="130"
/>
<el-table-column prop="DEPARTURESTATUS" label="出车状态" width="130" />
<el-table-column prop="DRIVINGCONDITION" label="行车状态" width="130" />
<el-table-column prop="TRANSPORTVEHICLE" label="运输车辆" width="130" />
<el-table-column prop="EMPLOYEES" label="从业人员" width="130" />
<el-table-column prop="CONTACTPHONE" label="联系电话" width="130" />
<el-table-column prop="WEATHERCONDITION" label="天气预报" width="130" />
<el-table-column prop="TRANSPORTNATURE" label="运输性质" width="130" />
<el-table-column prop="DEPARTURETIME" label="发车时间" />
<el-table-column prop="ARRIVALTIME" label="收车时间" />
<el-table-column prop="TRANSPORTCOMPANY" label="运输企业" />
<el-table-column label="操作" width="180">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/driving_inspections/driving_log/drivingLog_info',
query: {
DRIVING_LOG_ID: row.DRIVING_LOG_ID,
},
})
"
>
查看
</el-button>
<el-button
type="primary"
text
link
@click="
router.push({
path: '/driving_inspections/safety_meeting/add',
})
"
>
添加
</el-button>
<el-button
type="danger"
text
link
@click="deleteItem(row.DRIVING_LOG_ID)"
>
删除
</el-button>
</template>
</el-table-column>
</layout-table>
</layout-card>
<edit
v-model:visible="data.analysisDialog.visible"
:info="data.analysisDialog.info"
@get-data="fnResetPagination"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import useListData from "@/assets/js/useListData.js";
import { reactive } from "vue";
import {
getSafetyDrivingLogList,
setDrivingLogDelete,
} from "@/request/traffic_driving_log.js";
import router from "@/router/index.js";
import { ElMessage, ElMessageBox } from "element-plus";
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getSafetyDrivingLogList);
const data = reactive({
analysisDialog: {
visible: false,
info: {},
},
});
//
const deleteItem = async (value) => {
await ElMessageBox.confirm(`确定要删除吗?`, {
type: "warning",
});
await setDrivingLogDelete({ DRIVING_LOG_ID: value });
ElMessage.success("删除成功");
fnGetData();
};
</script>
<style scoped></style>

View File

@ -0,0 +1,97 @@
<template>
<el-dialog
v-model="visible"
:title="type === 'edit' ? '修改' : '新增'"
:before-close="fnClose"
>
<el-form ref="formRef" :rules="rules" :model="form" label-width="100px">
<el-form-item label="排查项类型" prop="CHECKTYPE_ID">
<el-select v-model="form.CHECKTYPE_ID">
<el-option
v-for="item in drivingTypeList"
:key="item.BIANMA"
:label="item.NAME"
:value="item.BIANMA"
/>
</el-select>
</el-form-item>
<el-form-item label="排查项名称" prop="CHECKITEMNAME">
<el-input v-model="form.CHECKITEMNAME"/>
</el-form-item>
<el-form-item label="排查项说明" prop="REMARKS">
<el-input
v-model="form.REMARKS"
type="textarea"
:autosize="{ minRows: 5 }"
/>
</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 { ref } from "vue";
import { useVModels } from "@vueuse/core";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage } from "element-plus";
import {setDrivingTypeAdd, setDrivingTypeEdit} from "@/request/traffic_driving_type.js";
import {layoutFnGetDrivingType} from "@/assets/js/data_dictionary.js";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "get-data"]);
const { visible, form } = useVModels(props, emits);
const rules = {
CHECKTYPE_ID: [
{ required: true, message: "排查项类型不能为空", trigger: "blur" },
],
CHECKITEMNAME: [
{ required: true, message: "排查项名称不能为空", trigger: "blur" },
],
REMARKS: [
{ 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 setDrivingTypeAdd({ ...form.value })
: await setDrivingTypeEdit({ ...form.value });
ElMessage.success("操作成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
const drivingTypeList = await layoutFnGetDrivingType();
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,145 @@
<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="CHECKTYPE_ID">
<el-select v-model="searchForm.CHECKTYPE_ID">
<el-option
v-for="item in drivingTypeList"
:key="item.BIANMA"
:label="item.NAME"
:value="item.BIANMA"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
prop="CHECKITEMNAME"
label="检查项名称"
width="330"
/>
<el-table-column prop="CHECKTYPE_NAME" label="检查项类型" width="130" />
<el-table-column prop="REMARKS" label="检查项说明" width="230" />
<el-table-column prop="CORP_NAME" label="经营企业" width="230" />
<el-table-column prop="TRANSPORTVEHICLE" label="经营类型" width="230" />
<el-table-column prop="CREATTIME" label="创建时间" width="130" />
<el-table-column prop="OPERATTIME" label="修改时间" width="130" />
<el-table-column label="操作" >
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnAddOrEdit(row.DRIVINGTYPE_ID, 'edit')"
>
修改
</el-button>
<el-button
type="danger"
text
link
@click="deleteItem(row.DRIVINGTYPE_ID)"
>
删除
</el-button>
</template>
</el-table-column>
<template #button>
<el-button
type="primary"
@click="fnAddOrEdit('', 'add')"
>
新增
</el-button>
</template>
</layout-table>
</layout-card>
<add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
@get-data="fnResetPagination"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils";
import useListData from "@/assets/js/useListData.js";
import { nextTick,reactive } from "vue";
import Add from "./components/add.vue";
import {
getSafetyDrivingTypeList, getSafetyDrivingTypeView,
setDrivingTypeDelete,
} from "@/request/traffic_driving_type.js";
import { ElMessage, ElMessageBox } from "element-plus";
import {layoutFnGetDrivingType} from "@/assets/js/data_dictionary.js";
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getSafetyDrivingTypeList);
const data = reactive({
addOrEditDialog: {
visible: false,
type: "",
form: {
CHECKITEMNAME: "",
REMARKS: "",
},
},
});
const fnAddOrEdit = async (DRIVINGTYPE_ID, type) => {
data.addOrEditDialog.visible = true;
await nextTick();
data.addOrEditDialog.type = type;
if (type === "edit") {
const resData = await getSafetyDrivingTypeView({ DRIVINGTYPE_ID });
data.addOrEditDialog.form = resData.pd;
}
};
//
const deleteItem = async (value) => {
await ElMessageBox.confirm(`确定要删除吗?`, {
type: "warning",
});
await setDrivingTypeDelete({ DRIVINGTYPE_ID: value });
ElMessage.success("删除成功");
fnGetData();
};
const drivingTypeList = await layoutFnGetDrivingType();
</script>
<style scoped></style>

View File

@ -0,0 +1,188 @@
<template>
<el-dialog
v-model="visible"
:append-to-body="true"
:title="reviewUserId ? (type === 'view' ? '查看' : '修改') : '添加'"
:on-close="fnClose"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-col :span="24">
<el-form-item label="姓名" prop="NAME">
<el-input v-model="form.NAME" :disabled="type === 'view'" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="工作部门" prop="DEPARTMENT_NAME">
<el-input
v-model="form.DEPARTMENT_NAME"
:disabled="type === 'view'"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="职务职称" prop="DUTIES">
<el-input v-model="form.DUTIES" :disabled="type === 'view'" />
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item label="签字" prop="SIGN_PICTURE">
<el-select v-model="data.SIGNTYPE" style="width: 100%">
<el-option
v-for="idx in data.options"
:key="idx.value"
:label="idx.label"
:value="idx.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-show="form.SIGN_PICTURE" :span="24">
<el-form-item label="本人签字" prop="SIGN_PICTURE">
<img
:src="FILE_URL + form.SIGN_PICTURE"
alt=""
width="700"
height="300"
/>
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item v-if="data.SIGNTYPE === '0'" prop="SIGN_PICTURE">
<vue-esign
ref="signRef"
:width="700"
:height="300"
:is-crop="false"
:is-clear-bg-color="false"
:line-width="6"
line-color="#000"
bg-color="#fff"
/>
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item v-if="data.SIGNTYPE === '1'" prop="SIGN_PICTURE">
<layout-upload
v-model:file-list="form.SIGN_PICTURE_2"
list-type="picture-card"
accept=".jpg,.jpeg,.png"
:limit="1"
delete-to-server
/>
</el-form-item>
</el-col>
</el-form>
<template #footer>
<el-button
v-if="type !== 'view' && (data.SIGNTYPE === '0' || form.SIGN_PICTURE)"
@click="
$refs.signRef.reset();
form.SIGN_PICTURE = '';
"
>重签</el-button
>
<el-button @click="fnClose"></el-button>
<el-button v-if="type !== 'view'" type="primary" @click="fnSubmit"
>确定</el-button
>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { reactive, ref, watchEffect } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import {
getReviewUserGoEdit,
setReviewUserAdd,
setReviewUserEdit,
} from "@/request/training_archive_management.js";
import { ElMessage } from "element-plus";
import LayoutUpload from "@/components/upload/index.vue";
import VueEsign from "vue-esign";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
reviewUserId: {
type: String,
required: true,
default: "",
},
});
const FILE_URL = import.meta.env.VITE_FILE_URL;
const emits = defineEmits(["update:visible", "update:form"]);
const { visible, form } = useVModels(props, emits);
const data = reactive({
SIGNTYPE: "",
options: [
{
value: "0",
label: "手写签字",
},
{
value: "1",
label: "上传图片",
},
],
});
const rules = {
NAME: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
DEPARTMENT_NAME: [
{ required: true, message: "工作部门不能为空", trigger: "blur" },
],
DUTIES: [{ required: true, message: "职务职称不能为空", trigger: "blur" }],
};
const formRef = ref(null);
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnGetData = async () => {
const resData = await getReviewUserGoEdit({
REVIEW_USER_ID: props.reviewUserId,
});
form.value = resData.pd;
};
watchEffect(() => {
if (props.reviewUserId) fnGetData();
});
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);
}
props.type === "add"
? await setReviewUserAdd(formData)
: await setReviewUserEdit(formData);
ElMessage.success("操作成功");
fnClose();
},
{
atBegin: true,
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,144 @@
<template>
<div>
<el-card>
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="6">
<el-form-item label="姓名" prop="KEYWORDS">
<el-input
v-model="searchForm.KEYWORDS"
placeholder="请输入姓名"
/>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label-width="10px">
<el-button type="primary" native-type="submit">搜索</el-button>
<el-button native-type="reset" @click="fnResetPagination">
重置
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<layout-card>
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="NAME" label="姓名" width="200" />
<el-table-column prop="DEPARTMENT_NAME" label="工作部门" width="200" />
<el-table-column prop="DUTIES" label="职务职称" width="200" />
<el-table-column prop="CLIENT" label="签字图片" width="200">
<template #default="{ row }">
<img
v-viewer
:src="FILE_URL + row.SIGN_PICTURE"
alt=""
width="80"
height="50"
/>
</template>
</el-table-column>
<el-table-column prop="CREATTIME" label="签字录入时间" width="200" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnAdd(row.REVIEW_USER_ID)"
>
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
type="primary"
text
link
@click="fnAdd(row.REVIEW_USER_ID, 'view')"
>
查看
</el-button>
<el-divider direction="vertical" />
<el-button
type="primary"
text
link
@click="fnDelete(row.REVIEW_USER_ID)"
>
删除
</el-button>
</template>
</el-table-column>
<template #button>
<el-button type="primary" @click="fnAdd('')"> </el-button>
</template>
</layout-table>
</layout-card>
<review-add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
:review-user-id="data.addOrEditDialog.REVIEW_USER_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 {
getReviewUserList,
setReviewUserDelete,
} from "@/request/training_archive_management.js";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import ReviewAdd from "./components/review_add.vue";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const tableRef = ref(null);
const data = reactive({
addOrEditDialog: {
visible: false,
form: {},
type: "",
REVIEW_USER_ID: "",
},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getReviewUserList);
const fnAdd = (REVIEW_USER_ID, type) => {
data.addOrEditDialog.visible = true;
data.addOrEditDialog.REVIEW_USER_ID = REVIEW_USER_ID;
data.addOrEditDialog.type = type;
};
const fnDelete = debounce(
1000,
async (REVIEW_USER_ID) => {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
await setReviewUserDelete({ REVIEW_USER_ID });
ElMessage.success("删除成功");
fnResetPagination();
},
{ atBegin: true }
);
</script>
<style scoped></style>

View File

@ -0,0 +1,207 @@
<template>
<el-dialog
v-model="visible"
:append-to-body="true"
:title="usersignid ? (type === 'view' ? '查看' : '修改') : '添加'"
:on-close="fnClose"
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-col :span="24">
<el-form-item label="姓名" prop="USERNAME">
<el-input v-model="form.USERNAME" :disabled="type === 'view'" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="签字人员类型" prop="USERSIGNTYPE">
<el-select
v-model="form.USERSIGNTYPE"
:disabled="type === 'view'"
style="width: 100%"
>
<el-option
v-for="item in signUserTypeList"
:key="item.DICTIONARIES_ID"
:label="item.NAME"
:value="item.DICTIONARIES_ID"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="职务职称" prop="DUTIES">
<el-input v-model="form.DUTIES" :disabled="type === 'view'" />
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item label="签字" prop="SIGN_PICTURE">
<el-select v-model="data.SIGNTYPE" style="width: 100%">
<el-option
v-for="idx in data.options"
:key="idx.value"
:label="idx.label"
:value="idx.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-show="form.SIGN_PICTURE" :span="24">
<el-form-item label="本人签字" prop="SIGN_PICTURE">
<img
:src="FILE_URL + form.SIGN_PICTURE"
alt=""
width="700"
height="300"
/>
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item v-if="data.SIGNTYPE === '0'" prop="SIGN_PICTURE">
<vue-esign
ref="signRef"
:width="700"
:height="300"
:is-crop="false"
:is-clear-bg-color="false"
:line-width="6"
line-color="#000"
bg-color="#fff"
/>
</el-form-item>
</el-col>
<el-col v-show="!form.SIGN_PICTURE" :span="24">
<el-form-item v-if="data.SIGNTYPE === '1'" prop="SIGN_PICTURE">
<layout-upload
v-model:file-list="form.SIGN_PICTURE_2"
list-type="picture-card"
accept=".jpg,.jpeg,.png"
:limit="1"
delete-to-server
/>
</el-form-item>
</el-col>
</el-form>
<template #footer>
<el-button
v-if="type !== 'view' && (data.SIGNTYPE === '0' || form.SIGN_PICTURE)"
@click="
$refs.signRef.reset();
form.SIGN_PICTURE = '';
"
>重签</el-button
>
<el-button @click="fnClose"></el-button>
<el-button v-if="type !== 'view'" type="primary" @click="fnSubmit"
>确定</el-button
>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { reactive, ref, watchEffect } from "vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import {
getSignUserGoEdit,
setSignUserAdd,
setSignUserEdit,
} from "@/request/training_archive_management.js";
import { ElMessage } from "element-plus";
import { layoutFnGetSignUserType } from "@/assets/js/data_dictionary.js";
import VueEsign from "vue-esign";
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: "",
},
usersignid: {
type: String,
required: true,
default: "",
},
});
const FILE_URL = import.meta.env.VITE_FILE_URL;
const emits = defineEmits(["update:visible", "update:form"]);
const { visible, form } = useVModels(props, emits);
const data = reactive({
SIGNTYPE: "",
options: [
{
value: "0",
label: "手写签字",
},
{
value: "1",
label: "上传图片",
},
],
});
const rules = {
USERNAME: [{ required: true, message: "姓名不能为空", trigger: "blur" }],
USERSIGNTYPE: [
{ required: true, message: "签字人员类型不能为空", trigger: "change" },
],
DEPARTMENT_NAME: [
{ required: true, message: "工作部门不能为空", trigger: "blur" },
],
DUTIES: [{ required: true, message: "职务职称不能为空", trigger: "blur" }],
};
const formRef = ref(null);
const signRef = ref(null);
const signUserTypeList = await layoutFnGetSignUserType();
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnGetData = async () => {
const resData = await getSignUserGoEdit({
REVIEW_USER_ID: props.reviewUserId,
});
form.value = resData.pd;
data.SIGNTYPE = data.pd.SIGNTYPE;
};
watchEffect(() => {
if (props.reviewUserId) fnGetData();
});
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 (data.SIGNTYPE === "") {
this.$message.warning("请签字");
return;
}
if (props.form.hideUpload[0].raw) {
formData.append("FFILE", props.form.hideUpload[0].raw);
}
props.type === "add"
? await setSignUserAdd(formData)
: await setSignUserEdit(formData);
ElMessage.success("操作成功");
fnClose();
},
{
atBegin: true,
}
);
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,111 @@
<template>
<div>
<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="150">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column prop="SIGNTYPENAME" label="签字人员类型" width="350" />
<el-table-column label="签字图片" width="350">
<template #default="{ row }">
<img
v-viewer
:src="FILE_URL + row.SIGN_PICTURE"
alt=""
width="80"
height="50"
/>
</template>
</el-table-column>
<el-table-column prop="CREATTIME" label="签字录入时间" width="350" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" text link @click="fnAdd(row.USERSIGNID)">
编辑
</el-button>
<el-divider direction="vertical" />
<el-button
type="primary"
text
link
@click="fnAdd(row.USERSIGNID, 'view')"
>
查看
</el-button>
<el-divider direction="vertical" />
<el-button
type="primary"
text
link
@click="fnDelete(row.USERSIGNID)"
>
删除
</el-button>
</template>
</el-table-column>
<template #button>
<el-button type="primary" @click="fnAdd('')"> </el-button>
</template>
</layout-table>
</layout-card>
<sign-add
v-model:visible="data.addOrEditDialog.visible"
v-model:form="data.addOrEditDialog.form"
:type="data.addOrEditDialog.type"
:usersignid="data.addOrEditDialog.USERSIGNID"
/>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import { reactive, ref } from "vue";
import {
getSignUserList,
setSignUserDelete,
} from "@/request/training_archive_management.js";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import SignAdd from "./components/sign_add.vue";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const tableRef = ref(null);
const data = reactive({
addOrEditDialog: {
visible: false,
form: {},
type: "",
USERSIGNID: "",
},
});
const { list, pagination, fnGetData, fnResetPagination } =
useListData(getSignUserList);
const fnAdd = (USERSIGNID, type) => {
data.addOrEditDialog.visible = true;
data.addOrEditDialog.USERSIGNID = USERSIGNID;
data.addOrEditDialog.type = type;
};
const fnDelete = debounce(
1000,
async (USERSIGNID) => {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
await setSignUserDelete({ USERSIGNID });
ElMessage.success("删除成功");
fnResetPagination();
},
{ atBegin: true }
);
</script>
<style scoped></style>

View File

@ -146,12 +146,13 @@
</template> </template>
<script setup> <script setup>
import { reactive, watchEffect } from "vue"; import { reactive, ref, watchEffect } from "vue";
import { ElMessageBox } from "element-plus"; import { ElMessageBox } from "element-plus";
import { getClassEvaluation } from "@/request/training_archive_management.js"; import { getClassEvaluation } from "@/request/training_archive_management.js";
import { useVModel } from "@vueuse/core"; import { useVModel } from "@vueuse/core";
import dayjs from "dayjs"; import dayjs from "dayjs";
import * as echarts from "echarts";
const props = defineProps({ const props = defineProps({
classId: { classId: {
type: String, type: String,
@ -159,9 +160,11 @@ const props = defineProps({
}, },
visible: { visible: {
type: Boolean, type: Boolean,
required: true,
default: false, default: false,
}, },
}); });
const chart = ref(null);
const visible = useVModel(props, "visible"); const visible = useVModel(props, "visible");
const data = reactive({ const data = reactive({
evaluationDialogForm: {}, evaluationDialogForm: {},
@ -174,9 +177,10 @@ const fnGetData = async () => {
CLASS_ID: props.classId, CLASS_ID: props.classId,
}); });
data.evaluationDialogForm = resData.pageData; data.evaluationDialogForm = resData.pageData;
data.count1 = data.pageData.count1; data.count1 = resData.pageData.count1;
data.count2 = data.pageData.count2; data.count2 = resData.pageData.count2;
data.count3 = data.pageData.count3; data.count3 = resData.pageData.count3;
fnGetPie();
}; };
const fnExport = async () => { const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" }); await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
@ -188,6 +192,59 @@ const fnExport = async () => {
watchEffect(() => { watchEffect(() => {
if (visible.value) fnGetData(); if (visible.value) fnGetData();
}); });
const fnGetPie = async () => {
const bar_dv = chart.value;
const count1 = data.count1;
const count2 = data.count2;
const count3 = data.count3;
if (bar_dv) {
const data = [];
if (count1 !== 0) {
data.push({ value: count1, name: "正确率100%" });
}
if (count2 !== 0) {
data.push({ value: count2, name: "正确率80%-100%" });
}
if (count3 !== 0) {
data.push({ value: count3, name: "正确率80%以下" });
}
const myChart = echarts.init(bar_dv);
myChart.setOption({
title: {
text: "人数",
left: "center",
},
tooltip: {
trigger: "item",
},
series: [
{
name: "人数",
type: "pie",
itemStyle: {
borderRadius: 10,
borderColor: "#fff",
borderWidth: 2,
},
radius: "80%",
silent: "ture",
data,
label: {
normal: {
show: true,
position: "inner",
formatter: "{b}\n{c}%",
textStyle: {
fontWeight: 500,
fontSize: "12",
},
},
},
},
],
});
}
};
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="检查照片" :on-close="fnClose"> <el-dialog v-model="visible" title="检查照片" @close="fnClose">
<el-form ref="formRef" :model="form" label-width="100px"> <el-form ref="formRef" :model="form" label-width="100px">
<el-row> <el-row>
<el-col v-if="writeresults" :span="24"> <el-col v-if="writeresults" :span="24">

View File

@ -2,8 +2,8 @@
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="type === 'add' ? '添加隐患' : '修改隐患'" :title="type === 'add' ? '添加隐患' : '修改隐患'"
:on-close="fnClose"
width="1200" width="1200"
@close="fnClose"
> >
<layout-hidden-add <layout-hidden-add
ref="hiddenAddRef" ref="hiddenAddRef"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" :title="title" :on-close="fnClose"> <el-dialog v-model="visible" :title="title" @close="fnClose">
<el-form ref="formRef" :model="form" label-width="110px"> <el-form ref="formRef" :model="form" label-width="110px">
<el-form-item label="标题" prop="biaoti"> <el-form-item label="标题" prop="biaoti">
<el-input v-model="form.biaoti" maxlength="31" /> <el-input v-model="form.biaoti" maxlength="31" />

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="导出" :on-close="fnClose"> <el-dialog v-model="visible" title="导出" @close="fnClose">
<el-checkbox <el-checkbox
v-model="checkAll" v-model="checkAll"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="配置" :on-close="fnClose"> <el-dialog v-model="visible" title="配置" @close="fnClose">
<layout-table <layout-table
ref="tableRef" ref="tableRef"
v-model:pagination="pagination" v-model:pagination="pagination"

View File

@ -2,7 +2,7 @@
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="type === 'add' ? '新增' : '修改'" :title="type === 'add' ? '新增' : '修改'"
:on-close="fnClose" @close="fnClose"
> >
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="文件名" prop="NAME"> <el-form-item label="文件名" prop="NAME">

View File

@ -2,7 +2,7 @@
<el-dialog <el-dialog
v-model="visible" v-model="visible"
:title="type === 'add' ? '新增' : '修改'" :title="type === 'add' ? '新增' : '修改'"
:on-close="fnClose" @close="fnClose"
> >
<el-form ref="formRef" :model="form" :rules="rules" label-width="170"> <el-form ref="formRef" :model="form" :rules="rules" label-width="170">
<el-form-item :label="labelName" prop="REMARKS"> <el-form-item :label="labelName" prop="REMARKS">

View File

@ -0,0 +1,339 @@
<template>
<layout-card>
<el-row :gutter="24">
<el-col :span="16">
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="8">
<el-form-item label="课程名称" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="8">
<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="8">
<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="8">
<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="8">
<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="8">
<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">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="CURRICULUMNAME"
label="课程名称"
/>
<el-table-column prop="CLASSHOUR" label="学时" width="100" />
<el-table-column
show-overflow-tooltip
prop="TRAININGTYPE_NAME"
label="培训类型"
/>
<el-table-column
show-overflow-tooltip
prop="INDUSTRY_ALL_NAME"
label="行业类型"
/>
<el-table-column
show-overflow-tooltip
prop="POSTTYPE_NAME"
label="岗位类型"
/>
<el-table-column
show-overflow-tooltip
prop="TRAINLEVEL_NAME"
label="培训等级"
/>
<el-table-column label="操作" align="center" width="60" fixed="right">
<template #default="{ row }">
<span v-if="row.ISUSE === '1'">使</span>
<el-button
v-else
type="primary"
text
link
@click="fnApply(row.CURRICULUM_ID)"
>
使用
</el-button>
</template>
</el-table-column>
</layout-table>
</el-col>
<el-col :span="8">
<template v-if="data.chapterList.length > 0">
<el-divider content-position="left">总学时</el-divider>
<el-row style="font-size: 14px">
<el-col :span="8">
所选课件总学时
<span>
{{
data.countClassHour === 0
? data.countClassHour
: data.countClassHour.toFixed(1)
}}
</span>
</el-col>
<el-col :span="16">
所选课件视频总时长
<span>
{{ secondConversion(data.countVideoTime) }}
</span>
</el-col>
<el-col :span="8" class="mt-10">
课程总学时
<span>{{ data.info.CLASSHOUR }}</span>
</el-col>
<el-col :span="16" class="mt-10">
课程视频总时长
<span>{{ secondConversion(data.info.VIDEOTIME) }}</span>
</el-col>
</el-row>
<el-divider content-position="left">章节编排</el-divider>
<div class="mb-5">
<el-button @click="fnSwitchSelectAll">
{{ data.isSelectAll ? "全不选" : "全选" }}
</el-button>
</div>
<el-scrollbar style="height: 310px">
<el-tree
ref="treeRef"
:data="data.chapterList"
:props="{ children: 'nodes', label: 'COURSEWARENAME' }"
class="directory_style"
default-expand-all
node-key="CHAPTER_ID"
show-checkbox
@check-change="fnCheckChange"
>
<template #default="{ data: item }">
<div class="directory_row">
<el-icon
v-if="item.COURSEWARENAME"
class="el-icon-video-camera"
size="18"
>
<video-camera />
</el-icon>
<span class="directory_name line-1">
{{ item.NAME || item.COURSEWARENAME }}
</span>
<span v-if="item.COURSEWARENAME" class="directory_type">
课件时长{{ secondConversion(item.VIDEOTIME) }}
</span>
<el-button
v-if="item.COURSEWARENAME"
type="primary"
size="small"
@click="fnPreview(item)"
>
预览
</el-button>
</div>
</template>
</el-tree>
</el-scrollbar>
</template>
<div v-else class="tc mt-50">暂未选择课程请点击左侧使用</div>
<layout-video
v-model:visible="data.videoDialog.visible"
:src="data.videoDialog.src"
/>
</el-col>
</el-row>
<div class="tc mt-10">
<el-button type="primary" @click="fnSubmit"></el-button>
</div>
</layout-card>
</template>
<script setup>
import LayoutLearningTrainType from "@/components/learning_train_type/index.vue";
import { secondConversion, serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import {
getCourseManagementList,
getCourseManagementView,
getPreviewingVideo,
} from "@/request/training_resource_management.js";
import { useRoute, useRouter } from "vue-router";
import { VideoCamera } from "@element-plus/icons-vue";
import LayoutVideo from "@/components/video/index.vue";
import { reactive, ref } from "vue";
import { sumBy } from "lodash-es";
import { debounce } from "throttle-debounce";
import { ElMessage } from "element-plus";
import { setClassManagementCurriculumAdd } from "@/request/training_process_management.js";
const route = useRoute();
const router = useRouter();
const { CLASS_ID } = route.query;
const { list, searchForm, pagination, fnGetData, fnResetPagination } =
useListData(getCourseManagementList, {
otherParams: { ISSELL: "1", CLASS_ID },
});
let checkedList = [];
const treeRef = ref(null);
const data = reactive({
chapterList: [],
countClassHour: 0,
countVideoTime: 0,
isSelectAll: false,
info: {},
videoDialog: {
visible: false,
src: "",
},
});
const fnApply = async (CURRICULUM_ID) => {
const resData = await getCourseManagementView({ CURRICULUM_ID });
data.chapterList = resData.chapterList;
data.info = resData.pd;
data.countClassHour = 0;
data.countVideoTime = 0;
data.isSelectAll = false;
checkedList = [];
};
const fnSwitchSelectAll = () => {
data.isSelectAll = !data.isSelectAll;
treeRef.value.setCheckedNodes(data.isSelectAll ? data.chapterList : []);
};
const fnCheckChange = (row, checked) => {
if (row.disabled) {
treeRef.value.setChecked(row, false, false);
return;
}
if (row.VIDEOCOURSEWARE_ID) {
if (checked) {
checkedList.push(row);
} else {
const index = checkedList.findIndex(
(item) => item.VIDEOCOURSEWARE_ID === row.VIDEOCOURSEWARE_ID
);
checkedList.splice(index, 1);
}
data.countClassHour = sumBy(checkedList, (item) => +item.CLASSHOUR);
data.countVideoTime = sumBy(checkedList, (item) => +item.VIDEOTIME);
}
};
const fnPreview = async ({ VIDEOCOURSEWARE_ID, VIDEOFILES, CURRICULUM_ID }) => {
const resData = await getPreviewingVideo({
VIDEOCOURSEWARE_ID,
VIDEOFILES,
CURRICULUM_ID,
});
data.videoDialog.src = JSON.stringify(resData.urlList);
data.videoDialog.visible = true;
};
const fnSubmit = debounce(
1000,
async () => {
const chapterList = [
...treeRef.value.getCheckedKeys(),
...treeRef.value.getHalfCheckedKeys(),
];
if (chapterList.length === 0) {
ElMessage.warning("请选择课程");
return;
}
await setClassManagementCurriculumAdd({
CLASS_ID,
CURRICULUM_ID: data.info.CURRICULUM_ID,
chapterList: chapterList.join(","),
});
ElMessage.success("保存成功");
router.back();
},
{ atBegin: true }
);
</script>
<style scoped lang="scss">
.directory_style {
font-size: 14px;
margin-bottom: 20px;
.el-icon-video-camera {
margin-right: 10px;
}
.directory_row {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 15px;
.directory_name {
flex: 1;
}
.directory_type {
flex: 1;
}
}
}
:deep {
.el-tree-node__content {
margin-bottom: 10px;
height: auto;
}
}
</style>

View File

@ -0,0 +1,211 @@
<template>
<el-dialog v-model="visible" title="平台试卷" @close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<el-form-item v-if="type !== 'batchAdd'" label="试卷名称" prop="EXAMNAME">
<el-input v-model="form.EXAMNAME" />
</el-form-item>
<el-form-item label="试卷分数" prop="EXAMSCORE">
<el-input-number v-model="form.EXAMSCORE" :min="0" />
</el-form-item>
<el-form-item label="合格分数" prop="PASSSCORE">
<el-input-number v-model="form.PASSSCORE" :min="0" />
</el-form-item>
<el-form-item prop="DANYUANTICOUNT">
<template #label>
单选题数
<span v-if="type !== 'batchAdd'">
可选题数{{ form.OPTIONALDANYUANTICOUNT }}
</span>
</template>
<el-input-number v-model="form.DANYUANTICOUNT" :min="0" />
</el-form-item>
<el-form-item label="单选分值" prop="DANXUANTINUMBER">
<el-input-number v-model="form.DANXUANTINUMBER" :min="0" />
</el-form-item>
<el-form-item prop="DUOXUANTICOUNT">
<template #label>
多选题数
<span v-if="type !== 'batchAdd'">
可选题数{{ form.OPTIONALDUOXUANTICOUNT }}
</span>
</template>
<el-input-number v-model="form.DUOXUANTICOUNT" :min="0" />
</el-form-item>
<el-form-item label="多选分值" prop="DUOXUANTINUMBER">
<el-input-number v-model="form.DUOXUANTINUMBER" :min="0" />
</el-form-item>
<el-form-item prop="PANDUITICOUNT">
<template #label>
判断题数
<span v-if="type !== 'batchAdd'">
可选题数{{ form.OPTIONALPANDUITICOUNT }}
</span>
</template>
<el-input-number v-model="form.PANDUITICOUNT" :min="0" />
</el-form-item>
<el-form-item label="判断分值" prop="PANDUITINUMBER">
<el-input-number v-model="form.PANDUITINUMBER" :min="0" />
</el-form-item>
<el-form-item label="考试时长(分钟)" prop="ANSWERSHEETTIME">
<el-input-number v-model="form.ANSWERSHEETTIME" :min="0" />
</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 { ElMessage, ElMessageBox } from "element-plus";
import { getClassManagementExamPaperHasTestPaper } from "@/request/training_process_management.js";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
form: {
type: Object,
required: true,
default: () => ({}),
},
type: {
type: String,
required: true,
default: "",
},
classPostId: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "update:form", "submit"]);
const { visible, form } = useVModels(props, emits);
const formRef = ref(null);
const rules = {
EXAMNAME: [{ required: true, message: "请输入试卷名称", trigger: "blur" }],
EXAMSCORE: [{ required: true, message: "请输入试卷分数", trigger: "blur" }],
PASSSCORE: [{ required: true, message: "请输入合格分数", trigger: "blur" }],
DANYUANTICOUNT: [
{ required: true, message: "请输入单选题数", trigger: "blur" },
],
DANXUANTINUMBER: [
{ required: true, message: "请输入单选分值", trigger: "blur" },
],
DUOXUANTICOUNT: [
{ required: true, message: "请输入多选题数", trigger: "blur" },
],
DUOXUANTINUMBER: [
{ required: true, message: "请输入多选分值", trigger: "blur" },
],
PANDUITICOUNT: [
{ required: true, message: "请输入判断题数", trigger: "blur" },
],
PANDUITINUMBER: [
{ required: true, message: "请输入判断分值", trigger: "blur" },
],
ANSWERSHEETTIME: [
{ required: true, message: "请输入考试时长(分钟)", trigger: "blur" },
],
};
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
const {
EXAMSCORE,
PASSSCORE,
DANYUANTICOUNT,
OPTIONALDANYUANTICOUNT,
DANXUANTINUMBER,
DUOXUANTICOUNT,
OPTIONALDUOXUANTICOUNT,
DUOXUANTINUMBER,
PANDUITICOUNT,
OPTIONALPANDUITICOUNT,
PANDUITINUMBER,
} = form.value;
if (props.type === "add" || props.type === "edit") {
if (DANYUANTICOUNT > OPTIONALDANYUANTICOUNT) {
ElMessage.warning("单选题题数不足");
return;
}
if (DUOXUANTICOUNT > OPTIONALDUOXUANTICOUNT) {
ElMessage.warning("多选题题数不足");
return;
}
if (PANDUITICOUNT > OPTIONALPANDUITICOUNT) {
ElMessage.warning("判断题题数不足");
return;
}
if (
DANYUANTICOUNT * DANXUANTINUMBER +
DUOXUANTICOUNT * DUOXUANTINUMBER +
PANDUITICOUNT * PANDUITINUMBER !==
EXAMSCORE * 1
) {
ElMessage.warning("所有题的分数相加必须等于试卷分数");
return;
}
if (PASSSCORE > EXAMSCORE) {
ElMessage.warning("合格分数不能大于试卷分数");
return;
}
emits("submit", form.value);
} else if (props.type === "batchAdd") {
if (
DANYUANTICOUNT * DANXUANTINUMBER +
DUOXUANTICOUNT * DUOXUANTINUMBER +
PANDUITICOUNT * PANDUITINUMBER !==
EXAMSCORE * 1
) {
ElMessage.warning("所有题的分数相加必须等于试卷分数");
return;
}
if (PASSSCORE > EXAMSCORE) {
ElMessage.warning("合格分数不能大于试卷分数");
return;
}
const resData = await getClassManagementExamPaperHasTestPaper({
CLASSPOST_IDS: props.classPostId,
});
if (resData.varList.length > 0) {
const depart_post = [];
for (let i = 0; i < resData.varList.length; i++) {
depart_post[i] =
"【" +
resData.varList[i].DEPARTMENT_NAME +
"-" +
resData.varList[i].POST_NAME +
"】";
}
await ElMessageBox.confirm(
"已选择的工种可能存在试卷,如继续操作可能造成" +
depart_post +
"试卷被覆盖,是否继续?",
{ type: "warning" }
);
emits("submit", form.value);
} else {
emits("submit", form.value);
}
}
fnClose();
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -185,17 +185,17 @@
<el-col :span="12"> <el-col :span="12">
<el-form-item label="是否人脸识别" prop="ISFACE"> <el-form-item label="是否人脸识别" prop="ISFACE">
<el-radio-group v-model="data.form.ISFACE" :disabled="isEdit"> <el-radio-group v-model="data.form.ISFACE" :disabled="isEdit">
<el-radio label="1"></el-radio> <el-radio value="1"></el-radio>
<el-radio label="0"></el-radio> <el-radio value="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col v-if="data.form.EXAMINATION === 1" :span="12"> <el-col v-if="data.form.EXAMINATION === 1" :span="12">
<el-form-item label="是否效果评估" prop="ISSTRENGTHEN"> <el-form-item label="是否效果评估" prop="ISSTRENGTHEN">
<el-radio-group v-model="data.form.ISSTRENGTHEN" :disabled="isEdit"> <el-radio-group v-model="data.form.ISSTRENGTHEN" :disabled="isEdit">
<el-radio label="2">强制</el-radio> <el-radio value="2">强制</el-radio>
<el-radio label="1"></el-radio> <el-radio value="1"></el-radio>
<el-radio label="0"></el-radio> <el-radio value="0"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -351,7 +351,6 @@ const fnSubmit = debounce(
query: { query: {
...route.query, ...route.query,
CLASS_ID: !CLASS_ID ? resData.CLASS_ID : CLASS_ID, CLASS_ID: !CLASS_ID ? resData.CLASS_ID : CLASS_ID,
TRAINTYPE: data.form.TRAINTYPE,
EXAMINATION: data.form.EXAMINATION, EXAMINATION: data.form.EXAMINATION,
ISSTRENGTHEN: data.form.ISSTRENGTHEN, ISSTRENGTHEN: data.form.ISSTRENGTHEN,
}, },

View File

@ -0,0 +1,168 @@
<template>
<el-dialog v-model="visible" title="配置试卷" width="60%">
<layout-table
ref="tableRef"
v-model:pagination="pagination"
:data="list"
row-key="STAGEEXAMPAPERINPUT_ID"
@get-data="fnGetData"
>
<el-table-column reserve-selection type="selection" width="55" />
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="DEPARTMENT_NAME"
label="部门"
/>
<el-table-column show-overflow-tooltip prop="POST_NAME" label="岗位" />
<el-table-column
show-overflow-tooltip
prop="CURRICULUMNAME"
label="涉及课程"
/>
<el-table-column label="试卷类型" width="120">
<template #default="{ row }">
{{ row.PAPERSELECTTYPE === "1" ? "平台试卷" : "" }}
{{ row.PAPERSELECTTYPE === "2" ? "自动生成试卷" : "" }}
</template>
</el-table-column>
<el-table-column label="操作" width="150">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
fnTestPaperType(
row.PAPERSELECTTYPE ? 'edit' : 'add',
row.CLASSPOST_ID,
row.PAPERSELECTTYPE ? row.POSTPAPER_ID : '',
row.CURRICULUM_IDS
)
"
>
{{ row.PAPERSELECTTYPE ? "编辑试卷" : "新增试卷" }}
</el-button>
<el-button
:disabled="!row.PAPERSELECTTYPE"
type="primary"
text
link
@click="fnView(row.STAGEEXAMPAPERINPUT_ID)"
>
查看
</el-button>
</template>
</el-table-column>
<template #button>
<el-button type="primary" @click="fnBatch"> </el-button>
</template>
</layout-table>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
<exam-paper-details
v-model:visible="data.viewDialog.visible"
:info="data.viewDialog.info"
/>
<test-paper-type
v-model:visible="data.testPaperTypeDialog.visible"
:type="data.testPaperTypeDialog.type"
:class-post-id="data.testPaperTypeDialog.CLASSPOST_ID"
:post-paper-id="data.testPaperTypeDialog.POSTPAPER_ID"
:curriculum-ids="data.testPaperTypeDialog.CURRICULUM_IDS"
:batch-data="data.testPaperTypeDialog.batchData"
@get-data="fnResetPagination"
/>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { useRoute } from "vue-router";
import useListData from "@/assets/js/useListData.js";
import { getClassManagementExamPaperList } from "@/request/training_process_management.js";
import { serialNumber } from "@/assets/js/utils.js";
import {
getExamPaperManagementTestQuestions,
getExamPaperManagementView,
} from "@/request/training_resource_management.js";
import { reactive, watchEffect } from "vue";
import ExamPaperDetails from "./exam_paper_details.vue";
import TestPaperType from "./test_paper_type.vue";
import { ElMessage } from "element-plus";
const route = useRoute();
const { CLASS_ID } = route.query;
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
const { list, pagination, fnGetData, fnResetPagination, tableRef } =
useListData(getClassManagementExamPaperList, {
otherParams: { CLASS_ID },
immediate: false,
});
const data = reactive({
viewDialog: {
visible: false,
info: {},
},
testPaperTypeDialog: {
visible: false,
type: "",
CLASSPOST_ID: "",
POSTPAPER_ID: "",
CURRICULUM_IDS: "",
batchData: [],
},
});
watchEffect(() => {
if (visible.value) fnResetPagination();
});
const fnView = async (STAGEEXAMPAPERINPUT_ID) => {
const { pd } = await getExamPaperManagementView({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info = pd;
const { varList } = await getExamPaperManagementTestQuestions({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info.testPaper = varList;
data.viewDialog.visible = true;
};
const fnTestPaperType = (type, CLASSPOST_ID, POSTPAPER_ID, CURRICULUM_IDS) => {
data.testPaperTypeDialog.type = type;
data.testPaperTypeDialog.CLASSPOST_ID = CLASSPOST_ID;
data.testPaperTypeDialog.POSTPAPER_ID = POSTPAPER_ID;
data.testPaperTypeDialog.CURRICULUM_IDS = CURRICULUM_IDS;
data.testPaperTypeDialog.batchData = [];
data.testPaperTypeDialog.visible = true;
};
const fnBatch = () => {
const selectionData = tableRef.value.getSelectionRows();
if (selectionData.length === 0) {
ElMessage.warning("请选择要添加的项");
return;
}
data.testPaperTypeDialog.CLASSPOST_ID = selectionData
.map((item) => item.CLASSPOST_ID)
.join(";");
data.testPaperTypeDialog.batchData = [...selectionData];
data.testPaperTypeDialog.type = "batchAdd";
data.testPaperTypeDialog.POSTPAPER_ID = "";
data.testPaperTypeDialog.CURRICULUM_IDS = "";
data.testPaperTypeDialog.visible = true;
};
</script>
<style scoped lang="scss"></style>

View File

@ -1,5 +1,94 @@
<template> <template>
<div> <div>
<div class="mb-10">
<el-button
v-if="!isEdit"
type="primary"
@click="
router.push({
path: '/training_process_management/class_management/curriculum/add',
query: { CLASS_ID },
})
"
>
新增课程
</el-button>
<el-button
v-if="!isEdit && EXAMINATION === '1'"
type="primary"
@click="data.configurationTestPaperDialogVisible = true"
>
配置试卷
</el-button>
<el-button
v-if="isEdit && EXAMINATION === '1'"
type="primary"
@click="data.examPaperRecordsDialogVisible = true"
>
试卷详情
</el-button>
</div>
<layout-table
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="CURRICULUMNAME"
label="课程名称"
/>
<el-table-column prop="ALL_DEPARTMENT_NAME" label="部门" />
<el-table-column prop="ALL_POST_NAME" label="岗位" />
<el-table-column prop="CLASSHOUR" label="要求完成总学时" width="150" />
<el-table-column label="视频累计时长" width="150">
<template #default="{ row }">
{{ secondConversion(row.VIDEOTIME) }}
</template>
</el-table-column>
<el-table-column prop="start_sum" label="上课学员数" width="150" />
<el-table-column prop="finsh_num" label="已完成学员数" width="150" />
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/training_process_management/class_management/curriculum/view',
query: { CLASSCURRICULUM_ID: row.CLASSCURRICULUM_ID },
})
"
>
查看
</el-button>
<el-button
v-if="!isEdit"
type="primary"
text
link
@click="fnInvolvedInTraining(row.CLASSCURRICULUM_ID)"
>
涉及培训岗位
</el-button>
<el-button
v-if="!isEdit"
type="primary"
text
link
@click="fnDelete(row.CLASSCURRICULUM_ID)"
>
删除
</el-button>
</template>
</el-table-column>
</layout-table>
<div v-if="!isEdit" class="mt-10 tc"> <div v-if="!isEdit" class="mt-10 tc">
<el-button <el-button
@click=" @click="
@ -13,16 +102,74 @@
</el-button> </el-button>
<el-button type="primary"> 完成 </el-button> <el-button type="primary"> 完成 </el-button>
</div> </div>
<involved-in-training
:id="data.involvedInTrainingDialog.CLASSCURRICULUM_ID"
v-model:visible="data.involvedInTrainingDialog.visible"
v-model:form="data.involvedInTrainingDialog.form"
@get-data="fnResetPagination"
/>
<exam-paper-records v-model:visible="data.examPaperRecordsDialogVisible" />
<configuration-test-paper
v-model:visible="data.configurationTestPaperDialogVisible"
/>
</div> </div>
</template> </template>
<script setup> <script setup>
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { secondConversion, serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import {
getClassManagementCurriculumList,
getClassManagementInvolvedInTrainingList,
setClassManagementCurriculumDelete,
} from "@/request/training_process_management.js";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import { reactive } from "vue";
import InvolvedInTraining from "./involved_in_training.vue";
import ExamPaperRecords from "./exam_paper_records.vue";
import ConfigurationTestPaper from "./configuration_test_paper.vue";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { STATE } = route.query; const { STATE, CLASS_ID, EXAMINATION } = route.query;
const isEdit = STATE && STATE !== "1"; const isEdit = STATE && STATE !== "1";
const { list, pagination, fnGetData, fnResetPagination } = useListData(
getClassManagementCurriculumList,
{
otherParams: { CLASS_ID },
}
);
const data = reactive({
involvedInTrainingDialog: {
visible: false,
CLASSCURRICULUM_ID: "",
form: { list: [] },
},
examPaperRecordsDialogVisible: false,
configurationTestPaperDialogVisible: false,
});
const fnInvolvedInTraining = async (CLASSCURRICULUM_ID) => {
const resData = await getClassManagementInvolvedInTrainingList({
CLASSCURRICULUM_ID,
});
data.involvedInTrainingDialog.CLASSCURRICULUM_ID = CLASSCURRICULUM_ID;
data.involvedInTrainingDialog.form.list = resData.varList;
data.involvedInTrainingDialog.visible = true;
};
const fnDelete = debounce(
1000,
async (CLASSCURRICULUM_ID) => {
await ElMessageBox.confirm("你确定要删除该课程吗?", {
type: "warning",
});
await setClassManagementCurriculumDelete({ CLASSCURRICULUM_ID });
ElMessage.success("删除成功");
fnResetPagination();
},
{ atBegin: true }
);
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss"></style>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="延期" :on-close="fnClose"> <el-dialog v-model="visible" title="延期" @close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="60px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="60px">
<el-form-item label="日期" prop="TIME"> <el-form-item label="日期" prop="TIME">
<el-date-picker <el-date-picker

View File

@ -1,18 +1,32 @@
<template> <template>
<el-dialog v-model="visible" title="考试详情" width="70%"> <el-dialog v-model="visible" title="考试详情" width="70%">
<el-divider content-position="left">考试学员信息</el-divider> <el-divider content-position="left">考试学员信息</el-divider>
<div style="display: flex; justify-content: space-around"> <el-descriptions :column="1" border>
<div>学员名字{{ info.USERNAME }}</div> <el-descriptions-item label="学员名字">
<div>考试时间{{ info.EXAMTIMEBEGIN + "至" + info.EXAMTIMEEND }}</div> {{ info.USERNAME }}
<div>得分{{ info.EXAMSCORE }}</div> </el-descriptions-item>
</div> <el-descriptions-item label="考试时间">
{{ info.EXAMTIMEBEGIN + "至" + info.EXAMTIMEEND }}
</el-descriptions-item>
<el-descriptions-item label="得分">
{{ info.EXAMSCORE }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">试卷基本信息</el-divider> <el-divider content-position="left">试卷基本信息</el-divider>
<div style="display: flex; justify-content: space-around"> <el-descriptions :column="2" border>
<div>试卷名称{{ info.EXAMNAME }}</div> <el-descriptions-item label="试卷名称">
<div>试卷总分{{ info.PAPEREXAMSCORE }}</div> {{ info.EXAMNAME }}
<div>考试时长{{ info.ANSWERSHEETTIME }}分钟</div> </el-descriptions-item>
<div>通过分数{{ info.PASSSCORE }}</div> <el-descriptions-item label="试卷总分">
</div> {{ info.PAPEREXAMSCORE }}
</el-descriptions-item>
<el-descriptions-item label="考试时长">
{{ info.ANSWERSHEETTIME }}分钟
</el-descriptions-item>
<el-descriptions-item label="通过分数">
{{ info.PASSSCORE }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">试卷内容信息</el-divider> <el-divider content-position="left">试卷内容信息</el-divider>
<div class="items mt-20 p-20"> <div class="items mt-20 p-20">
<div <div
@ -34,28 +48,28 @@
disabled disabled
:model-value="item.ANSWER" :model-value="item.ANSWER"
> >
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio> <el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio> <el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio label="C">C.{{ item.OPTIONC }}</el-radio> <el-radio value="C">C.{{ item.OPTIONC }}</el-radio>
<el-radio label="D">D.{{ item.OPTIOND }}</el-radio> <el-radio value="D">D.{{ item.OPTIOND }}</el-radio>
</el-radio-group> </el-radio-group>
<el-checkbox-group <el-checkbox-group
v-if="item.QUESTIONTYPE === '2'" v-if="item.QUESTIONTYPE === '2'"
disabled disabled
:model-value="item.ANSWER?.split('')" :model-value="item.ANSWER?.split('')"
> >
<el-checkbox label="A">A.{{ item.OPTIONA }}</el-checkbox> <el-checkbox value="A">A.{{ item.OPTIONA }}</el-checkbox>
<el-checkbox label="B">B.{{ item.OPTIONB }}</el-checkbox> <el-checkbox value="B">B.{{ item.OPTIONB }}</el-checkbox>
<el-checkbox label="C">C.{{ item.OPTIONC }}</el-checkbox> <el-checkbox value="C">C.{{ item.OPTIONC }}</el-checkbox>
<el-checkbox label="D">D.{{ item.OPTIOND }}</el-checkbox> <el-checkbox value="D">D.{{ item.OPTIOND }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
<el-radio-group <el-radio-group
v-if="item.QUESTIONTYPE === '3'" v-if="item.QUESTIONTYPE === '3'"
disabled disabled
:model-value="item.ANSWER" :model-value="item.ANSWER"
> >
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio> <el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio> <el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="mt-10">答案{{ item.ANSWER }}</div> <div class="mt-10">答案{{ item.ANSWER }}</div>

View File

@ -0,0 +1,30 @@
<template>
<el-dialog v-model="visible" title="试卷详情" width="70%">
<view-info :info="info" />
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import ViewInfo from "@/views/training_resource_management/exam_paper_management/components/view.vue";
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"></style>

View File

@ -0,0 +1,106 @@
<template>
<el-dialog v-model="visible" title="试卷记录" width="60%">
<layout-table
v-model:pagination="pagination"
:data="list"
@get-data="fnGetData"
>
<el-table-column label="序号" width="60">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="DEPARTMENT_NAME"
label="部门"
/>
<el-table-column show-overflow-tooltip prop="POST_NAME" label="岗位" />
<el-table-column
show-overflow-tooltip
prop="CURRICULUMNAME"
label="涉及课程"
/>
<el-table-column label="试卷类型" width="120">
<template #default="{ row }">
{{ row.PAPERSELECTTYPE === "1" ? "平台试卷" : "" }}
{{ row.PAPERSELECTTYPE === "2" ? "自动生成试卷" : "" }}
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnView(row.STAGEEXAMPAPERINPUT_ID)"
>
查看
</el-button>
</template>
</el-table-column>
</layout-table>
<template #footer>
<el-button @click="visible = false">关闭</el-button>
</template>
</el-dialog>
<exam-paper-details
v-model:visible="data.viewDialog.visible"
:info="data.viewDialog.info"
/>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { useRoute } from "vue-router";
import useListData from "@/assets/js/useListData.js";
import { getClassManagementExamPaperList } from "@/request/training_process_management.js";
import { serialNumber } from "@/assets/js/utils.js";
import {
getExamPaperManagementTestQuestions,
getExamPaperManagementView,
} from "@/request/training_resource_management.js";
import { reactive, watchEffect } from "vue";
import ExamPaperDetails from "./exam_paper_details.vue";
const route = useRoute();
const { CLASS_ID } = route.query;
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
const { list, pagination, fnGetData, fnResetPagination } = useListData(
getClassManagementExamPaperList,
{
otherParams: { CLASS_ID },
immediate: false,
}
);
const data = reactive({
viewDialog: {
visible: false,
info: {},
},
});
watchEffect(() => {
if (visible.value) fnResetPagination();
});
const fnView = async (STAGEEXAMPAPERINPUT_ID) => {
const { pd } = await getExamPaperManagementView({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info = pd;
const { varList } = await getExamPaperManagementTestQuestions({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info.testPaper = varList;
data.viewDialog.visible = true;
};
</script>
<style scoped lang="scss"></style>

View File

@ -0,0 +1,222 @@
<template>
<el-dialog v-model="visible" title="涉及培训岗位" @close="fnClose">
<el-form ref="formRef" :model="form" label-width="70px">
<el-row class="mb-10">
<el-col class="tr">
<el-button v-if="!isEdit" type="primary" @click="fnAdd">
添加
</el-button>
</el-col>
</el-row>
<el-row v-for="(item, index) in form.list" :key="item.id">
<el-col :span="9">
<el-form-item
:prop="'list.' + index + '.DEPARTMENT_ID'"
:label="'部门' + (index + 1)"
:rules="{
required: true,
message: '部门不能为空',
trigger: 'change',
}"
>
<el-select
:disabled="isEdit"
:model-value="item.DEPARTMENT_ID"
filterable
@change="fnPostChange($event, index)"
>
<el-option
v-for="item1 in departmentList"
:key="item1.DEPARTMENT_ID"
:value="item1.DEPARTMENT_ID"
:label="item1.NAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item
:prop="'list.' + index + '.POST_ID'"
:label="'岗位' + (index + 1)"
:rules="{
required: true,
message: '岗位不能为空',
trigger: 'change',
}"
>
<el-select
v-model="item.POST_ID"
:disabled="isEdit"
filterable
multiple
>
<el-option
v-for="item1 in item.postList"
:key="item1.POST_ID"
:value="item1.POST_ID"
:label="item1.NAME"
/>
</el-select>
</el-form-item>
</el-col>
<el-col v-if="!isEdit" :span="6">
<el-form-item label-width="10px">
<el-button type="primary" @click="fnSelectAll(index)">
岗位{{
!form.list[index].DEPARTMENT_ID
? "全选"
: form.list[index].POST_ID.length !==
form.list[index].postList.length
? "全选"
: "取消全选"
}}
</el-button>
<el-button
v-if="index !== 0"
type="danger"
@click="form.list.splice(index, 1)"
>
删除
</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button v-if="!isEdit" type="primary" @click="fnSubmit">
保存
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { useVModels } from "@vueuse/core";
import { useRoute } from "vue-router";
import { ref, watch } from "vue";
import {
getClassManagementInvolvedInTrainingDepartmentList,
getClassManagementInvolvedInTrainingPostList,
setClassManagementInvolvedInTrainingAdd,
} from "@/request/training_process_management.js";
import { verifyDuplicateSelection } from "@/assets/js/utils.js";
import { ElMessage } from "element-plus";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
const route = useRoute();
const { STATE, CLASS_ID } = route.query;
const isEdit = STATE && STATE !== "1";
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 departmentList = ref([]);
const formRef = ref(null);
const fnAdd = () => {
if (form.value.list.length >= departmentList.value.length) {
ElMessage.warning("无法添加新的培训岗位");
return;
}
form.value.list.push({
id: Math.random(),
DEPARTMENT_ID: "",
POST_ID: [],
postList: [],
});
};
const getDepartmentList = async () => {
const resData = await getClassManagementInvolvedInTrainingDepartmentList({
CLASS_ID,
});
departmentList.value = resData.varList;
};
getDepartmentList();
const fnPostChange = async (value, index) => {
await verifyDuplicateSelection(
form.value.list,
index,
"DEPARTMENT_ID",
value
);
form.value.list[index].POST_ID = [];
form.value.list[index].postList = [];
await fnGetPostList(value, index);
};
const fnGetPostList = async (DEPARTMENT_ID, index) => {
const resData = await getClassManagementInvolvedInTrainingPostList({
DEPARTMENT_ID,
CLASS_ID,
});
form.value.list[index].postList = resData.postList;
};
watch(
() => visible.value,
() => {
if (visible.value) {
if (form.value.list.length === 0) fnAdd();
else {
for (let i = 0; i < form.value.list.length; i++) {
form.value.list[i].id = Math.random();
form.value.list[i].postList = [];
fnGetPostList(form.value.list[i].DEPARTMENT_ID, i);
}
}
}
}
);
const fnSelectAll = (index) => {
if (!form.value.list[index].DEPARTMENT_ID) {
ElMessage.warning("请先选择部门");
return;
}
if (form.value.list[index].postList.length === 0) {
ElMessage.warning("当前部门下没有岗位");
return;
}
if (
form.value.list[index].POST_ID.length !==
form.value.list[index].postList.length
) {
form.value.list[index].POST_ID = form.value.list[index].postList.map(
(item) => item.POST_ID
);
} else form.value.list[index].POST_ID = [];
};
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
await setClassManagementInvolvedInTrainingAdd({
CLASSCURRICULUM_ID: props.id,
deptPostList: JSON.stringify(form.value.list),
});
ElMessage.success("保存成功");
fnClose();
emits("get-data");
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="修改考试次数" :on-close="fnClose"> <el-dialog v-model="visible" title="修改考试次数" @close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-form-item label="原考试次数" prop="source"> <el-form-item label="原考试次数" prop="source">
<el-input-number v-model="form.source" disabled /> <el-input-number v-model="form.source" disabled />

View File

@ -0,0 +1,230 @@
<template>
<el-dialog v-model="visible" title="平台试卷" width="70%" @close="fnClose">
<el-row :gutter="24">
<el-col :span="16">
<el-form
:model="searchForm"
label-width="100px"
@submit.prevent="fnResetPagination"
>
<el-row>
<el-col :span="8">
<el-form-item label="试卷名称" prop="KEYWORDS">
<el-input v-model="searchForm.KEYWORDS" />
</el-form-item>
</el-col>
<el-col :span="8">
<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">
<template #default="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column
show-overflow-tooltip
prop="EXAMNAME"
label="试卷名称"
/>
<el-table-column label="操作" width="100px">
<template #default="{ row }">
<el-button
type="primary"
text
link
@click="fnView(row.STAGEEXAMPAPERINPUT_ID)"
>
预览
</el-button>
<el-button type="primary" text link @click="fnApply(row)">
使用
</el-button>
</template>
</el-table-column>
</layout-table>
</el-col>
<el-col :span="8">
<el-divider content-position="left">考试设置</el-divider>
<el-form
ref="formRef"
:model="data.form"
:rules="rules"
label-position="top"
>
<el-form-item label="试卷名称">
<el-input :model-value="data.form.EXAMNAME" readonly />
</el-form-item>
<el-form-item label="试卷分数">
<el-input :model-value="data.form.EXAMSCORE" readonly />
</el-form-item>
<el-form-item label="合格分数">
<el-input :model-value="data.form.PASSSCORE" readonly />
</el-form-item>
<el-form-item label="考试时长(分)" prop="ANSWERSHEETTIME">
<el-input-number v-model="data.form.ANSWERSHEETTIME" :min="0" />
</el-form-item>
</el-form>
</el-col>
</el-row>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnSubmit"></el-button>
</template>
</el-dialog>
<exam-paper-details
v-model:visible="data.viewDialog.visible"
:info="data.viewDialog.info"
/>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import useListData from "@/assets/js/useListData.js";
import {
getExamPaperManagementList,
getExamPaperManagementTestQuestions,
getExamPaperManagementView,
} from "@/request/training_resource_management.js";
import { reactive, ref, watchEffect } from "vue";
import { serialNumber } from "@/assets/js/utils.js";
import ExamPaperDetails from "./exam_paper_details.vue";
import { debounce } from "throttle-debounce";
import useFormValidate from "@/assets/js/useFormValidate.js";
import { ElMessage, ElMessageBox } from "element-plus";
import {
getClassManagementExamPaperHasTestPaper,
setClassManagementExamPaperEffectEvaluationIsRelatedCourseware,
} from "@/request/training_process_management.js";
import { useRoute } from "vue-router";
const route = useRoute();
const { ISSTRENGTHEN } = route.query;
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
type: {
type: String,
required: true,
default: "",
},
classPostId: {
type: String,
required: true,
default: "",
},
});
const emits = defineEmits(["update:visible", "submit"]);
const visible = useVModel(props, "visible", emits);
const { list, searchForm, pagination, fnGetData, fnResetPagination } =
useListData(getExamPaperManagementList, { immediate: false });
watchEffect(() => {
if (visible.value) fnResetPagination();
});
const data = reactive({
viewDialog: {
visible: false,
info: {},
},
form: {
STAGEEXAMPAPERINPUT_ID: "",
EXAMNAME: "",
EXAMSCORE: "",
PASSSCORE: "",
ANSWERSHEETTIME: 60,
},
});
const formRef = ref(null);
const rules = {
ANSWERSHEETTIME: [
{ required: true, message: "请输入考试时长", trigger: "blur" },
],
};
const fnView = async (STAGEEXAMPAPERINPUT_ID) => {
const { pd } = await getExamPaperManagementView({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info = pd;
const { varList } = await getExamPaperManagementTestQuestions({
STAGEEXAMPAPERINPUT_ID,
});
data.viewDialog.info.testPaper = varList;
data.viewDialog.visible = true;
};
const fnApply = ({
STAGEEXAMPAPERINPUT_ID,
EXAMNAME,
EXAMSCORE,
PASSSCORE,
}) => {
data.form.STAGEEXAMPAPERINPUT_ID = STAGEEXAMPAPERINPUT_ID;
data.form.EXAMNAME = EXAMNAME;
data.form.EXAMSCORE = EXAMSCORE;
data.form.PASSSCORE = PASSSCORE;
};
const fnClose = () => {
formRef.value.resetFields();
data.form.STAGEEXAMPAPERINPUT_ID = "";
visible.value = false;
};
const fnSubmit = debounce(
1000,
async () => {
await useFormValidate(formRef);
if (!data.form.STAGEEXAMPAPERINPUT_ID) {
ElMessage.warning("请选择要使用的试卷");
return;
}
if (props.type === "add" || props.type === "edit") {
if (ISSTRENGTHEN === "1") {
await setClassManagementExamPaperEffectEvaluationIsRelatedCourseware({
STAGEEXAMPAPERINPUT_ID: data.form.STAGEEXAMPAPERINPUT_ID,
});
}
emits("submit", data.form);
} else if (props.type === "batchAdd") {
const resData = await getClassManagementExamPaperHasTestPaper({
CLASSPOST_IDS: props.classPostId,
});
if (resData.varList.length > 0) {
const depart_post = [];
for (let i = 0; i < resData.varList.length; i++) {
depart_post[i] =
"【" +
resData.varList[i].DEPARTMENT_NAME +
"-" +
resData.varList[i].POST_NAME +
"】";
}
await ElMessageBox.confirm(
"已选择的工种可能存在试卷,如继续操作可能造成" +
depart_post +
"试卷被覆盖,是否继续?",
{ type: "warning" }
);
emits("submit", data.form);
} else {
emits("submit", data.form);
}
}
fnClose();
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -202,13 +202,11 @@ import { reactive } from "vue";
import { translationStatus } from "@/assets/js/utils.js"; import { translationStatus } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js"; import useListData from "@/assets/js/useListData.js";
import { import {
getClassManagementExportLearningRecords,
getClassManagementStudentList, getClassManagementStudentList,
setClassManagementStudentDelete, setClassManagementStudentDelete,
} from "@/request/training_process_management.js"; } from "@/request/training_process_management.js";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import * as XLSX from "xlsx";
import { debounce } from "throttle-debounce"; import { debounce } from "throttle-debounce";
import AddStudent from "./add_student.vue"; import AddStudent from "./add_student.vue";
@ -274,71 +272,22 @@ const fnGetLearningRecords = async () => {
await ElMessageBox.confirm("确定要导出查询出来所有的学习记录?", { await ElMessageBox.confirm("确定要导出查询出来所有的学习记录?", {
type: "warning", type: "warning",
}); });
const resData = await getClassManagementExportLearningRecords({ window.location.href =
CLASS_ID, import.meta.env[import.meta.env.DEV ? "VITE_PROXY" : "VITE_BASE_URL"] +
...searchForm.value, "/student/exportStudentInfo?CLASS_ID=" +
START_TIME: searchForm.value.TIME?.[0], CLASS_ID +
END_TIME: searchForm.value.TIME?.[1], "&START_TIME=" +
}); searchForm.value.TIME?.[0] +
if (resData.varList.length > 0) fnExportLearningRecords(resData.varList); "&END_TIME=" +
else ElMessage.warning("没有学习记录"); searchForm.value.TIME?.[1] +
}; "&DEPARTMENT_ID=" +
const fnExportLearningRecords = (list) => { searchForm.value.DEPARTMENT_ID +
const tableData = [ "&POST_ID=" +
[ searchForm.value.POST_ID +
"序号", "&STUDYSTATE=" +
"身份证", searchForm.value.STUDYSTATE +
"姓名", "&STAGEEXAMSTATE=" +
"性别", searchForm.value.STAGEEXAMSTATE;
"手机号",
"部门",
"岗位",
"要求总学时",
"已完成学时",
"是否考试通过",
"考试分数",
"学习状态",
"班级名称",
],
];
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("导出成功"); ElMessage.success("导出成功");
}; };
const fnDelete = debounce( const fnDelete = debounce(

View File

@ -0,0 +1,202 @@
<template>
<el-dialog v-model="visible" title="试卷类型" @close="fnClose">
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="试卷类型" prop="PAPERSELECTTYPE">
<el-select v-model="form.PAPERSELECTTYPE">
<el-option value="1" label="平台试卷" />
<el-option value="2" label="自动生成试卷" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="fnClose"></el-button>
<el-button type="primary" @click="fnConfirm"></el-button>
</template>
</el-dialog>
<platform-test-paper
v-model:visible="data.platformTestPaperDialogVisible"
:type="type"
:class-post-id="classPostId"
@submit="fnSubmit"
/>
<automatically-generate-test-papers
v-model:visible="data.automaticallyGenerateTestPapersDialog.visible"
v-model:form="data.automaticallyGenerateTestPapersDialog.form"
:type="type"
:class-post-id="classPostId"
@submit="fnSubmit"
/>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { nextTick, reactive, ref } from "vue";
import useFormValidate from "@/assets/js/useFormValidate.js";
import PlatformTestPaper from "./platform_test_paper.vue";
import AutomaticallyGenerateTestPapers from "./automatically_generate_test_papers.vue";
import {
getClassManagementExamPaperCount,
setClassManagementExamPaperAdd,
setClassManagementExamPaperBatchAdd,
setClassManagementExamPaperEdit,
} from "@/request/training_process_management.js";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
const route = useRoute();
const { CLASS_ID } = route.query;
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
type: {
type: String,
required: true,
default: "",
},
classPostId: {
type: String,
required: true,
default: "",
},
postPaperId: {
type: String,
required: true,
default: "",
},
curriculumIds: {
type: String,
required: true,
default: "",
},
batchData: {
type: Array,
required: true,
default: () => [],
},
});
const emits = defineEmits(["update:visible", "get-data"]);
const visible = useVModel(props, "visible", emits);
const formRef = ref(null);
const form = ref({ PAPERSELECTTYPE: "" });
const rules = {
PAPERSELECTTYPE: {
required: true,
message: "请选择试卷类型",
trigger: "change",
},
};
const data = reactive({
platformTestPaperDialogVisible: false,
automaticallyGenerateTestPapersDialog: {
visible: false,
form: {
OPTIONALDANYUANTICOUNT: 0,
OPTIONALDUOXUANTICOUNT: 0,
OPTIONALPANDUITICOUNT: 0,
COURSEWAREIDS: "",
EXAMNAME: "",
EXAMSCORE: 0,
PASSSCORE: 0,
DANYUANTICOUNT: 0,
DANXUANTINUMBER: 0,
DUOXUANTICOUNT: 0,
DUOXUANTINUMBER: 0,
PANDUITICOUNT: 0,
PANDUITINUMBER: 0,
ANSWERSHEETTIME: 0,
},
},
});
const fnClose = () => {
formRef.value.resetFields();
visible.value = false;
};
const fnConfirm = async () => {
await useFormValidate(formRef);
if (form.value.PAPERSELECTTYPE === "1") {
data.platformTestPaperDialogVisible = true;
}
if (form.value.PAPERSELECTTYPE === "2") {
if (props.type === "batchAdd") {
data.automaticallyGenerateTestPapersDialog.visible = true;
await nextTick();
data.automaticallyGenerateTestPapersDialog.form.ANSWERSHEETTIME = 60;
} else {
if (!props.curriculumIds) {
ElMessage.warning("请配置涉及课程");
return;
}
await fnGetExamPaperCount();
}
}
};
const fnGetExamPaperCount = async () => {
const resData = await getClassManagementExamPaperCount({
CLASS_ID,
CURRICULUM_IDS: props.curriculumIds,
});
if (resData.message) {
ElMessage.warning(resData.message);
} else {
data.automaticallyGenerateTestPapersDialog.visible = true;
await nextTick();
const countMap = {
1: "OPTIONALDANYUANTICOUNT",
2: "OPTIONALDUOXUANTICOUNT",
3: "OPTIONALPANDUITICOUNT",
};
for (let i = 0; i < resData.questionCount.length; i++) {
const item = resData.questionCount[i];
data.automaticallyGenerateTestPapersDialog.form[
countMap[item.QUESTIONTYPE]
] = item.NUM;
}
data.automaticallyGenerateTestPapersDialog.form.COURSEWAREIDS =
JSON.stringify(resData.coursewareIds.COURSEWAREIDS);
data.automaticallyGenerateTestPapersDialog.form.ANSWERSHEETTIME = 60;
}
};
const fnSubmit = async (value) => {
const params = {
...value,
CLASS_ID,
PAPERSELECTTYPE: form.value.PAPERSELECTTYPE,
CLASSPOST_ID: props.classPostId,
POSTPAPER_ID: props.postPaperId,
};
if (
props.type === "add" ||
(props.type === "batchAdd" && form.value.PAPERSELECTTYPE === "1")
) {
await setClassManagementExamPaperAdd(params);
ElMessage.success("操作成功");
}
if (props.type === "edit") {
await setClassManagementExamPaperEdit(params);
ElMessage.success("操作成功");
}
if (props.type === "batchAdd" && form.value.PAPERSELECTTYPE === "2") {
const resData = await setClassManagementExamPaperBatchAdd({
...value,
PAPERSELECTTYPE: form.value.PAPERSELECTTYPE,
CLASS_ID,
batchdata: JSON.stringify(props.batchData),
});
if (resData.message) {
await ElMessageBox.confirm(resData.message.replace(/\n/g, "<br/>"), {
type: "warning",
dangerouslyUseHTMLString: true,
});
} else {
ElMessage.success("操作成功");
}
}
fnClose();
emits("get-data");
};
</script>
<style scoped lang="scss"></style>

View File

@ -175,7 +175,6 @@
CLASS_ID: row.CLASS_ID, CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION, EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN, ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: row.STATE === '1' ? 'edit' : 'view', type: row.STATE === '1' ? 'edit' : 'view',
}, },
}) })
@ -195,7 +194,6 @@
CLASS_ID: row.CLASS_ID, CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION, EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN, ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: 'edit', type: 'edit',
}, },
}) })
@ -215,7 +213,6 @@
CLASS_ID: row.CLASS_ID, CLASS_ID: row.CLASS_ID,
EXAMINATION: row.EXAMINATION, EXAMINATION: row.EXAMINATION,
ISSTRENGTHEN: row.ISSTRENGTHEN, ISSTRENGTHEN: row.ISSTRENGTHEN,
TRAINTYPE: row.TRAINTYPE,
type: 'edit', type: 'edit',
}, },
}) })

View File

@ -0,0 +1,166 @@
<template>
<layout-card>
<el-divider content-position="left">课程基本信息</el-divider>
<el-descriptions :column="1" border>
<el-descriptions-item label="课程名称">
{{ data.info.CURRICULUMNAME }}
</el-descriptions-item>
<el-descriptions-item label="培训类型">
{{ data.info.TYPENAME }}
</el-descriptions-item>
<el-descriptions-item label="课程描述">
{{ data.info.CURRICULUMINTRODUCE }}
</el-descriptions-item>
<el-descriptions-item label="课程封面">
<img
v-viewer
:src="VITE_FILE_URL + data.info.COVERPATH"
alt=""
width="100"
height="100"
/>
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">总学时</el-divider>
<el-descriptions :column="2" border>
<el-descriptions-item label="所选课件总学时">
{{
data.selectClassHour === 0
? data.selectClassHour
: data.selectClassHour.toFixed(1)
}}
</el-descriptions-item>
<el-descriptions-item label="所选课件视频总时长">
{{ secondConversion(data.selectVideoTime) }}
</el-descriptions-item>
<el-descriptions-item label="课程总学时">
{{ data.info.CLASSHOUR }}
</el-descriptions-item>
<el-descriptions-item label="课程视频总时长">
{{ secondConversion(data.info.VIDEOTIME) }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">课程目录</el-divider>
<el-tree
:data="data.chapterList"
:props="{ children: 'nodes', label: 'COURSEWARENAME' }"
class="directory_style"
default-expand-all
>
<template #default="{ data: item }">
<div class="directory_row">
<el-icon
v-if="item.COURSEWARENAME"
class="el-icon-video-camera"
size="18"
>
<video-camera />
</el-icon>
<span class="directory_name line-1">
{{ item.NAME || item.COURSEWARENAME }}
</span>
<span v-if="item.COURSEWARENAME" class="directory_type">
课件时长{{ secondConversion(item.VIDEOTIME) }}
</span>
<el-button
v-if="item.COURSEWARENAME"
type="primary"
size="small"
@click="fnPreview(item)"
>
预览
</el-button>
</div>
</template>
</el-tree>
<layout-video
v-model:visible="data.videoDialog.visible"
:src="data.videoDialog.src"
/>
</layout-card>
</template>
<script setup>
import { useRoute } from "vue-router";
import { getPreviewingVideo } from "@/request/training_resource_management.js";
import { reactive } from "vue";
import { secondConversion } from "@/assets/js/utils.js";
import { VideoCamera } from "@element-plus/icons-vue";
import LayoutVideo from "@/components/video/index.vue";
import { getClassManagementCurriculumView } from "@/request/training_process_management.js";
const route = useRoute();
const { CLASSCURRICULUM_ID } = route.query;
const VITE_FILE_URL = import.meta.env.VITE_FILE_URL;
const data = reactive({
info: {},
chapterList: [],
selectClassHour: 0,
selectVideoTime: 0,
videoDialog: {
visible: false,
src: "",
},
});
const fnGetData = async () => {
const resData = await getClassManagementCurriculumView({
CLASSCURRICULUM_ID,
});
data.info = resData.pd;
data.chapterList = resData.chapterList;
fnSumSelectTime(data.chapterList);
};
fnGetData();
const fnSumSelectTime = (list) => {
list.forEach((item) => {
data.selectClassHour += Number(item.CLASSHOUR || 0);
data.selectVideoTime += Number(item.VIDEOTIME || 0);
if (item.nodes && item.nodes.length > 0) {
fnSumSelectTime(item.nodes);
}
});
};
const fnPreview = async ({ VIDEOCOURSEWARE_ID, VIDEOFILES, CURRICULUM_ID }) => {
const resData = await getPreviewingVideo({
VIDEOCOURSEWARE_ID,
VIDEOFILES,
CURRICULUM_ID,
});
data.videoDialog.src = JSON.stringify(resData.urlList);
data.videoDialog.visible = true;
};
</script>
<style scoped lang="scss">
.directory_style {
font-size: 14px;
margin-bottom: 20px;
.el-icon-video-camera {
margin-right: 10px;
}
.directory_row {
flex-basis: 600px;
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 15px;
.directory_name {
flex: 1;
}
.directory_type {
flex: 1;
}
}
}
:deep {
.el-tree-node__content {
margin-bottom: 10px;
height: auto;
}
}
</style>

View File

@ -112,28 +112,28 @@
disabled disabled
:model-value="item.ANSWER" :model-value="item.ANSWER"
> >
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio> <el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio> <el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
<el-radio label="C">C.{{ item.OPTIONC }}</el-radio> <el-radio value="C">C.{{ item.OPTIONC }}</el-radio>
<el-radio label="D">D.{{ item.OPTIOND }}</el-radio> <el-radio value="D">D.{{ item.OPTIOND }}</el-radio>
</el-radio-group> </el-radio-group>
<el-checkbox-group <el-checkbox-group
v-if="item.QUESTIONTYPE === '2'" v-if="item.QUESTIONTYPE === '2'"
disabled disabled
:model-value="item.ANSWER?.split('')" :model-value="item.ANSWER?.split('')"
> >
<el-checkbox label="A">A.{{ item.OPTIONA }}</el-checkbox> <el-checkbox value="A">A.{{ item.OPTIONA }}</el-checkbox>
<el-checkbox label="B">B.{{ item.OPTIONB }}</el-checkbox> <el-checkbox value="B">B.{{ item.OPTIONB }}</el-checkbox>
<el-checkbox label="C">C.{{ item.OPTIONC }}</el-checkbox> <el-checkbox value="C">C.{{ item.OPTIONC }}</el-checkbox>
<el-checkbox label="D">D.{{ item.OPTIOND }}</el-checkbox> <el-checkbox value="D">D.{{ item.OPTIOND }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
<el-radio-group <el-radio-group
v-if="item.QUESTIONTYPE === '3'" v-if="item.QUESTIONTYPE === '3'"
disabled disabled
:model-value="item.ANSWER" :model-value="item.ANSWER"
> >
<el-radio label="A">A.{{ item.OPTIONA }}</el-radio> <el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio label="B">B.{{ item.OPTIONB }}</el-radio> <el-radio value="B">B.{{ item.OPTIONB }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="flex"> <div class="flex">

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog v-model="visible" title="选择课件" width="90%" :on-close="fnClose"> <el-dialog v-model="visible" title="选择课件" width="90%" @close="fnClose">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="type === 'multiple' ? 16 : 24"> <el-col :span="type === 'multiple' ? 16 : 24">
<el-form <el-form

View File

@ -37,7 +37,7 @@
> >
<video-camera /> <video-camera />
</el-icon> </el-icon>
<span class="directory_name"> <span class="directory_name line-1">
{{ item.NAME || item.COURSEWARENAME }} {{ item.NAME || item.COURSEWARENAME }}
</span> </span>
<span v-if="item.COURSEWARENAME" class="directory_type"> <span v-if="item.COURSEWARENAME" class="directory_type">
@ -106,28 +106,26 @@ const fnPreview = async (VIDEOCOURSEWARE_ID, VIDEOFILES) => {
margin-bottom: 20px; margin-bottom: 20px;
.el-icon-video-camera { .el-icon-video-camera {
display: inline-block;
vertical-align: middle;
margin-right: 10px; margin-right: 10px;
} }
.directory_row { .directory_row {
flex-basis: 600px;
display: flex;
justify-content: space-between;
align-items: center;
margin-right: 15px;
.directory_name { .directory_name {
width: 260px; flex: 1;
display: inline-block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: middle;
} }
.directory_type { .directory_type {
width: 200px; flex: 1;
display: inline-block;
vertical-align: middle;
} }
} }
} }
:deep { :deep {
.el-tree-node__content { .el-tree-node__content {
margin-bottom: 10px; margin-bottom: 10px;

View File

@ -0,0 +1,92 @@
<template>
<el-divider content-position="left">试卷基本信息</el-divider>
<el-descriptions :column="2" border>
<el-descriptions-item label="试卷名称" :span="2">
{{ info.EXAMNAME }}
</el-descriptions-item>
<el-descriptions-item label="合格分数">
{{ info.PASSSCORE }}
</el-descriptions-item>
<el-descriptions-item label="总分数">
{{ info.EXAMSCORE }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">试卷题目信息</el-divider>
<div class="items mt-20 p-20">
<div
v-for="(item, index) in info.testPaper"
: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 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'"
disabled
:model-value="item.ANSWER?.split('')"
>
<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'"
disabled
:model-value="item.ANSWER"
>
<el-radio value="A">A.{{ item.OPTIONA }}</el-radio>
<el-radio value="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>
<script setup>
defineProps({
info: {
type: Object,
required: true,
default: () => ({}),
},
});
</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

@ -1,67 +1,6 @@
<template> <template>
<layout-card> <layout-card>
<el-divider content-position="left">试卷基本信息</el-divider> <view-info :info="info" />
<el-descriptions :column="2" border>
<el-descriptions-item label="试卷名称" :span="2">
{{ info.EXAMNAME }}
</el-descriptions-item>
<el-descriptions-item label="合格分数">
{{ info.PASSSCORE }}
</el-descriptions-item>
<el-descriptions-item label="总分数">
{{ info.EXAMSCORE }}
</el-descriptions-item>
</el-descriptions>
<el-divider content-position="left">试卷题目信息</el-divider>
<div class="items mt-20 p-20">
<div
v-for="(item, index) in testPaper"
: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>
</layout-card> </layout-card>
</template> </template>
@ -72,11 +11,11 @@ import {
getExamPaperManagementView, getExamPaperManagementView,
} from "@/request/training_resource_management.js"; } from "@/request/training_resource_management.js";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import ViewInfo from "./components/view.vue";
const route = useRoute(); const route = useRoute();
const { STAGEEXAMPAPERINPUT_ID } = route.query; const { STAGEEXAMPAPERINPUT_ID } = route.query;
const info = ref({}); const info = ref({});
const testPaper = ref([]);
const fnGetData = async () => { const fnGetData = async () => {
const { pd } = await getExamPaperManagementView({ const { pd } = await getExamPaperManagementView({
STAGEEXAMPAPERINPUT_ID, STAGEEXAMPAPERINPUT_ID,
@ -85,25 +24,9 @@ const fnGetData = async () => {
const { varList } = await getExamPaperManagementTestQuestions({ const { varList } = await getExamPaperManagementTestQuestions({
STAGEEXAMPAPERINPUT_ID, STAGEEXAMPAPERINPUT_ID,
}); });
testPaper.value = varList; info.value.testPaper = varList;
}; };
fnGetData(); fnGetData();
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss"></style>
.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>