恢复 dietaryNutritionTips8 的代码
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user