档案管理

This commit is contained in:
qinjie 2021-09-08 17:39:48 +08:00
parent 0e62d9e1a4
commit 87a00f07b9
8 changed files with 594 additions and 34 deletions

84
src/api/archives/user.js Normal file
View File

@ -0,0 +1,84 @@
import request from '@/utils/request'
const courseApi = {
list: '/archives/user/listPage',
autoTrainList: '/archives/user/autoTrainPageList',
autoTrainDetailList: '/archives/user/autoTrainDetailPageList',
autoTrainAnswerList: '/archives/user/autoTrainAnswerPageList',
terminalTrainList: '/archives/user/terminalTrainPageList',
terminalTrainDetail: '/archives/user/terminalTrainDetail',
selfStudyList: '/archives/user/selfStudyPageList',
violationList: '/archives/user/violationPageList'
}
// 人员档案 列表
export function getArchivesUserList(params) {
return request({
url: courseApi.list,
method: 'get',
params: params
})
}
// 人员档案-自主培训 列表
export function getArchivesUserAutoTrainList(params) {
return request({
url: courseApi.autoTrainList,
method: 'get',
params: params
})
}
// 人员档案-自主培训-培训详情 列表
export function getArchivesUserAutoTrainDetailList(params) {
return request({
url: courseApi.autoTrainDetailList,
method: 'get',
params: params
})
}
// 人员档案-自主培训-答题记录 列表
export function getArchivesUserAutoTrainAnswerList(params) {
return request({
url: courseApi.autoTrainAnswerList,
method: 'get',
params: params
})
}
// 人员档案-终端培训 列表
export function getArchivesUserTerminalTrainList(params) {
return request({
url: courseApi.terminalTrainList,
method: 'get',
params: params
})
}
// 人员档案-终端培训-查看详情
export function getArchivesUserTerminalTrainDetail(params) {
return request({
url: courseApi.terminalTrainDetail,
method: 'get',
params: params
})
}
// 人员档案-自学档案
export function getArchivesUserSelfStudyList(params) {
return request({
url: courseApi.selfStudyList,
method: 'get',
params: params
})
}
// 人员档案-违章档案
export function getArchivesUserViolationList(params) {
return request({
url: courseApi.violationList,
method: 'get',
params: params
})
}

View File

@ -0,0 +1,123 @@
<template>
<!-- 点击式按钮建议高度介于36px与46px -->
<div id="vaptchaContainer" style="width: 300px;height: 36px;">
<!--vaptcha-container是用来引入VAPTCHA的容器下面代码为预加载动画仅供参考-->
<div class="vaptcha-init-main">
<div class="vaptcha-init-loading">
<a href="/" target="_blank">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48px" height="60px" viewBox="0 0 24 30" style="enable-background: new 0 0 50 50; width: 14px; height: 14px; vertical-align: middle" xml:space="preserve">
<rect x="0" y="9.22656" width="4" height="12.5469" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0s" dur="0.6s" repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0s" dur="0.6s" repeatCount="indefinite"></animate>
</rect>
<rect x="10" y="5.22656" width="4" height="20.5469" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.15s" dur="0.6s" repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.15s" dur="0.6s" repeatCount="indefinite"></animate>
</rect>
<rect x="20" y="8.77344" width="4" height="13.4531" fill="#CCCCCC">
<animate attributeName="height" attributeType="XML" values="5;21;5" begin="0.3s" dur="0.6s" repeatCount="indefinite"></animate>
<animate attributeName="y" attributeType="XML" values="13; 5; 13" begin="0.3s" dur="0.6s" repeatCount="indefinite"></animate>
</rect>
</svg>
</a>
<span class="vaptcha-text">Vaptcha Initializing...</span>
</div>
</div>
</div>
</template>
<script>
const extend = function (to, _from) {
for (const key in _from) {
to[key] = _from[key];
}
return to;
}
export default {
props: {
type: {
type: String,
default: 'click'
},
scene: {
type: String,
default: ''
},
vpStyle: {
type: String,
default: 'dark'
},
color: {
type: String,
default: '#3C8AFF'
},
lang: {
type: String,
default: 'zh-CN'
}
},
mounted() {
var config = extend({
vid: '6121123db849dfa2f02958c6',
container: this.$refs.vaptcha,
style: this.vpStyle
}, this.$props)
this.loadV2Script().then(() => {
window.vaptcha(config).then(obj => {
this.$emit('input', obj)
obj.render()
})
})
},
methods: {
loadV2Script() {
if (typeof window.vaptcha === 'function') { //
return Promise.resolve()
} else {
return new Promise(resolve => {
var script = document.createElement('script')
script.src = 'https://v-cn.vaptcha.com/v3.js'
script.async = true
script.onload = script.onreadystatechange = function () {
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') {
resolve()
script.onload = script.onreadystatechange = null
}
}
document.getElementsByTagName("head")[0].appendChild(script)
})
}
}
}
}
</script>
<style>
.vaptcha-init-main {
display: table;
width: 100%;
height: 100%;
background-color: #eeeeee;
}
.vaptcha-init-loading {
display: table-cell;
vertical-align: middle;
text-align: center;
}
.vaptcha-init-loading > a {
display: inline-block;
width: 18px;
height: 18px;
border: none;
}
.vaptcha-init-loading .vaptcha-text {
font-family: sans-serif;
font-size: 12px;
color: #cccccc;
vertical-align: middle;
}
</style>

