档案管理和效果评估

dev
zhangyanli 2024-03-21 16:22:25 +08:00
parent f6e8a66857
commit 4663e598b2
8 changed files with 738 additions and 17 deletions

View File

@ -89,6 +89,13 @@ export const layoutFnGetPersonnelType = async () => {
});
return ref(resData.list);
};
// 签字人员类型
export const layoutFnGetSignUserType = async () => {
const resData = await getLevels({
DICTIONARIES_ID: "e0309e3085f04aa9b0e6a56e88ee8c2f",
});
return ref(resData.list);
};
// 清单类型
export const layoutFnGetInventoryType = async () => {
const resData = await getLevels({

View File

@ -21,7 +21,6 @@ export const getUserArchives = (params) =>
post("/archives/getUserArchives", params); // 一人一档-档案详情
export const getLearningRecord = (params) =>
post("/archives/getLearningRecord", params);
export const getDict = (params) => post("/dictionaries/getLevels", params); // 获取人员类型
export const downloadFilesdetailword = (params) =>
post("/archives/filesdetailword", params); // 一人一档:档案详情导出
export const downloadAward = (params) =>
@ -125,4 +124,19 @@ export const getClassEvaluation = (params) =>
post("/class/getEvaluation", params); // 获取班级效果评估表信息
export const getStudentEvaluation = (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

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

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>
<script setup>
import { reactive, watchEffect } from "vue";
import { reactive, ref, watchEffect } from "vue";
import { ElMessageBox } from "element-plus";
import { getClassEvaluation } from "@/request/training_archive_management.js";
import { useVModel } from "@vueuse/core";
import dayjs from "dayjs";
import * as echarts from "echarts";
const props = defineProps({
classId: {
type: String,
@ -159,9 +160,11 @@ const props = defineProps({
},
visible: {
type: Boolean,
required: true,
default: false,
},
});
const chart = ref(null);
const visible = useVModel(props, "visible");
const data = reactive({
evaluationDialogForm: {},
@ -174,9 +177,10 @@ const fnGetData = async () => {
CLASS_ID: props.classId,
});
data.evaluationDialogForm = resData.pageData;
data.count1 = data.pageData.count1;
data.count2 = data.pageData.count2;
data.count3 = data.pageData.count3;
data.count1 = resData.pageData.count1;
data.count2 = resData.pageData.count2;
data.count3 = resData.pageData.count3;
fnGetPie();
};
const fnExport = async () => {
await ElMessageBox.confirm("确定要导出吗?", { type: "warning" });
@ -188,6 +192,59 @@ const fnExport = async () => {
watchEffect(() => {
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>
<style scoped lang="scss">