feat:完成指挥部大屏安全教育和和项目总览弹窗开发

This commit is contained in:
Vce 2024-07-05 15:30:26 +08:00
parent e8b9db8c66
commit 18a096c551
6 changed files with 4212 additions and 67 deletions

View File

@ -63,6 +63,20 @@ export const getSpecialSideStationApi = (params: {}) => {
export const getSafeEducationDataApi = (params: {}) => { export const getSafeEducationDataApi = (params: {}) => {
return http.post(BASEURL + `/xmgl/xzWorkerInfoAuditRecord/selectWorkerInfoAuditList`, params, { headers: { noLoading: true } }); return http.post(BASEURL + `/xmgl/xzWorkerInfoAuditRecord/selectWorkerInfoAuditList`, params, { headers: { noLoading: true } });
}; };
export const getEduPlanDataApi = (params: {}) => {
return http.post(BASEURL + `/exam/train/page`, params, { headers: { noLoading: true } });
};
//培训详情
//(未)学习记录
export const getStudyDataApi = (params: {}) => {
// return http.post(BASEURL + `/exam/courseRecord/page`, params, { headers: { noLoading: true } });
return http.post(BASEURL + `/exam/courseRecord/list`, params, { headers: { noLoading: true } });
};
//(未)考试记录
export const getExamDataApi = (params: {}) => {
// return http.post(BASEURL + `/exam/trainRecord/examRecordPage`, params, { headers: { noLoading: true } });
return http.post(BASEURL + `/exam/trainRecord/list`, params, { headers: { noLoading: true } });
};
// 天气弹窗 // 天气弹窗
// 顶部数据 // 顶部数据
@ -152,8 +166,8 @@ export const queryAttendanceOfEachCompanyApi = (params: {}, showLoading: boolean
}; };
// 进度情况分析 // 进度情况分析
// 项目总进度/项目剩余天数 // 项目总进度/项目剩余天数
export const getCountTaskProgressApi = (params: {}, showLoading: boolean) => { export const getCountTaskProgressApi = (params: {}) => {
return http.post(BASEURL + `/xmgl/xzTaskProgress/countTaskProgress`, params, { headers: { noLoading: showLoading } }); return http.post(BASEURL + `/xmgl/xzTaskProgress/countTaskProgress`, params, { headers: { noLoading: true } });
}; };
// 总包进度列表 // 总包进度列表
export const queryCountEnterpriseApi = (params: {}, showLoading: boolean) => { export const queryCountEnterpriseApi = (params: {}, showLoading: boolean) => {
@ -204,3 +218,17 @@ export const getRiskTrendByProjectApi = (params: {}, showLoading: boolean) => {
export const getRiskTrendByMainEnterpriseApi = (params: {}, showLoading: boolean) => { export const getRiskTrendByMainEnterpriseApi = (params: {}, showLoading: boolean) => {
return http.post(BASEURL + `/xmgl/xzRiskPrediction/riskTrendByMainEnterprise`, params, { headers: { noLoading: showLoading } }); return http.post(BASEURL + `/xmgl/xzRiskPrediction/riskTrendByMainEnterprise`, params, { headers: { noLoading: showLoading } });
}; };
// 甘特图接口开始位置
export const getQualityRegionListApi = (params: {}) => {
return http.post(BASEURL + `/xmgl/qualityRegion/list`, params, { headers: { noLoading: true } });
};
export const selectHierarchyEnterpriseListApi = (params: {}) => {
return http.post(BASEURL + `/xmgl/enterpriseInfo/selectHierarchyEnterpriseList`, params, { headers: { noLoading: true } });
};
export const getXzParentChildTaskListApi = (params: {}) => {
return http.post(BASEURL + `/xmgl/xzTaskProgress/getParentChildList`, params, { headers: { noLoading: true } });
};
// 甘特图接口结束位置

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -86,10 +86,10 @@
<div class="classify-div-item" style="width: 250px" @click="openDialogData({ index: 1, title: '' })"> <div class="classify-div-item" style="width: 250px" @click="openDialogData({ index: 1, title: '' })">
<span style="font-size: 12px">危险特殊作业&nbsp;{{ statsDirectorateBigScreen.dangerousEngineeringRecordNum }}</span> <span style="font-size: 12px">危险特殊作业&nbsp;{{ statsDirectorateBigScreen.dangerousEngineeringRecordNum }}</span>
</div> </div>
<div class="classify-div-item" style="width: 210px" @click="openDialogData({ index: 2, title: '安全教育' })"> <div class="classify-div-item" style="width: 210px" @click="openDialogData({ index: 2, title: '' })">
<span style="font-size: 12px">安全教育&nbsp;{{ statsDirectorateBigScreen.workerInfoAuditRecordNum }}</span> <span style="font-size: 12px">安全教育&nbsp;{{ statsDirectorateBigScreen.workerInfoAuditRecordNum }}</span>
</div> </div>
<div class="classify-div-item" style="width: 300px" @click="openDialogData({ index: 3, title: '影响进度计划因素' })"> <div class="classify-div-item" style="width: 300px" @click="openDialogData({ index: 3, title: '' })">
<span style="font-size: 12px">影响进度计划因素&nbsp;{{ statsDirectorateBigScreen.taskProgressContentNum }}</span> <span style="font-size: 12px">影响进度计划因素&nbsp;{{ statsDirectorateBigScreen.taskProgressContentNum }}</span>
</div> </div>
<div class="classify-div-item" @click="openDialogData({ index: 4, title: '风险统计' })"> <div class="classify-div-item" @click="openDialogData({ index: 4, title: '风险统计' })">
@ -104,7 +104,7 @@
</div> </div>
<div class="classify-div-item" @click="openDialogData({ index: 99, title: '质量管理' })"> <div class="classify-div-item" @click="openDialogData({ index: 99, title: '质量管理' })">
<span style="font-size: 12px" <span style="font-size: 12px"
>质量管理&nbsp;{{ statsDirectorateBigScreen.securityQualityInspectionRecordNum }}</span >质量管理&nbsp;{{ statsDirectorateBigScreen.qualityInspectionRecordNum }}</span
> >
</div> </div>
<div class="classify-div-item" @click="openDialogData({ index: 6, title: 'AI警报' })"> <div class="classify-div-item" @click="openDialogData({ index: 6, title: 'AI警报' })">
@ -917,6 +917,7 @@ onMounted(async () => {
// padding: 0 5px; // padding: 0 5px;
span { span {
cursor: pointer;
margin-top: 10px; margin-top: 10px;
} }
} }

View File

@ -1,50 +1,15 @@
<template> <template>
<div class="political-outlook"> <div class="political-outlook">
<div class="content"> <div class="tabBox">
<!-- <div class="top-statistics"> <div :class="{'danger':true,active: currentTab == 'safeEdu' ? true : false}">
<div class="statistics-item"> <span @click="handleChangeTab('safeEdu')">入场前安全教育</span>
<span class="title">三级入场教育</span>
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div> </div>
<div class="statistics-item"> <div :class="{'danger':true,active: currentTab == 'eduPlan' ? true : false}">
<span class="title">特种作业人员安全教育</span> <span @click="handleChangeTab('eduPlan')">入场后培训计划</span>
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div> </div>
<div class="statistics-item">
<span class="title">日常安全教育</span>
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div> </div>
<div class="statistics-item">
<span class="title">安全技术交底</span> <div class="content" v-if="currentTab == 'safeEdu'">
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div>
<div class="statistics-item">
<span class="title">施工技术交流</span>
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div>
<div class="statistics-item">
<span class="title">VR安全教育</span>
<span class="statistics-item-content">总数1</span>
<span class="statistics-item-content">完成率1</span>
<span class="statistics-item-content">已完成1</span>
<span class="statistics-item-content">100%</span>
</div>
</div> -->
<div class="table-one"> <div class="table-one">
<div class="tabList"> <div class="tabList">
<div>序号</div> <div>序号</div>
@ -105,13 +70,189 @@
</el-scrollbar> </el-scrollbar>
</div> </div>
</div> </div>
<div class="content" v-if="currentTab == 'eduPlan'">
<div style="height:100%" v-if="!isDetail">
<div class="searchLine">
<span style="margin-right:5px">培训计划名称</span>
<el-input v-model="eduPlanName" clearable size="small" style="width: 150px" @input="handleInput" placeholder="请输入培训计划名称" />
</div>
<div class="table-one">
<div class="tabList">
<div>序号</div>
<div>培训计划名称</div>
<div>科目名称</div>
<div style="width:180px">教育主题</div>
<div style="width:350px">培训有效时限</div>
<div>教育人员</div>
<div>创建人</div>
<div>培训完成率</div>
<div>培训通过率</div>
<div>操作</div>
</div>
<el-scrollbar class="listBox" ref="refScrollbar">
<div v-for="(item, index) in partyMemberList" class="listStyle" :key="item.id">
<div>{{ index + 1 }}</div>
<div>
<el-tooltip class="box-item" style="text-align:center" effect="dark" :content="item.name" placement="top-start">
<span>{{ item.name || '--' }}</span>
</el-tooltip>
</div>
<div>{{ item.subjectName || '--' }}</div>
<div style="width:180px">
<el-tooltip class="box-item" style="text-align:center" effect="dark" :content="item.title" placement="top-start">
<span>{{ item.title || '--' }}</span>
</el-tooltip>
</div>
<div style="width:350px">{{ item.trainBeginTime || '--'}} - {{item.trainEndTime || '--' }}</div>
<div>{{ item.workerNum || '--' }}</div>
<div>{{ item.createByName || '--' }}</div>
<div>{{ item.completeRadio ? item.completeRadio + '%' : '--' }}</div>
<div>{{ item.passRadio ? item.passRadio + '%' : '--' }}</div>
<div style="color:#5382f6;cursor:pointer;" @click="handleOpenDetail(item)">查看培训详情</div>
</div>
<div class="notoDta" v-if="partyMemberList.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</el-scrollbar>
</div>
</div>
<div style="height:100%;" v-else>
<div class="searchLine" style="font-size:14px;left:91.6%;top:18%;z-index:99;cursor:pointer" @click="handleCloseDetail">{{'<<'}}返回</div>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleDetailTab">
<el-tab-pane :label="'学习记录'" name="first">
<div class="table-one" style="transform:translateY(-20px)">
<div class="tabList" style="justify-content:space-around">
<div>序号</div>
<div>姓名</div>
<div>课程名称</div>
<div>身份证号</div>
<div>培训计划名称</div>
<div>开始学习时间</div>
<div>结束学习时间</div>
</div>
<el-scrollbar class="listBox" ref="refScrollbar" style="height:420px">
<div v-for="(item, index) in studyExamRecord" class="listStyle" :key="item" style="justify-content:space-around">
<div>{{ index + 1 }}</div>
<div>{{ item.workerName || '--' }}</div>
<div>{{ item.courseName || '--' }}</div>
<div>{{ item.workerCard || '--' }}</div>
<div>{{ eduPlanItem.name || '--' }}</div>
<div>{{ item.beginTime || '--' }}</div>
<div>{{ item.endTime || '--' }}</div>
</div>
<div class="notoDta" v-if="studyExamRecord.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</el-scrollbar>
</div>
</el-tab-pane>
<el-tab-pane :label="'考试记录'" name="second">
<div class="table-one" style="transform:translateY(-20px)">
<div class="tabList" style="justify-content:space-around">
<div>序号</div>
<div>姓名</div>
<div>科目名称</div>
<div>考试名称</div>
<div>培训计划名称</div>
<div>身份证号</div>
<div>开始考试时间</div>
<div>作答时长</div>
<div>考试结果</div>
<div>考试总分</div>
<div>考得分</div>
<div>剩余重考次数</div>
</div>
<el-scrollbar class="listBox" ref="refScrollbar" style="height:420px">
<div v-for="(item, index) in studyExamRecord" class="listStyle" :key="item" style="justify-content:space-around">
<div>{{ index + 1 }}</div>
<div>{{ item.workerName || '--' }}</div>
<div>{{ item.subjectName || '--' }}</div>
<div>{{ item.examPaperName || '--' }}</div>
<div>{{ eduPlanItem.name || '--' }}</div>
<div>{{ item.workerCard || '--' }}</div>
<div>{{ item.startExamTime || '--' }}</div>
<div>{{ item.duration || '--' }}</div>
<div>{{ item.isPass || '--' }}</div>
<div>{{ item.totalScore || '--' }}</div>
<div>{{ item.score || '--' }}</div>
<div>{{ item.examCount || '--' }}</div>
</div>
<div class="notoDta" v-if="studyExamRecord.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</el-scrollbar>
</div>
</el-tab-pane>
<el-tab-pane :label="'未学习记录'" name="third">
<div class="table-one" style="transform:translateY(-20px);">
<div class="tabList" style="justify-content:space-around">
<div>序号</div>
<div>姓名</div>
<div>身份证号</div>
<div>培训计划名称</div>
<div>科目类型</div>
<div>课程名称</div>
</div>
<el-scrollbar class="listBox" ref="refScrollbar" style="height:420px">
<div v-for="(item, index) in studyExamRecord" class="listStyle" :key="item" style="justify-content:space-around">
<div>{{ index + 1 }}</div>
<div>{{ item.workerName || '--' }}</div>
<div>{{ item.workerCard || '--' }}</div>
<div>{{ eduPlanItem.name || '--' }}</div>
<div>{{ eduPlanItem.subjectName || '--' }}</div>
<div>{{ eduPlanItem.courseName || '--' }}</div>
</div>
<div class="notoDta" v-if="studyExamRecord.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</el-scrollbar>
</div>
</el-tab-pane>
<el-tab-pane :label="'未考试记录'" name="four">
<div class="table-one" style="transform:translateY(-20px)">
<div class="tabList" style="justify-content:space-around">
<div>序号</div>
<div>姓名</div>
<div>身份证号</div>
<div>培训计划名称</div>
<div>科目类型</div>
<div>考试名称</div>
</div>
<el-scrollbar class="listBox" ref="refScrollbar" style="height:420px;">
<div v-for="(item, index) in studyExamRecord" class="listStyle" :key="item" style="justify-content:space-around">
<div>{{ index + 1 }}</div>
<div>{{ item.workerName || '--' }}</div>
<div>{{ item.workerCard || '--' }}</div>
<div>{{ eduPlanItem.name || '--' }}</div>
<div>{{ eduPlanItem.subjectName || '--' }}</div>
<div>{{ eduPlanItem.paperName || '--' }}</div>
</div>
<div class="notoDta" v-if="studyExamRecord.length == 0">
<img src="@/assets/images/noData.png" alt="" />
<p>暂无数据</p>
</div>
</el-scrollbar>
</div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { GlobalStore } from "@/stores"; import { GlobalStore } from "@/stores";
import { getSafeEducationDataApi } from "@/api/modules/agjtCommandApi"; import type { TabsPaneContext } from 'element-plus'
import { getSafeEducationDataApi,getEduPlanDataApi,
getStudyDataApi,getExamDataApi
} from "@/api/modules/agjtCommandApi";
const store = GlobalStore(); const store = GlobalStore();
const props = defineProps(["tip"]); const props = defineProps(["tip"]);
const BASEURL = import.meta.env.VITE_API_URL; const BASEURL = import.meta.env.VITE_API_URL;
@ -119,6 +260,82 @@ let pageNo = ref(1 as any);
let moreScroll = ref(true as any); let moreScroll = ref(true as any);
const refScrollbar = ref(null as any); // const refScrollbar = ref(null as any); //
//tab
const currentTab = ref('safeEdu' as any)
function handleChangeTab(val: any){
//
isDetail.value = false
activeIndex.value = 0
//
currentTab.value = val
partyMemberList.value = []
pageNo.value = 1
getMemberCountList('search')
}
//
const eduPlanItem = ref('' as any)
const isDetail = ref(false as any)
//tab
const activeIndex = ref(0 as any)
const activeName = ref('first' as any)
const studyExamRecord = ref('' as any)
//
const handleOpenDetail = async(item: any) => {
isDetail.value = true
eduPlanItem.value = item
getStudyExamData()
}
const handleCloseDetail = async() => {
activeIndex.value = 0
isDetail.value = false
}
//tab
const handleDetailTab = async (tab: TabsPaneContext, event: Event) => {
if(tab.index == activeIndex.value) return;
activeIndex.value = tab.index
getStudyExamData()
}
const getStudyExamData = async() => {
let data:any = {
projectSn: store.sn,
trainId: eduPlanItem.value.id
}
if(activeIndex.value == 0){
data.number = 1;
await getStudyDataApi(data).then((res:any) => {
if(res.success){
studyExamRecord.value = res.result
}
})
}
if(activeIndex.value == 1){
data.examNum = 1;
await getExamDataApi(data).then((res:any) => {
if(res.success){
studyExamRecord.value = res.result
}
})
}
if(activeIndex.value == 2){
data.number = 0;
await getStudyDataApi(data).then((res:any) => {
if(res.success){
studyExamRecord.value = res.result
}
})
}
if(activeIndex.value == 3){
data.examNum = 0;
await getExamDataApi(data).then((res:any) => {
if(res.success){
studyExamRecord.value = res.result
}
})
}
}
const eduPlanName = ref(''as any)
const partyMemberList = ref({} as any); const partyMemberList = ref({} as any);
// //
const getMemberCountList = async (tip: any) => { const getMemberCountList = async (tip: any) => {
@ -134,7 +351,14 @@ const getMemberCountList = async (tip: any) => {
} else { } else {
requestData.inserviceType = 1; requestData.inserviceType = 1;
} }
const res: any = await getSafeEducationDataApi(requestData); // const res: any = await getSafeEducationDataApi(requestData);
let res: any = null
if(currentTab.value == 'safeEdu') {
res = await getSafeEducationDataApi(requestData);
}else{
requestData.name = eduPlanName.value
res = await getEduPlanDataApi(requestData)
}
if (tip == "more") { if (tip == "more") {
partyMemberList.value = partyMemberList.value.concat(res.result.records); partyMemberList.value = partyMemberList.value.concat(res.result.records);
} else { } else {
@ -150,6 +374,12 @@ const getMemberCountList = async (tip: any) => {
pageNo.value = pageNo.value + 1; pageNo.value = pageNo.value + 1;
} }
}; };
//
const handleInput = async () => {
partyMemberList.value = []
pageNo.value = 1
getMemberCountList('search')
}
onMounted(async () => { onMounted(async () => {
await getMemberCountList("search"); await getMemberCountList("search");
@ -175,6 +405,40 @@ onMounted(async () => {
.political-outlook { .political-outlook {
height: 97%; height: 97%;
margin: 0 60px; margin: 0 60px;
.tabBox{
position: absolute;
top: 6%;
left: 3.5%;
width:360px;
height:50px;
// background-color: #fff;
color: gray;
font-weight: bold;
font-size: 20px;
font-style: italic;
display: flex;
justify-content: space-around;
align-items: center;
.danger{
width:50%;
height:100%;
display: flex;
justify-content: space-around;
align-items: center;
cursor: pointer;
}
.special{
width:50%;
height:100%;
display: flex;
justify-content: space-around;
align-items: center;
cursor: pointer;
}
.active{
color:#fff
}
}
.content { .content {
height: 95%; height: 95%;
width: 100%; width: 100%;
@ -182,6 +446,12 @@ onMounted(async () => {
// background: url("@/assets/images/cardImg.png") no-repeat; // background: url("@/assets/images/cardImg.png") no-repeat;
background-size: 100% 100%; background-size: 100% 100%;
padding: 20px 15px; padding: 20px 15px;
.searchLine{
color:#fff;
position: absolute;
top:15.65%;
left:5%;
}
.top-statistics { .top-statistics {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr);
@ -258,6 +528,7 @@ onMounted(async () => {
div { div {
text-align: center; text-align: center;
width: 10%; width: 10%;
padding: 0 5px;
} }
} }
.listBox { .listBox {
@ -286,6 +557,7 @@ onMounted(async () => {
white-space: nowrap; // white-space: nowrap; //
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
padding: 0 5px;
} }
} }
.listStyle:hover { .listStyle:hover {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff