恢复 dietaryNutritionTips8 的代码

This commit is contained in:
17792275749
2026-01-05 18:19:24 +08:00
parent cb6e764bb7
commit 8b0d8dfbf3
@@ -9,11 +9,16 @@
<div class="title">
<div></div>
<div>
<div>体重管理行动{{ dataConfig.personnelType === 'staff' ? '员工' : '部门' }}</div>
<div>
体重管理行动{{
dataConfig.personnelType === "staff" ? "员工" : "部门"
}}
</div>
<div>
<div>{{ dataConfig.currentDate }}</div>
<div>
行动开始第<span>{{ dataConfig.doingDay }}</span>
行动开始第<span>{{ dataConfig.doingDay }}</span
>
</div>
</div>
</div>
@@ -34,7 +39,11 @@
</div>
<div class="contentBody" ref="scrollContentBody">
<template v-if="dataConfig.list && dataConfig.list.length">
<div class="contentBodyList" v-for="(item, index) in dataConfig.list" :key="index">
<div
class="contentBodyList"
v-for="(item, index) in dataConfig.list"
:key="`${item.rank}-${item.realName || item.orgName}`"
>
<template v-if="dataConfig.personnelType === 'staff'">
<div>{{ item.rank }}</div>
<div>{{ item.departName }}</div>
@@ -65,13 +74,28 @@
</template>
<script>
import { shallowRef, markRaw, triggerRef } from "vue";
import { httpRequest } from "@/XMLHttpRequest";
export default {
name: "dietaryNutritionTips",
setup() {
// 极限优化:使用 shallowRef 避免深度响应式,降低内存占用
const dataConfig = shallowRef({
personnelType: "department",
currentDate: "",
doingDay: "",
list: [], // 这个数组会用 markRaw 包裹,完全避免响应式
startDay: "-",
});
return {
dataConfig,
};
},
data() {
return {
isLoading: false, // 极限规避请求锁
isLoading: false, // 极限规避:请求锁
rankingConfig: {
personnelType: "department",
requestConfig: {
@@ -79,43 +103,56 @@ export default {
url: "api.cqygjk.com",
suffix: "",
urlPrefix: "/health-weight/api/anon",
orgCode: ""
orgCode: "",
},
setTimeOutFun: null
},
dataConfig: {
personnelType: "department",
currentDate: "",
doingDay: "",
list: [],
startDay: "-",
setTimeOutFun: null,
},
scrollConfig: {
scrollAnimationFrameId: null,
scrollSpeed: 2,
dynamicScrollWaitTime: 6
}
dynamicScrollWaitTime: 6,
},
reloadTimer: null, // 2小时reload兜底定时器
};
},
created() {
this.initParams();
this.load("department");
this.initDailyScheduler(); // 启动时间更新与零点刷新逻辑
this.initReloadFallback(); // 启动2小时reload兜底策略
},
beforeDestroy() {
this.stopAllLoops();
if (this.reloadTimer) {
clearTimeout(this.reloadTimer);
this.reloadTimer = null;
}
},
methods: {
initParams() {
let url = this.$route.query.url;
if (url) this.rankingConfig.requestConfig.url = Array.isArray(url) ? url[0] : url;
if (url)
this.rankingConfig.requestConfig.url = Array.isArray(url)
? url[0]
: url;
let code = this.$route.query.orgCode;
if (code) this.rankingConfig.requestConfig.orgCode = Array.isArray(code) ? code[0] : code;
if (code)
this.rankingConfig.requestConfig.orgCode = Array.isArray(code)
? code[0]
: code;
},
// 极限规避:时间管理与凌晨 0 点强制刷新
initDailyScheduler() {
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const weekDays = [
"星期日",
"星期一",
"星期二",
"星期三",
"星期四",
"星期五",
"星期六",
];
setInterval(() => {
const now = new Date();
@@ -126,11 +163,15 @@ export default {
// 1. 每秒更新一次界面日期信息
const year = now.getFullYear();
const month = (now.getMonth() + 1).toString().padStart(2, "0");
const day = (now.getDate()).toString().padStart(2, "0");
const day = now.getDate().toString().padStart(2, "0");
const week = now.getDay();
this.dataConfig.currentDate = `${year}${month}${day}${weekDays[week]}`;
this.dataConfig.doingDay = this.daysSinceDate("2025-05-07");
this.dataConfig.startDay = "2025年5月7日";
// 使用浅层更新,手动触发响应
this.dataConfig.value = {
...this.dataConfig.value,
currentDate: `${year}${month}${day}${weekDays[week]}`,
doingDay: this.daysSinceDate("2025-05-07"),
startDay: "2025年5月7日",
};
// 2. 极限规避:凌晨 00:00:00 强制刷新整个页面
// 彻底释放内存、清除过期缓存、重置字体渲染引擎
@@ -141,6 +182,16 @@ export default {
}, 1000);
},
// 极限规避:2小时自动reload兜底策略
// 配合凌晨0点刷新,确保即使出现内存泄漏也能定期释放
initReloadFallback() {
this.reloadTimer = setTimeout(() => {
console.log("[兜底策略] 2小时到期,执行页面刷新释放内存");
sessionStorage.clear();
window.location.reload();
}, 1000 * 60 * 60 * 2); // 2小时
},
stopAllLoops() {
if (this.scrollConfig.scrollAnimationFrameId) {
cancelAnimationFrame(this.scrollConfig.scrollAnimationFrameId);
@@ -184,30 +235,45 @@ export default {
Promise.all([
_this.orgCodeRequest(fullUrl + "A01A86"),
_this.orgCodeRequest(fullUrl + "A01A37"),
]).then((res) => {
const processedData = _this.combineAndSortAndTakeTop50(res[0], res[1], type);
])
.then((res) => {
const processedData = _this.combineAndSortAndTakeTop50(
res[0],
res[1],
type
);
// 存储带 OrgCode 的唯一缓存
const cacheKey = `weight_${type}_${config.orgCode}`;
sessionStorage.setItem(cacheKey, JSON.stringify(processedData));
// 存储带 OrgCode 的唯一缓存
const cacheKey = `weight_${type}_${config.orgCode}`;
sessionStorage.setItem(cacheKey, JSON.stringify(processedData));
// 只有类型匹配才更新渲染
if (_this.rankingConfig.personnelType === type) {
_this.renderUI(processedData, type);
}
}).catch(() => {
if (_this.rankingConfig.personnelType === type) {
_this.dataConfig.list = [];
_this.startBannerLoop();
}
}).finally(() => {
_this.isLoading = false;
});
// 只有类型匹配才更新渲染
if (_this.rankingConfig.personnelType === type) {
_this.renderUI(processedData, type);
}
})
.catch(() => {
if (_this.rankingConfig.personnelType === type) {
_this.dataConfig.value = {
..._this.dataConfig.value,
list: markRaw([]),
};
_this.startBannerLoop();
}
})
.finally(() => {
_this.isLoading = false;
});
},
renderUI(data, type) {
this.dataConfig.personnelType = type;
this.dataConfig.list = data;
// 极限优化:使用 markRaw 冻结数据,告诉 Vue 永远不要将其转为响应式
// 排行榜数据只需整体替换,不需要深度监听每个属性
this.dataConfig.value = {
...this.dataConfig.value,
personnelType: type,
list: markRaw(data), // 关键:冻结数组,避免响应式开销
};
this.$nextTick(() => {
this.startOneTimeScroll();
});
@@ -215,9 +281,11 @@ export default {
orgCodeRequest(requestUrl) {
return new Promise((resolve, reject) => {
httpRequest("POST", requestUrl, {}, {}).then((res) => {
resolve(res.result.rankList || []);
}).catch(() => reject());
httpRequest("POST", requestUrl, {}, {})
.then((res) => {
resolve(res.result.rankList || []);
})
.catch(() => reject());
});
},
@@ -236,22 +304,28 @@ export default {
currentScrollTop += this.scrollConfig.scrollSpeed;
if (currentScrollTop > maxScrollTop) currentScrollTop = maxScrollTop;
container.scrollTop = currentScrollTop;
this.scrollConfig.scrollAnimationFrameId = requestAnimationFrame(animateScroll);
this.scrollConfig.scrollAnimationFrameId =
requestAnimationFrame(animateScroll);
} else {
this.scrollConfig.scrollAnimationFrameId = null;
this.rankingConfig.setTimeOutFun = setTimeout(() => {
const nextType = this.rankingConfig.personnelType === "staff" ? "department" : "staff";
const nextType =
this.rankingConfig.personnelType === "staff"
? "department"
: "staff";
this.load(nextType);
}, this.scrollConfig.dynamicScrollWaitTime * 1000);
}
};
this.scrollConfig.scrollAnimationFrameId = requestAnimationFrame(animateScroll);
this.scrollConfig.scrollAnimationFrameId =
requestAnimationFrame(animateScroll);
},
startBannerLoop() {
this.rankingConfig.setTimeOutFun = setTimeout(() => {
const nextType = this.rankingConfig.personnelType === "staff" ? "department" : "staff";
const nextType =
this.rankingConfig.personnelType === "staff" ? "department" : "staff";
this.load(nextType);
}, 5000);
},
@@ -268,40 +342,54 @@ export default {
const combinedArray = arr1.concat(arr2);
let processedArray = [];
if(personnelType === "department") {
processedArray = combinedArray.filter(item =>
item.orgName && item.orgName !== "公司机关"
if (personnelType === "department") {
processedArray = combinedArray.filter(
(item) => item.orgName && item.orgName !== "公司机关"
);
} else {
const departmentsToReplace = [
"综合管理部", "人力资源部", "计划财务部", "安全与设备管理部",
"矿区建设中心", "物业后勤中心", "健康服务中心", "社会服务中心",
"机关事务中心", "交通服务中心"
"综合管理部",
"人力资源部",
"计划财务部",
"安全与设备管理部",
"矿区建设中心",
"物业后勤中心",
"健康服务中心",
"社会服务中心",
"机关事务中心",
"交通服务中心",
];
processedArray = combinedArray.filter(item =>
item.departName !== "部领导" && item.departName !== "助理副总师"
).map(item => {
if (departmentsToReplace.includes(item.departName)) {
return { ...item, departName: "公共事务中心" };
}
return item;
});
processedArray = combinedArray
.filter(
(item) =>
item.departName !== "部领导" && item.departName !== "助理副总师"
)
.map((item) => {
if (departmentsToReplace.includes(item.departName)) {
return { ...item, departName: "公共事务中心" };
}
return item;
});
}
const sorted = processedArray.sort((a, b) => parseFloat(b.value) - parseFloat(a.value));
const sorted = processedArray.sort(
(a, b) => parseFloat(b.value) - parseFloat(a.value)
);
let currentRank = 1;
let previousValue = null;
return sorted.map((item, index) => {
const val = parseFloat(item.value);
if (index !== 0 && val !== previousValue) {
currentRank++;
}
previousValue = val;
return { ...item, rank: currentRank };
}).filter(item => item.rank <= 50);
}
}
return sorted
.map((item, index) => {
const val = parseFloat(item.value);
if (index !== 0 && val !== previousValue) {
currentRank++;
}
previousValue = val;
return { ...item, rank: currentRank };
})
.filter((item) => item.rank <= 50);
},
},
};
</script>
@@ -334,7 +422,11 @@ export default {
> div:nth-of-type(1) {
width: 120px;
height: 4px;
background: linear-gradient(270deg, #ffc87c 0%, rgba(42, 199, 159, 0) 100%);
background: linear-gradient(
270deg,
#ffc87c 0%,
rgba(42, 199, 159, 0) 100%
);
border-radius: 2px;
}
@@ -350,7 +442,11 @@ export default {
> div:nth-of-type(3) {
width: 120px;
height: 4px;
background: linear-gradient(90deg, #ffc87c 0%, rgba(42, 199, 159, 0) 100%);
background: linear-gradient(
90deg,
#ffc87c 0%,
rgba(42, 199, 159, 0) 100%
);
border-radius: 2px;
}
}
@@ -382,7 +478,12 @@ export default {
padding: 18px 30px 0;
border-radius: 24px;
box-sizing: border-box;
background: linear-gradient(-90deg, #ffc77b 0%, #fff4e6 47%, #ffc879 100%);
background: linear-gradient(
-90deg,
#ffc77b 0%,
#fff4e6 47%,
#ffc879 100%
);
> div:nth-of-type(1) {
color: #8d0503;
@@ -443,9 +544,11 @@ export default {
padding: 105px 24px 0;
box-sizing: border-box;
border: 2px solid #ffc548;
background: linear-gradient(180deg,
rgba(225, 225, 225, 0) 0%,
rgba(225, 225, 225, 0.3) 100%);
background: linear-gradient(
180deg,
rgba(225, 225, 225, 0) 0%,
rgba(225, 225, 225, 0.3) 100%
);
.contentHeader {
width: 100%;
@@ -494,7 +597,9 @@ export default {
.contentBody {
width: 100%;
height: calc(100% - 152px); /* 减去 contentHeader 和其 margin-bottom 的高度 */
height: calc(
100% - 152px
); /* 减去 contentHeader 和其 margin-bottom 的高度 */
overflow: hidden; /* 关键:隐藏溢出内容,实现滚动效果 */
.contentBodyList {
@@ -562,7 +667,7 @@ export default {
}
> div:nth-of-type(2) {
color: #FFC87C;
color: #ffc87c;
width: 100%;
height: 40px;
font-size: 40px;
@@ -589,4 +694,4 @@ export default {
}
}
}
</style>
</style>