Files
fe-manage/src/views/report/Employeelearning.vue
2025-11-24 15:02:17 +08:00

881 lines
25 KiB
Vue

<template>
<div class="employeelearning">
<div class="searchForm">
<a-form layout="inline">
<a-form-item label="归属组织" :colon="false" class="reportSelect">
<a-cascader
change-on-select
:options="option"
@change="orgChange"
v-model:value="orgId"
style="width: 145px; height: 36px; border-radius: 4px"
placeholder="请选择归属组织"
:allowClear="false"
:fieldNames="{
label: 'orgName',
value: 'organizationId',
children: 'childList',
}"
>
</a-cascader>
</a-form-item>
<a-form-item label="姓名" :colon="false">
<a-input
v-model:value="name"
placeholder="请输入姓名"
allowClear
style="width: 120px; height: 36px; border-radius: 4px"
/>
</a-form-item>
<a-form-item label="工号" :colon="false">
<a-input
v-model:value="userNo"
placeholder="请输入工号"
allowClear
style="width: 126px; height: 36px; border-radius: 4px"
/>
</a-form-item>
<!-- <a-form-item label="岗位" :colon="false">
<a-input
v-model:value="studentJobName"
placeholder="请输入岗位"
allowClear
style="width: 126px; height: 36px; border-radius: 4px"
/>
</a-form-item> -->
<a-form-item label="Band" :colon="false" class="reportSelect">
<a-select
ref="select"
allowClear
v-model:value="valueBand"
style="width: 120px; height: 36px; border-radius: 4px"
:options="optionsBand"
placeholder="请选择Band"
@focus="focusBand"
@change="handleBandChange"
></a-select>
</a-form-item>
<a-form-item>
<a-space>
<a-button
style="
width: 60px;
height: 32px;
background: #4395ff;
border-radius: 4px 4px 4px 4px;
color: #ffffff;
"
@click="getTableData"
>搜索</a-button
>
<a-button
style="
width: 60px;
height: 32px;
background: #4395ff;
border-radius: 4px 4px 4px 4px;
color: #ffffff;
"
@click="reset"
>重置</a-button
>
</a-space>
</a-form-item>
</a-form>
</div>
<div class="content">
<div class="topToolbar">
<div>
<a-space>
<a-button
style="
width: 60px;
height: 32px;
background: #4395ff;
border-radius: 4px 4px 4px 4px;
color: #ffffff;
"
@click="exportbtnz"
>导出</a-button
>
<a-tooltip>
<template #title>导出全部数据</template>
<a-button
style="
width: 88px;
height: 32px;
background: #ffffff;
border-radius: 4px 4px 4px 4px;
border: 1px solid #e6e6e6;
color: #333333;
"
@click="exportAllbtnz"
>导出全部</a-button
>
</a-tooltip>
</a-space>
</div>
<div>
<TableColSet v-model:columns="columns" />
</div>
</div>
<!-- 以下为table表格 -->
<div class="tableBox">
<a-table
:columns="columns.filter((n) => n.visible == true)"
:data-source="tableData"
:loading="tableLoading"
:scroll="{ x: 700 }"
:pagination="false"
@change="handleTableChange"
:row-selection="{
selectedRowKeys: selectedRowKeys,
onChange: onSelectChange,
}"
rowKey="id"
>
<template v-slot:header>
<draggable
v-model="columns"
item-key="key"
:list="columns"
:group="{ name: 'columns', pull: 'clone', put: false }"
>
<template #item="{ element }">
<a-table-column
:title="element.title"
:dataIndex="element.dataIndex"
:key="element.key"
></a-table-column>
</template>
</draggable>
</template>
<template #bodyCell="{ record, column }">
<template v-if="column.key === 'projectCompletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 1)"
>
{{
!record.projectCompletedNum ? "0" : record.projectCompletedNum
}}
</div>
</template>
<template v-if="column.key === 'routerCompletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 2)"
>
{{
!record.routerCompletedNum ? "0" : record.routerCompletedNum
}}
</div>
</template>
<template v-if="column.key === 'offCourseCompletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 3)"
>
{{
!record.offCourseCompletedNum
? "0"
: record.offCourseCompletedNum
}}
</div>
</template>
<template v-if="column.key === 'onlineCompletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 4)"
>
{{
!record.onlineCompletedNum ? "0" : record.onlineCompletedNum
}}
</div>
</template>
<template v-if="column.key === 'examCompletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 5)"
>
{{ !record.examCompletedNum ? "0" : record.examCompletedNum }}
</div>
</template>
<template v-if="column.key === 'caseViewsNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 6)"
>
{{ !record.caseViewsNum ? "0" : record.caseViewsNum }}
</div>
</template>
<template v-if="column.key === 'professionalCompeletedNum'">
<div
style="color: #02a7f0; cursor: pointer"
@click="openModal(record.studentId, 7)"
>
{{
!record.professionalCompeletedNum
? "0"
: record.professionalCompeletedNum
}}
</div>
</template>
</template>
</a-table>
<div class="tableBox">
<div class="pa">
<a-pagination
v-if="tableDataTotal > 10"
:showSizeChanger="false"
showQuickJumper="true"
hideOnSinglePage="true"
:pageSize="pageSize"
v-model:current="pageNo"
:total="tableDataTotal"
class="pagination"
@change="changePagination"
/>
</div>
</div>
</div>
</div>
<EmployeelearningModal
v-if="isModalVisible"
v-model:isModalVisible="isModalVisible"
v-model:modalType="modalType"
v-model:studentId="currentStudentId"
/>
</div>
</template>
<script lang="jsx">
import { ref, toRefs, reactive, onMounted } from "vue";
import * as api from "../../api/indexOvervoew";
import { message } from "ant-design-vue";
import Cookies from "vue-cookies";
import axios from "axios";
import downLoad from "../../utils/downLoad";
import { useStore } from "vuex";
import draggable from 'vuedraggable';
import EmployeelearningModal from './EmployeelearningModal.vue';
import TableColSet from '../../components/common/TableColSet.vue';
export default {
name: "EmployeelearninG",
components: {
EmployeelearningModal: EmployeelearningModal,
draggable:draggable,
TableColSet:TableColSet
},
setup() {
const store = useStore();
const state = reactive({
tableLoading: false, // table加载图标
tableDataTotal: 0, // 数据总条数
pageSize: 10, // 每页条数
pageNo: 1, //当前页码
orgId: null, // 状态值
name: "", // 名称
band: "", // band
userNo: "", //工号
option: [], //组织列表
selectedRowKeys: [], // 选中的列
ids: [],
allowClear:true,
resetOrgId:[],
valueBand: null,
studentJobName: null,
optionsBand:[
{value: 'Band1',label: 'Band1',},
{value: 'Band2',label: 'Band2',},
{value: 'Band3',label: 'Band3',},
{value: 'Band4',label: 'Band4',},
{value: 'Band5',label: 'Band5',},
{value: 'Band6',label: 'Band6',},
{value: 'Band7',label: 'Band7',},
{value: 'Band8',label: 'Band8',},
{value: 'Band9',label: 'Band9',},
{value: 'Band10',label: 'Band10',},
{value: 'Band11',label: 'Band11',},
{value: 'Band12',label: 'Band12',},
{value: 'Band13',label: 'Band13',},
{value: 'Band14',label: 'Band14',},
{value: 'Band15',label: 'Band15',},
{value: 'Band16',label: 'Band16',},
{value: 'Band17',label: 'Band17',},
{value: 'Band18',label: 'Band18',},
{value: 'Band19',label: 'Band19',},
{value: 'Band20',label: 'Band20',},
],
optionsCourseType: [
{
value: true,
label: '是',
},
{
value: false,
label: '否',
},
],
isModalVisible:false,
currentStudentId:null,
modalType:null,
tableSorts:[]
});
const focusBand = () => {
console.log('focus band');
};
const handleBandChange = (value) => {
console.log(`selected handleBandChange ${value}`);
state.valueBand = value;
};
const handleCourseTypeChange = (value) => {
console.log(`selected handleCourseTypeChange ${value}`);
state.studentJobName = value;
};
// table选中
const onSelectChange = (selectedRowKeys, record) => {
state.selectedRowKeys = selectedRowKeys;
state.ids = record?.map((item) => {
return item.id;
});
};
//请求组织接口
const getOrgList = async () => {
var manageFlag = false;
if (store.state.userInfo != null && store.state.userInfo.roleList != null) {
for (let i = 0; i < store.state.userInfo.roleList.length; i++) {
if (store.state.userInfo.roleList[i].roleCode == "system-admin") {
manageFlag = true;
break;
}
}
}
const res = await api.userGetUserOrg({});
// const res = orgjson;
if (res != null && res.data != null && res.data.result != null && res.data.result.orgTreeList != null) {
orgArray = flattenOrgTree(res.data.result.orgTreeList);
}
if (res) {
if (manageFlag) {
state.option = [{
orgName: "全部",
organizationId: null,
childList: res.data?.result.orgTreeList
}];
state.orgId = [null, ...res.data?.result.treeNodeList];
state.resetOrgId = [null, ...res.data?.result.treeNodeList];
} else {
if (res.data?.result.orgTreeList != null) {
state.option = res.data?.result.orgTreeList;
state.orgId = res.data?.result.treeNodeList;
state.resetOrgId = res.data?.result.treeNodeList;
} else {
state.option = [{
orgName: "无权限",
organizationId: "1",
childList: [],
}];
state.orgId = ["1"];
state.resetOrgId = ["1"];
}
}
state.type = res.data?.result?.userType;
res.data?.result?.userType === 1
? (state.allowClear = true)
: (state.allowClear = false);
getTableData();
}
};
let orgArray = [];
const orgChange = (value) => {
//匹配value
let arr = orgArray.filter(org => value.includes(org.organizationId))
//arr使用/拼接
let orgPath = arr.map(org => org.orgName).join('/')
if (orgPath) {
state.orgPath = "/" + orgPath;
}
};
function flattenOrgTree(orgTree) {
const result = [];
function traverse(node) {
if (node.organizationId && node.orgName) {
result.push({
organizationId: node.organizationId,
orgName: node.orgName
});
}
if (node.childList && node.childList.length > 0) {
node.childList.forEach(child => traverse(child));
}
}
orgTree.forEach(node => traverse(node));
return result;
}
//导出
const exportbtnz = async () => {
if (!state.selectedRowKeys?.length) {
return message.warning("请至少选择一条数据进行导出");
} else {
let fields = columns.value.filter(item=>item.visible==true).map(function(item){
return item.dataIndex;
})
if(!fields?.length){
return message.warning("请至少选择一个字段进行导出");
}
axios({
method: "post",
url: "/reportsnake/export/report",
data: { ids: state.selectedRowKeys ,type: 20, fields: fields},
responseType: "blob",
headers: {
token: Cookies.get("token"),
},
}).then((res) => {
downLoad(res.data, "学习员工数据.xlsx");
});
}
};
// 表格数据
let tableData = ref([]);
// cloumns 表头 colSortNo:列默认排序号
const columns = ref([
{
title: "工号",
dataIndex: "studentUserNo",
key: "studentUserNo",
width: 120,
ellipsis: true,
align: "center",
colSortNo: 1,
visible: true,
},
{
title: "姓名",
dataIndex: "studentName",
ellipsis: true,
key: "studentName",
width: 120,
align: "center",
sorter: true,
colSortNo: 2,
visible: true,
},
{
title: "归属组织",
dataIndex: "studentOrgName",
ellipsis: true,
key: "studentOrgName",
width: 120,
align: "center",
sorter: true,
colSortNo: 3,
visible: true,
},
/*
{
title: "所属岗位",
dataIndex: "studentJobName",
ellipsis: true,
key: "studentJobName",
width: 120,
align: "center",
sorter: true,
colSortNo: 4,
visible: true,
},
*/
{
title: "所在Band",
dataIndex: "bandInfo",
ellipsis: true,
key: "bandInfo",
width: 120,
align: "center",
sorter: true,
colSortNo: 5,
visible: true,
},
{
title: "项目完成数",
dataIndex: "projectCompletedNum",
ellipsis: true,
key: "projectCompletedNum",
width: 120,
align: "center",
colSortNo: 6,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "面授完成数",
dataIndex: "offCourseCompletedNum",
ellipsis: true,
key: "offCourseCompletedNum",
width: 120,
align: "center",
colSortNo: 7,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "面授完成率",
dataIndex: "offCourseCompletedRate",
ellipsis: true,
key: "offCourseCompletedRate",
width: 120,
align: "center",
colSortNo: 8,
visible: true,
customRender: (text) => {return !text.value && text.value != 0?'0%':text.value + "%";}
},
{
title: "在线课完成数",
dataIndex: "onlineCompletedNum",
ellipsis: true,
key: "onlineCompletedNum",
width: 130,
align: "center",
colSortNo: 9,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "在线课学习总时长",
dataIndex: "onlineCompletedDuration",
ellipsis: true,
key: "onlineCompletedDuration",
width: 160,
align: "center",
colSortNo: 10,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
/*
{
title: "考试完成数",
dataIndex: "examCompletedNum",
ellipsis: true,
key: "examCompletedNum",
width: 120,
align: "center",
colSortNo: 15,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "考试及格数",
dataIndex: "examPassNum",
ellipsis: true,
key: "examPassNum",
width: 120,
align: "center",
colSortNo: 16,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "考试及格率",
dataIndex: "examPassRate",
ellipsis: true,
key: "examPassRate",
width: 120,
align: "center",
colSortNo: 17,
visible: true,
customRender: (text) => {return !text.value && text.value != 0?'0%':text.value + "%";}
},
*/
{
title: "项目完成率",
dataIndex: "projectCompletedRate",
ellipsis: true,
key: "projectCompletedRate",
width: 120,
align: "center",
sorter: true,
colSortNo: 11,
visible: true,
customRender: (text) => {return !text.value && text.value != 0?'0%':text.value + "%";},
},
{
title: "学习路径完成关卡数",
dataIndex: "routerCompletedNum",
ellipsis: true,
key: "routerCompletedNum",
width: 180,
align: "center",
colSortNo: 12,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "学习路径完成率",
dataIndex: "routerCompletedRate",
ellipsis: true,
key: "routerCompletedRate",
width: 160,
align: "center",
colSortNo: 13,
visible: true,
customRender: (text) => {return !text.value && text.value != 0?'0%':text.value + "%";}
},
{
title: "案例贡献数",
dataIndex: "caseNum",
ellipsis: true,
key: "caseNum",
width: 120,
align: "center",
colSortNo: 14,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "案例浏览数",
dataIndex: "caseViewsNum",
ellipsis: true,
key: "caseViewsNum",
width: 120,
align: "center",
colSortNo: 18,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
/*
{
title: "专业力必修完成数",
dataIndex: "professionalCompeletedNum",
ellipsis: true,
key: "professionalCompeletedNum",
width: 180,
align: "center",
colSortNo: 19,
visible: true,
customRender: (text) => {return !text.value?'0':text.value;}
},
{
title: "专业力必修完成率",
dataIndex: "professionalCompletedRate",
ellipsis: true,
key: "professionalCompletedRate",
width: 180,
align: "center",
colSortNo: 20,
visible: true,
customRender: (text) => {return !text.value && text.value != 0?'0%':text.value + "%";}
},
*/
// {
// title: "操作",
// dataIndex: "operation",
// key: "operation",
// width: 150,
// align: "center",
// fixed: "right",
// customRender: (record) => {
// return (
// <a
// key="export"
// onClick={() => {
// oneExport(record);
// }}
// >
// 导出详细信息
// </a>
// );
// },
// },
]);
// 行内单条下载
const oneExport = (record) => {
axios({
method: "get",
url: "/report/boeu/studyData/exportDetailed",
params: { ids: `${record.record.userId}` },
responseType: "blob",
headers: {
token: Cookies.get("token"),
},
}).then((res) => {
downLoad(res.data, "学习员工数据.xlsx");
});
};
//table 分页事件
const changePagination = (page) => {
state.pageNo = page;
getTableData();
};
// 获取数据
const getTableData = async () => {
state.tableLoading = true;
const res = await api.studentReportPageList({
page: state.pageNo,
size: state.pageSize,
userNo: state.userNo,
name: state.name,
orgId: state.orgId ? state.orgId[state.orgId.length - 1] : null,
bandCode: state.valueBand,
//jobName: state.studentJobName,
tableSorted: state.tableSorts
});
if (res) {
state.tableDataTotal = res.data.total;
tableData.value = res.data.records || [];
state.tableLoading = false;
}
};
// 重置按钮
const reset = async () => {
state.tableLoading = true;
state.name = "";
state.band = "";
state.userNo = "";
state.valueBand = null;
state.studentJobName = null;
state.orgId = state.resetOrgId;
getTableData();
};
const openModal = (studentId, modalType) =>{
state.currentStudentId = studentId;
state.modalType = modalType;
state.isModalVisible = true;
}
// 导出全部按钮
const exportAllbtnz = async () => {
let fields = columns.value.filter(item=>item.visible==true).map(function(item){
return item.dataIndex;
})
if(!fields?.length){
return message.warning("请至少选择一个字段进行导出");
}
let studentReportReq = {
userNo: state.userNo,
name: state.name,
orgId: state.orgId ? state.orgId[state.orgId.length - 1] : null,
bandCode: state.valueBand,
// jobName: state.studentJobName,
}
axios({
method: "post",
url: "/reportsnake/export/report",
data: {
studentReportReq: studentReportReq,
fields: fields,
type: 20
},
responseType: "blob",
headers: {
token: Cookies.get("token"),
},
}).then((res) => {
downLoad(res.data, "学习员工数据.xlsx");
});
};
// 表格 change 事件(分页、排序等)
const handleTableChange = (pag, filters, sorter) => {
const {field, order} = sorter;
if (order) {
state.tableSorts = [{
sortField: field,
sortOrder: order === 'ascend' ? 'asc' : order === 'descend' ? 'desc' : null,
}];
} else {
state.tableSorts = [];
}
getTableData();
};
onMounted(() => {
state.tableLoading = true;
getOrgList();
//getTableData();
});
return {
focusBand,
handleBandChange,
handleCourseTypeChange,
exportAllbtnz,
onSelectChange,
exportbtnz,
reset,
getTableData,
...toRefs(state),
tableData,
columns,
changePagination,
openModal,
handleTableChange,
orgChange,
};
},
};
</script>
<style lang="scss">
.reportSelect .ant-select-selector {
height: 36px !important;
border-radius: 4px !important;
}
.employeelearning {
width: 100%;
height: 100%;
background: #f3f5f9;
.searchForm {
height: 84px;
box-shadow: 1px 0px 4px 0px #dee9ff;
border-radius: 8px 8px 8px 8px;
background: #ffffff;
padding: 24px;
box-sizing: border-box;
}
.content {
background: #ffffff;
box-shadow: 0px 0px 6px 4px rgba(25, 102, 255, 0.06);
border-radius: 8px 8px 8px 8px;
padding: 24px;
margin-top: 12px;
.topToolbar {
display: flex;
justify-content: space-between;
}
}
}
.tableBox {
margin: 13px 0px 0px;
.ant-table-thead > tr > th {
background-color: #e9f0ff;
}
}
.tableBox {
padding-bottom: 0px;
.pa {
// position: absolute;
// bottom: 20px;
// left: 0;
width: 100%;
// height: 20px;
// background-color: red;
display: flex;
justify-content: center;
// margin-bottom: 10px;
// position: absolute;
// bottom: -40px;
}
}
</style>