View File

@ -1,52 +1,84 @@
<template>
<div>
<!-- 搜索区 -->
<a-space>
人员姓名:
<a-input style="width: 180px" v-model="organizationId"></a-input>
<a-button type="primary">查询</a-button>
<a-button type="primary">导出</a-button>
</a-space>
<org-tree defaultOrganizationId="000100020001" startOrganizationId="00010002" @getSelectTreeKey="getSelectTreeKey"></org-tree>
<!-- <div class="table-page-search-wrapper">
<a-form layout="inline">
<a-row>
<a-col :span="4">
<a-form-item label="人员姓名">
</a-form-item>
</a-col>
</a-row>
</a-form>
</div> -->
</div>
<page-header-wrapper :title="false">
<!-- 是否有边框 bordered -->
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<SearchCom :form="queryParam" :list="queryOptions" :orgTree="orgTreeOptions" @search="handleRefresh" @reset="() => {queryParam = {}, handleRefresh()}"></SearchCom>
<div style="width: 100%; height: 32px; margin-bottom: 8px;">
<a-button type="primary" :style="{float: 'right'}">导出</a-button>
</div>
</div>
<s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData">
<template slot="action" slot-scope="text, record">
<a href="javascript:;" @click="archivesProject(record)">项目档案</a>
<a-divider type="vertical" />
<a href="javascript:;" @click="archivesSelfStudy(record)">自学档案</a>
<br />
<a href="javascript:;">违章档案</a>
<a-divider type="vertical" />
<a-popconfirm title="确认导出?" cancelText="取消" okText="确认" @confirm="() => handleDelete(record)">
<a href="javascript:;"> 导出 </a>
</a-popconfirm>
</template>
</s-table>
</a-card>
</page-header-wrapper>
<!-- 搜索区 -->
<!-- -->
</template>
<script>
import orgTree from '@/components/OrgTree/Index'
import { STable, SearchCom, orgTree } from '@/components'
import { getArchivesUserList } from '@/api/archives/user'
export default {
components: { orgTree },
components: { STable, SearchCom, orgTree },
data() {
return {
organizationId: ''
queryParam: { name: '', orgId: '' },
columns: [
{ title: '姓名', width: '100px', align: 'center', dataIndex: 'name', key: 'name' },
{ title: '受训角色', width: 'auto', align: 'center', dataIndex: 'roleName', key: 'roleName' },
{ title: '单位信息', width: 'auto', align: 'center', dataIndex: 'dwOrgName', key: 'dwOrgName' },
{ title: '部门信息', width: 'auto', align: 'center', dataIndex: 'bmOrgName', key: 'bmOrgName' },
{ title: '年度学时要求/时', width: 'auto', align: 'center', dataIndex: 'yearClassHourRequire', key: 'yearClassHourRequire' },
{ title: '年度学时', width: 'auto', align: 'center', dataIndex: 'yearClassHour', key: 'yearClassHour' },
{ title: '累计学时', width: 'auto', align: 'center', dataIndex: 'addUpClassHour', key: 'addUpClassHour' },
{ title: '项目学时', width: 'auto', align: 'center', dataIndex: 'projectClassHour', key: 'projectClassHour' },
{ title: '操作', width: '170px', key: 'operation', align: 'center', scopedSlots: { customRender: 'action' } }
],
loadData: parameter => { return getArchivesUserList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
}
},
computed: {
queryOptions: function () {
return [
{ type: 'input', placeholder: '人员姓名', key: 'name' }
]
},
orgTreeOptions: () => {
return { ifshow: true, formKey: 'orgId', startOrganizationId: '' };
}
},
methods: {
getSelectTreeKey(key) {
this.organizationId = key;
handleRefresh() {
this.$refs.table.refresh(true)
},
//
archivesProject(record) {
this.$router.push({ path: '/archives/user/Project', query: { id: record.id } });
},
//
archivesSelfStudy(record) {
this.$router.push({ path: '/archives/user/SelfStudy', query: { id: record.id } });
}
}
}
</script>
<style scoped>
a {
width: 100px;
.table-page-search-wrapper-button-group {
width: 100%;
margin-bottom: 8px;
}
</style>

View File

@ -0,0 +1,138 @@
<template>
<page-header-wrapper :title="false">
<a-tabs :animated="false" default-active-key="1" @change="callback" :style="{backgroundColor: '#fff'}">
<a-tab-pane key="1" tab="自主培训">
<a-card :bordered="false" :bodyStyle="{paddingTop: '0px'}">
<div class="table-page-search-wrapper">
<SearchCom :form="tabs1.queryParam" :list="tabs1QueryOptions" @search="tabs1HandleRefresh" @reset="() => {queryParam = {}, tabs1HandleRefresh()}"></SearchCom>
</div>
<s-table ref="table1" size="default" rowKey="id" :columns="tabs1.columns" :data="tabs1.loadData">
<template slot="action" slot-scope="text, record">
<a href="javascript:;" @click="trainDetail(record)">培训详情</a>
<br />
<a href="javascript:;" @click="trainAnswer(record)">答题记录</a>
</template>
</s-table>
</a-card>
</a-tab-pane>
<a-tab-pane key="2" tab="终端培训" force-render>
<a-card :bordered="false" :bodyStyle="{paddingTop: '0px'}">
<div class="table-page-search-wrapper">
<SearchCom :form="tabs2.queryParam" :list="tabs2QueryOptions" @search="tabs2HandleRefresh" @reset="() => {queryParam = {}, tabs2HandleRefresh()}"></SearchCom>
</div>
<s-table ref="table2" size="default" rowKey="id" :columns="tabs2.columns" :data="tabs2.loadData">
<template slot="action" slot-scope="text, record">
<a href="javascript:;" @click="terminalTrainDetail(record)">查看详情</a>
</template>
</s-table>
</a-card>
</a-tab-pane>
</a-tabs>
</page-header-wrapper>
</template>
<script>
import { STable, SearchCom } from '@/components'
import { getArchivesUserAutoTrainList, getArchivesUserTerminalTrainList } from '@/api/archives/user'
export default {
components: { STable, SearchCom },
data() {
return {
userid: this.$route.query.id,
tabs1: {
queryParam: { projectName: '', finishState: '' },
columns: [
{ title: '项目名称', width: 'auto', align: 'center', dataIndex: 'projectName', key: 'projectName' },
{ title: '项目时间', width: 'auto', align: 'center', dataIndex: 'projectData', key: 'projectData' },
{ title: '受训角色', width: 'auto', align: 'center', dataIndex: 'roleName', key: 'roleName' },
{ title: '应修学时', width: 'auto', align: 'center', dataIndex: 'mustClassHour', key: 'mustClassHour' },
{ title: '已修学时', width: 'auto', align: 'center', dataIndex: 'alreadyClassHour', key: 'alreadyClassHour' },
{
title: '完成状态', width: 'auto', align: 'center', dataIndex: 'finishState', key: 'finishState', customRender: (text, record, index) => {
// 0- 1-
if (text == 0) return '未完成'; else if (text == 1) return '已完成';
}
},
{ title: '总练习题量', width: 'auto', align: 'center', dataIndex: 'addUpExercises', key: 'addUpExercises' },
{ title: '已练习题量', width: 'auto', align: 'center', dataIndex: 'alreadyExercises', key: 'alreadyExercises' },
{ title: '答对题量', width: 'auto', align: 'center', dataIndex: 'yesTopic', key: 'yesTopic' },
{ title: '正确率', width: 'auto', align: 'center', dataIndex: 'yesRate', key: 'yesRate' },
{ title: '考试成绩', width: 'auto', align: 'center', dataIndex: 'testResult', key: 'testResult' },
{ title: '补考成绩', width: 'auto', align: 'center', dataIndex: 'mendTestResult', key: 'mendTestResult' },
{ title: '考试耗时', width: 'auto', align: 'center', dataIndex: 'testTime', key: 'testTime' },
{
title: '考试状态', width: 'auto', align: 'center', dataIndex: 'testState', key: 'testState', customRender: (text, record, index) => {
// 0- 1-
if (text == 0) return '不合格'; else if (text == 1) return '合格';
}
},
{ title: '操作', width: '90px', key: 'operation', align: 'center', scopedSlots: { customRender: 'action' } }
],
loadData: parameter => { return getArchivesUserAutoTrainList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
},
tabs2: {
queryParam: { projectName: '' },
columns: [
{ title: '项目名称', width: 'auto', align: 'center', dataIndex: 'projectName', key: 'projectName' },
{ title: '项目时间', width: 'auto', align: 'center', dataIndex: 'projectData', key: 'projectData' },
{ title: '受训角色', width: 'auto', align: 'center', dataIndex: 'roleName', key: 'roleName' },
{ title: '培训地址', width: 'auto', align: 'center', dataIndex: 'trainAddr', key: 'trainAddr' },
{ title: '签到时间', width: 'auto', align: 'center', dataIndex: 'signInTime', key: 'signInTime' },
{
title: '完成状态', width: 'auto', align: 'center', dataIndex: 'finishState', key: 'finishState', customRender: (text, record, index) => {
// 0- 1-
if (text == 0) return '未完成'; else if (text == 1) return '已完成';
}
},
{ title: '操作', width: '90px', key: 'operation', align: 'center', scopedSlots: { customRender: 'action' } }
],
loadData: parameter => { return getArchivesUserTerminalTrainList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
}
}
},
computed: {
tabs1QueryOptions: function () {
return [
{ type: 'input', placeholder: '项目名称', key: 'projectName' },
{
type: 'select', placeholder: '完成状态', key: 'finishState', options: [
{ id: '', name: '全部' },
{ id: '1', name: '已完成' },
{ id: '0', name: '未完成' }
]
}
]
},
tabs2QueryOptions: function () {
return [
{ type: 'input', placeholder: '项目名称', key: 'projectName' }
]
},
},
methods: {
callback(key) {
if (key === '1') this.tabs1HandleRefresh();
else this.tabs2HandleRefresh();
},
tabs1HandleRefresh() {
this.$refs.table1.refresh(true)
},
tabs2HandleRefresh() {
this.$refs.table2.refresh(true)
},
//
trainDetail(record) {
this.$router.push({ path: '/archives/user/ProjectDetail', query: { userId: this.userid, projectId: record.id } });
},
//
trainAnswer(record) {
this.$router.push({ path: '/archives/user/ProjectAnswer', query: { userId: this.userid, projectId: record.id } });
},
//
terminalTrainDetail(record) {
this.$router.push({ path: '/archives/user/TerminalTrainDetail', query: { userId: this.userid, projectId: record.id } });
}
}
}
</script>

View File

@ -0,0 +1,36 @@
<template>
<page-header-wrapper :title="false">
<a-card :bordered="false">
<s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData">
<template slot="action" slot-scope="text, record">
<a href="javascript:;" @click="trainDetail(record)">答题记录</a>
</template>
</s-table>
</a-card>
</page-header-wrapper>
</template>
<script>
import { STable, SearchCom } from '@/components'
import { getArchivesUserAutoTrainAnswerList } from '@/api/archives/user'
export default {
components: { STable, SearchCom },
data() {
return {
userId: this.$route.query.userId,
projectId: this.$route.query.projectId,
queryParam: { userId: this.$route.query.userId, projectId: this.$route.query.projectId },
columns: [
{ title: '交卷时间', width: 'auto', align: 'center', dataIndex: 'handDate', key: 'handDate' },
{ title: '考试时长', width: 'auto', align: 'center', dataIndex: 'testTime', key: 'testTime' },
{ title: '考试成绩', width: 'auto', align: 'center', dataIndex: 'testResult', key: 'testResult' },
{ title: '操作', width: 'auto', key: 'operation', align: 'center', scopedSlots: { customRender: 'action' } }
],
loadData: parameter => { return getArchivesUserAutoTrainAnswerList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
}
},
computed: {},
methods: {}
}
</script>

View File

@ -0,0 +1,56 @@
<template>
<page-header-wrapper :title="false">
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<SearchCom :form="queryParam" :list="queryOptions" @search="handleRefresh" @reset="() => {queryParam = {}, handleRefresh()}"></SearchCom>
</div>
<s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData"></s-table>
</a-card>
</page-header-wrapper>
</template>
<script>
import { STable, SearchCom } from '@/components'
import { getArchivesUserAutoTrainDetailList } from '@/api/archives/user'
export default {
components: { STable, SearchCom },
data() {
return {
userId: this.$route.query.userId,
projectId: this.$route.query.projectId,
queryParam: { userId: this.$route.query.userId, projectId: this.$route.query.projectId, courseName: '' },
columns: [
{ title: '课程名称', width: 'auto', align: 'center', dataIndex: 'courseName', key: 'courseName' },
{ title: '应修学时', width: 'auto', align: 'center', dataIndex: 'mustClassHour', key: 'mustClassHour' },
{ title: '已修学时', width: 'auto', align: 'center', dataIndex: 'alreadyClassHour', key: 'alreadyClassHour' },
{ title: '总题量', width: 'auto', align: 'center', dataIndex: 'addUpExercises', key: 'addUpExercises' },
{ title: '已答题量', width: 'auto', align: 'center', dataIndex: 'alreadyExercises', key: 'alreadyExercises' },
{ title: '答对题量', width: 'auto', align: 'center', dataIndex: 'yesExercises', key: 'yesExercises' },
{ title: '答对正确率', width: 'auto', align: 'center', dataIndex: 'yesTopic', key: 'yesTopic' },
{
title: '完成状态', width: 'auto', align: 'center', dataIndex: 'finishState', key: 'finishState', customRender: (text, record, index) => {
// 0- 1-
if (text == 0) return '未完成'; else if (text == 1) return '已完成';
}
}
],
loadData: parameter => { return getArchivesUserAutoTrainDetailList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
}
},
computed: {
queryOptions: function () {
return [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
]
}
},
methods: {
handleRefresh() {
this.queryParam.userId = this.userId;
this.queryParam.projectId = this.projectId;
this.$refs.table.refresh(true)
}
}
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<page-header-wrapper :title="false">
<a-card :bordered="false">
<div class="table-page-search-wrapper">
<SearchCom :form="queryParam" :list="queryOptions" @search="handleRefresh" @reset="() => {queryParam = {}, handleRefresh()}"></SearchCom>
</div>
<s-table ref="table" size="default" rowKey="id" :columns="columns" :data="loadData"></s-table>
</a-card>
</page-header-wrapper>
</template>
<script>
import { STable, SearchCom } from '@/components'
import { getArchivesUserSelfStudyList } from '@/api/archives/user'
export default {
components: { STable, SearchCom },
data() {
return {
userId: this.$route.query.userId,
queryParam: { userId: this.$route.query.userId, courseName: '' },
columns: [
{ title: '课程名称', width: 'auto', align: 'center', dataIndex: 'courseName', key: 'courseName' },
{ title: '课时(分)', width: 'auto', align: 'center', dataIndex: 'classHour', key: 'classHour' },
{ title: '已学学时', width: 'auto', align: 'center', dataIndex: 'alreadyClassHour', key: 'alreadyClassHour' },
],
loadData: parameter => { return getArchivesUserSelfStudyList(Object.assign(parameter, this.queryParam)).then(res => { return res }) }
}
},
computed: {
queryOptions: function () {
return [
{ type: 'input', placeholder: '课程名称', key: 'courseName' },
]
}
},
methods: {
handleRefresh() {
this.queryParam.userId = this.userId;
this.$refs.table.refresh(true)
}
}
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<page-header-wrapper :title="false">
<a-card :bordered="false">
<a-descriptions title="集中培训详情" layout="horizontal" bordered size="small" :column="1">
<a-descriptions-item label="培训名称">{{detailData.name}}</a-descriptions-item>
<a-descriptions-item label="培训时间">{{detailData.time}}</a-descriptions-item>
<a-descriptions-item label="主持人">{{detailData.host}}</a-descriptions-item>
<a-descriptions-item label="会议人数">{{detailData.personSize}}</a-descriptions-item>
<a-descriptions-item label="学习内容">{{detailData.studyContent}}</a-descriptions-item>
<a-descriptions-item label="联系人">{{detailData.contact}}</a-descriptions-item>
<a-descriptions-item label="备注">{{detailData.remark}}</a-descriptions-item>
</a-descriptions>
<br />
<a-descriptions title="签到时间" layout="horizontal" bordered size="small" :column="1">
<a-descriptions-item label="时间">{{detailData.signInTime}}</a-descriptions-item>
</a-descriptions>
<br />
<a-descriptions title="培训状态" layout="horizontal" bordered size="small" :column="1">
<a-descriptions-item label="状态">{{detailData.state}}</a-descriptions-item>
</a-descriptions>
</a-card>
</page-header-wrapper>
</template>
<script>
import { getArchivesUserTerminalTrainDetail } from '@/api/archives/user'
export default {
data() {
return {
queryParam: { userId: this.$route.query.userId, projectId: this.$route.query.projectId },
detailData: {}
}
},
created: function () {
let parameter = {};
getArchivesUserTerminalTrainDetail(Object.assign(parameter, this.queryParam)).then(res => { this.detailData = res.data });
}
}
</script>
<style>
.ant-descriptions-item-label {
width: 100px;
text-align: center;
}
</style>