<template>
|
<div>
|
<div class="top-box-header">
|
<div class="top-box-header-title">
|
<div>项目组总积分表</div>
|
<div class="top-box-header-time">
|
<div>评定开始时间:{{ topData.startTime || '-' }}</div>
|
<div>评定结束时间:{{ topData.endTime || '-' }}</div>
|
</div>
|
</div>
|
<div class="top-box-integral">
|
<div :style="{ backgroundColor: ['rgba(232, 250, 246, 1)', 'rgba(255, 243, 213, 1)', 'rgba(254, 237, 220, 1)', 'rgba(239, 248, 255, 1)', 'rgba(255, 237, 238, 1)'][item - 1] }"
|
v-for="(item,index) in 5" :key="index" class="top-box-integral-card">
|
<div class="top-box-integral-card-title">{{ ['项目组总积分', '工艺工程师积分', '化验师积分', '实验员积分', '实验终止次数'][item -
|
1] }}</div>
|
<div :style="{ color: ['rgba(4, 156, 154, 1)', 'rgba(255, 197, 61, 1)', 'rgba(255, 147, 0, 1)', 'rgba(23, 119, 213, 1)', 'rgba(255, 73, 85, 1)'][item - 1] }"
|
class="top-box-integral-card-num">{{
|
[
|
topData.teamIntegral ?? '0',
|
topData.engineerIntegral ?? '0',
|
topData.chemistIntegral ?? '0',
|
topData.testerIntegral ?? '0',
|
topData.termination ?? '0'
|
][item - 1]
|
}}</div>
|
</div>
|
</div>
|
</div>
|
<div class="integral-content">
|
<div class="integral-content-box">
|
<div class="integral-content-box-left">
|
<div @click="changeActiveItem(item.value)" class="integral-content-box-left-item"
|
:class="actionsLeftTab == item.value && 'activeItem'" v-for="item in leftTabs" :key="item.value">
|
<div>{{ item.label }}</div>
|
<div>工作内容评定</div>
|
</div>
|
</div>
|
<div class="integral-content-box-right">
|
<div v-show="actionsLeftTab == 2" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
|
<div
|
v-for="(item, idx) in chemistTabList"
|
:key="item.userName || idx"
|
@click="changeActiveName(idx)"
|
:class="activeNameTab == idx && 'activeName'"
|
class="integral-content-box-right-nameTab-name"
|
>
|
{{ item.userName }}
|
</div>
|
</div>
|
<!-- <div v-show="actionsLeftTab != 1 && actionsLeftTab != 2" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
|
<div @click="changeActiveName(item)" :class="activeNameTab == item && 'activeName'" class="integral-content-box-right-nameTab-name" v-for="item in 8" :key="item">张三</div>
|
</div> -->
|
<div v-show="actionsLeftTab == 3" @wheel.prevent="handleWheel" class="integral-content-box-right-nameTab">
|
<div
|
v-for="(item, idx) in testerTabList"
|
:key="item.userName || idx"
|
@click="changeActiveName(idx)"
|
:class="activeNameTab == idx && 'activeName'"
|
class="integral-content-box-right-nameTab-name"
|
>
|
{{ item.userName }}
|
</div>
|
</div>
|
<div class="integral-content-box-right-thead">
|
<div>评定项</div>
|
<div>评定情况</div>
|
<div>开始时间</div>
|
<div>结束时间</div>
|
<div v-if="roleType == 1 || roleType == 2">操作</div>
|
</div>
|
<div class="integral-content-box-right-body">
|
<div v-for="(item, idx) in itemList" :key="item.id || idx" class="integral-content-box-right-body-item">
|
<div>{{ item.gainer }}</div>
|
<div>
|
<div v-if="item.situationOne">{{ item.situationOne }}</div>
|
<div v-if="item.situationTwo">{{ item.situationTwo }}</div>
|
</div>
|
<div v-if="item.startTime">{{item.startTime}}</div>
|
<div v-if="item.endTime">{{item.endTime}}</div>
|
<div v-if="roleType == 1 || roleType == 2">
|
<el-button type="text" @click.stop='toChange(item.url)'>{{item.url? '修改':''}}</el-button>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import {
|
getDetailById,
|
getDetailByIdLeftOne,
|
getDetailByIdLeftTwo,
|
getDetailByIdLeftThree,
|
} from "./service";
|
export default {
|
data() {
|
return {
|
actionsLeftTab: 1,
|
activeNameTab: 1,
|
actionspPersonnel: null,
|
roleType: null,
|
leftTabs: [],
|
detailId: null,
|
topData: {},
|
tabData: [],
|
chemistTabList: [], // 化验师tab的人员列表
|
testerTabList: [], // 实验员tab的人员列表
|
craftList: [
|
{
|
gainer: "1、项目可研报告",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "2、项目可行报告",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "3、项目实验室开发阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "4、项目中试试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "5、项目生产验证试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "6、工艺开发工具",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "7、验证与开发",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "8、立项报告",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "9、临床实验积分",
|
situationTwo: "积分数:",
|
url:'/deliveryAssessment/clinicalTrial'
|
},
|
], //工艺工程师-工作内容评定
|
assayList: [
|
{
|
gainer: "1、项目开发阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "2、项目中试试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "3、项目生产验证试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "4、项目检测项、检验包评定",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "5、中试、生产验证试验检验分析报告评定",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "6、原辅料、包材、竞品检验分析报告评定",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "7、产品报批及项目工作总结报告评定",
|
situationOne: "课题数:",
|
situationTwo: "积分数:",
|
},
|
], //化验师-工作内容评定
|
experimentList: [
|
{
|
gainer: "1、项目实验室开发阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "2、项目中试试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "3、项目生产验证试验阶段",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
},
|
{
|
gainer: "4、其他任务",
|
situationOne: "实验数:",
|
situationTwo: "积分数:",
|
url:'/deliveryAssessment/restsTask'
|
},
|
], //实验员-工作内容评定
|
};
|
},
|
computed: {
|
itemList() {
|
return this.tabData || [];
|
},
|
},
|
created() {
|
const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
|
this.roleType = userInfo.roleType;
|
this.initTabs();
|
this.detailId = this.$route.query.id || this.$route.params.id;
|
this.fetchTopData();
|
this.fetchTabData(this.actionsLeftTab);
|
},
|
methods: {
|
initTabs() {
|
if (this.roleType == 3) {
|
// 工艺工程师
|
this.leftTabs = [
|
{ label: "工艺工程师", value: 1 },
|
{ label: "化验师", value: 2 },
|
{ label: "实验员", value: 3 },
|
];
|
} else if (this.roleType == 4) {
|
// 化验师
|
this.leftTabs = [{ label: "化验师", value: 2 }];
|
this.actionsLeftTab = 2;
|
} else if (this.roleType == 5) {
|
// 实验员
|
this.leftTabs = [{ label: "实验员", value: 3 }];
|
this.actionsLeftTab = 3;
|
} else {
|
// 超级管理员、审批人或其他
|
this.leftTabs = [
|
{ label: "工艺工程师", value: 1 },
|
{ label: "化验师", value: 2 },
|
{ label: "实验员", value: 3 },
|
];
|
this.actionsLeftTab = 1;
|
}
|
},
|
fetchTopData() {
|
if (!this.detailId) return;
|
getDetailById({ id: this.detailId }).then((res) => {
|
if (res) {
|
this.topData = res;
|
}
|
});
|
},
|
fetchTabData(tabType) {
|
if (!this.detailId) return;
|
let api;
|
if (tabType == 1) api = getDetailByIdLeftOne;
|
else if (tabType == 2) api = getDetailByIdLeftTwo;
|
else if (tabType == 3) api = getDetailByIdLeftThree;
|
else return;
|
api({ id: this.detailId }).then((res) => {
|
if (res) {
|
if (tabType == 1) {
|
const list = res.engineerList || [];
|
this.craftList = this.craftList.map((item, idx) => {
|
const apiItem = list[idx] || {};
|
let label =
|
item.situationOne && item.situationOne.includes("课题")
|
? "课题数:"
|
: "实验数:";
|
return {
|
...item,
|
situationOne: label + (apiItem.count ?? "0"),
|
situationTwo: "积分数:" + (apiItem.integral ?? "0"),
|
startTime: apiItem.startTime || "-",
|
endTime: apiItem.endTime || "-",
|
};
|
});
|
this.tabData = this.craftList;
|
} else if (tabType == 2) {
|
// 化验师
|
const chemistList = res.chemistList || [];
|
this.chemistTabList = chemistList;
|
this.activeNameTab = 0;
|
this.updateAssayListByChemist(0);
|
} else if (tabType == 3) {
|
const testerList = res.testerList || [];
|
this.testerTabList = testerList;
|
this.activeNameTab = 0;
|
this.updateExperimentListByTester(0);
|
}
|
// 其他tab后续再做
|
}
|
});
|
},
|
updateAssayListByChemist(idx) {
|
const chemist = this.chemistTabList[idx];
|
if (!chemist) {
|
this.tabData = [];
|
return;
|
}
|
const list = chemist.list || [];
|
this.tabData = this.assayList.map((item, i) => {
|
const apiItem = list[i] || {};
|
let label = item.situationOne && item.situationOne.includes("课题") ? "课题数:" : "实验数:";
|
return {
|
...item,
|
situationOne: label + (apiItem.count ?? "0"),
|
situationTwo: "积分数:" + (apiItem.integral ?? "0"),
|
startTime: apiItem.startTime || "-",
|
endTime: apiItem.endTime || "-",
|
};
|
});
|
},
|
updateExperimentListByTester(idx) {
|
const tester = this.testerTabList[idx];
|
if (!tester) {
|
this.tabData = [];
|
return;
|
}
|
const list = tester.list || [];
|
this.tabData = this.experimentList.map((item, i) => {
|
const apiItem = list[i] || {};
|
let label = item.situationOne && item.situationOne.includes("课题") ? "课题数:" : "实验数:";
|
return {
|
...item,
|
situationOne: label + (apiItem.count ?? "0"),
|
situationTwo: "积分数:" + (apiItem.integral ?? "0"),
|
startTime: apiItem.startTime || "-",
|
endTime: apiItem.endTime || "-",
|
};
|
});
|
},
|
changeActiveItem(item) {
|
this.actionsLeftTab = item;
|
this.fetchTabData(item);
|
},
|
changeActiveName(idx) {
|
this.activeNameTab = idx;
|
if (this.actionsLeftTab == 2) {
|
this.updateAssayListByChemist(idx);
|
} else if (this.actionsLeftTab == 3) {
|
this.updateExperimentListByTester(idx);
|
}
|
},
|
handleWheel(e) {
|
if (this.scrollTimer) {
|
this.scrollAmount += e.deltaY;
|
return;
|
}
|
|
const container = e.currentTarget;
|
this.scrollAmount = e.deltaY;
|
|
const scroll = () => {
|
container.scrollLeft += this.scrollAmount * 1.2; // 增加滚动速度
|
this.scrollAmount = 0;
|
this.scrollTimer = null;
|
};
|
|
this.scrollTimer = setTimeout(scroll, 8); // 减少延迟时间
|
},
|
toChange(url){
|
if(url){
|
this.$router.push(url)
|
}
|
}
|
},
|
};
|
</script>
|
|
<style scope lang="less">
|
.top-box-header {
|
&-title {
|
color: #ffffff;
|
padding: 0 20px;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
flex-wrap: wrap;
|
min-height: 58px;
|
padding-bottom: 12px;
|
font-size: 20px;
|
background: linear-gradient(180deg, #05a0c1 0%, #05f2c2 100%);
|
border-radius: 16px 16px 0px 0px;
|
font-family: "Source Han Sans CN Bold Bold";
|
}
|
|
&-time {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
font-family: "SourceHanSansCN-Medium";
|
font-size: 16px;
|
|
div:first-child {
|
margin-right: 57px;
|
}
|
}
|
|
.top-box-integral {
|
padding: 42px 30px 38px 30px;
|
margin-top: -12px;
|
background: linear-gradient(
|
180deg,
|
#ffffff 0%,
|
rgba(255, 255, 255, 0.2) 100%
|
);
|
box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06);
|
border-radius: 16px;
|
border: 4px solid #ffffff;
|
display: flex;
|
justify-content: space-between;
|
flex-wrap: wrap;
|
gap: 28px;
|
|
&-card {
|
flex: 1;
|
background: #e8faf6;
|
box-shadow: 0px 10px 10px 0px rgba(0, 0, 0, 0.06);
|
border-radius: 10px;
|
padding: 21px 20px;
|
|
&-title {
|
font-family: "SourceHanSansCN-Medium";
|
font-size: 14px;
|
color: rgba(0, 0, 0, 0.8);
|
}
|
|
&-num {
|
font-family: "SF Compact Display Black";
|
text-align: center;
|
font-weight: 900;
|
font-size: 50px;
|
color: #049c9a;
|
line-height: 60px;
|
}
|
}
|
}
|
}
|
|
.integral-content {
|
margin-top: 20px;
|
padding: 30px 30px 95px 30px;
|
background: rgba(255, 255, 255, 0.8);
|
box-shadow: 0px 10px 19px 0px rgba(0, 0, 0, 0.06);
|
border-radius: 16px;
|
border: 4px solid #ffffff;
|
|
&-box {
|
display: flex;
|
|
&-left {
|
display: flex;
|
flex-direction: column;
|
gap: 10px;
|
margin-right: 30px;
|
margin-top: 50px;
|
|
.activeItem {
|
background: linear-gradient(
|
180deg,
|
rgba(5, 160, 193, 0.4) 0%,
|
rgba(5, 242, 194, 0) 100%
|
);
|
border-image: linear-gradient(
|
180deg,
|
rgba(10, 203, 202, 1),
|
rgba(4, 156, 154, 0.2)
|
)
|
1 1;
|
clip-path: inset(0 round 10px);
|
filter: hue-rotate(360deg);
|
}
|
|
&-item {
|
cursor: pointer;
|
width: 160px;
|
height: 170px;
|
font-family: "Source Han Sans CN Bold Bold";
|
font-weight: bold;
|
font-size: 20px;
|
color: #049c9a;
|
display: flex;
|
text-align: center;
|
flex-direction: column;
|
justify-content: center;
|
line-height: 30px;
|
background: #eff8fa;
|
border-radius: 10px;
|
border: 1px solid;
|
clip-path: inset(0px round 10px);
|
filter: hue-rotate(360deg);
|
border-image: linear-gradient(
|
180deg,
|
rgba(220, 223, 230, 1),
|
rgba(220, 223, 230, 1)
|
)
|
1 1;
|
|
&:hover {
|
background: linear-gradient(
|
180deg,
|
rgba(5, 160, 193, 0.4) 0%,
|
rgba(5, 242, 194, 0) 100%
|
);
|
border-image: linear-gradient(
|
180deg,
|
rgba(10, 203, 202, 1),
|
rgba(4, 156, 154, 0.2)
|
)
|
1 1;
|
clip-path: inset(0 round 10px);
|
filter: hue-rotate(360deg);
|
}
|
}
|
}
|
|
&-right {
|
flex: 1;
|
min-width: 0;
|
overflow: hidden;
|
|
&-nameTab {
|
flex: 1;
|
min-width: 0;
|
display: flex;
|
overflow-x: auto;
|
gap: 10px;
|
scroll-behavior: auto; // 移除平滑滚动,提高性能
|
-webkit-overflow-scrolling: touch;
|
|
&-name {
|
cursor: pointer;
|
text-align: center;
|
font-weight: 400;
|
font-size: 18px;
|
color: #606266;
|
background: #fafafc;
|
border-radius: 8px 8px 0px 0px;
|
border: 1px solid #dcdfe6;
|
line-height: 50px;
|
min-width: 94px;
|
margin-bottom: 10px;
|
}
|
|
.activeName {
|
border: 1px solid #049c9a;
|
background: #ffffff;
|
font-weight: bold;
|
font-size: 18px;
|
color: #049c9a;
|
}
|
}
|
|
&-thead {
|
display: flex;
|
flex-wrap: wrap;
|
|
div {
|
font-family: "SourceHanSansCN-Medium";
|
font-weight: 500;
|
font-size: 20px;
|
color: #ffffff;
|
text-align: center;
|
line-height: 40px;
|
flex: 1;
|
background: linear-gradient(270deg, #0acbca 0%, #049c9a 100%);
|
box-shadow: 0px 6px 10px 0px rgba(4, 156, 154, 0.09);
|
border-radius: 10px;
|
}
|
}
|
|
&-body {
|
margin-top: 10px;
|
display: flex;
|
flex-direction: column;
|
gap: 10px;
|
|
&-item {
|
display: flex;
|
flex-wrap: wrap;
|
|
& > div {
|
padding-left: 23px;
|
font-family: "SourceHanSansCN-Medium";
|
flex: 1;
|
font-weight: 500;
|
font-size: 16px;
|
color: #606266;
|
display: flex;
|
align-items: center;
|
min-height: 50px;
|
background: #d7eff4;
|
box-shadow: 0px 6px 10px 0px rgba(4, 156, 154, 0.09);
|
border-radius: 10px;
|
|
&:nth-child(2) {
|
display: flex;
|
align-items: center;
|
flex-wrap: wrap;
|
justify-content: space-between;
|
|
& div:last-child {
|
flex-shrink: 0;
|
margin-right: 84px;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
</style>
|