From 1f31612609ae70e8c50d5503351ed259f4a7650d Mon Sep 17 00:00:00 2001
From: chenxing
Date: Thu, 15 Oct 2026 16:30:13 +0800
Subject: [PATCH] =?UTF-8?q?feat(=E4=B8=80=E5=91=A8=E5=AE=89=E6=8E=92?=
=?UTF-8?q?=E5=B0=8F=E7=BB=84=E4=BB=B6):=20weekplan=20=E5=AF=B9=E6=8E=A5?=
=?UTF-8?q?=20WorkWeekPlan=20GET=20/oapi/workplan/Get,=E6=9B=BF=E6=8D=A2?=
=?UTF-8?q?=E5=8E=9F=20L2=20mock?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 分发 CODE_WEEKPLAN -> weekplan(caller, params),原样透传单个周对象 data(含 days[7])
- week 为相对本周偏移(0=本周/-1=上周/+1=下周),缺省 0 不向外传(签名 target 最小化);合法范围见 minWeek/maxWeek
- 缓存 key 改 schId|week偏移(全校共享、与身份无关,但不同周内容不同)
- 90s TTL + 15s 失败退避 + 上限 500;缺身份/不可达/验签失败/越界均降级空对象,不抛 500
- 配套 front WeekplanWidget 翻页改版
---
.../userhome/service/WidgetDataService.java | 109 ++++++++++++------
1 file changed, 73 insertions(+), 36 deletions(-)
diff --git a/src/main/java/com/yunhai/userhome/service/WidgetDataService.java b/src/main/java/com/yunhai/userhome/service/WidgetDataService.java
index 4dab6d8..9c51b63 100644
--- a/src/main/java/com/yunhai/userhome/service/WidgetDataService.java
+++ b/src/main/java/com/yunhai/userhome/service/WidgetDataService.java
@@ -9,10 +9,6 @@ import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
-import java.time.DayOfWeek;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -27,7 +23,12 @@ import java.util.concurrent.ConcurrentHashMap;
* 带 yh-app-auth 签名;目标 {@code acasyllabu} 配于 {@code yh.call.targets}),**原样透传** {@code data[]}
* 班级数组(含 {@code timetable.slots[].subjects[7]}),由前端按班级维度渲染。
*
- * {@code evaluate} / {@code weekplan} 仍为 L2 可溯源 mock(字段名逐一等于
+ *
{@code weekplan}(一周安排)已对接 WorkWeekPlan {@code GET /oapi/workplan/Get?userid=&schId=&week=}(出站走
+ * {@link YschOpenCall})。全校共享数据、不区分角色,**原样透传**单个周对象 {@code data}(含 {@code days[7]});
+ * {@code week} 为相对本周偏移(0=本周、-1=上一周、+1=下一周),合法范围见响应 {@code minWeek}/{@code maxWeek};
+ * 返回内容与身份无关但随周偏移变化,缓存按 {@code schId|week偏移} 双段键。
+ *
+ * {@code evaluate} 仍为 L2 可溯源 mock(字段名逐一等于
* {@code design/widget-snapshots-old-bsch/*.js} 的旧接口口径);未知 code 返回 null 由调用方兜空数据,不抛异常。
*/
@Service
@@ -41,8 +42,6 @@ public class WidgetDataService {
private static final String CODE_WEEKPLAN = "weekplan";
- private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-
/** 听评课旧接口 pageSize 默认值(evaluate_index.js 传 count=5) */
private static final int EVALUATE_DEFAULT_COUNT = 5;
@@ -61,12 +60,30 @@ public class WidgetDataService {
/** 课表缓存条目上限,超出时清理过期项 */
private static final int SYLLABUS_CACHE_MAX = 500;
+ /** 一周安排 oapi 目标名(见 yh.call.targets.workplan) */
+ private static final String TARGET_WORKPLAN = "workplan";
+
+ /** 一周安排 oapi 路径(签名按目标 ctx 剥离,故此处不含 /work-week-plan) */
+ private static final String PATH_WORKPLAN = "/oapi/workplan/Get";
+
+ /** 一周安排缓存时长:全校共享、低频变更 */
+ private static final long WEEKPLAN_TTL_MS = 90_000L;
+
+ /** 一周安排取数失败后的静默期 */
+ private static final long WEEKPLAN_FAIL_BACKOFF_MS = 15_000L;
+
+ /** 一周安排缓存条目上限,超出时清理过期项 */
+ private static final int WEEKPLAN_CACHE_MAX = 500;
+
@Autowired
private YschOpenCall openCall;
/** key = userId|roleId|schId → 缓存条目 */
private final ConcurrentHashMap syllabusCache = new ConcurrentHashMap<>();
+ /** key = schId|weekOffset → 缓存条目(周安排为全校共享数据,与 userid/roleId 无关;但不同周内容不同) */
+ private final ConcurrentHashMap weekplanCache = new ConcurrentHashMap<>();
+
/**
* 按数据键取数;params 为 urlencoded 查询串(对齐旧 otherParams 口径)。
*
@@ -75,7 +92,7 @@ public class WidgetDataService {
public Object getData(String code, String params, Caller caller) {
if (CODE_EVALUATE.equals(code)) return evaluate(params);
if (CODE_SYLLABUS.equals(code)) return syllabus(caller);
- if (CODE_WEEKPLAN.equals(code)) return weekplan(params, caller == null ? null : caller.getSchId());
+ if (CODE_WEEKPLAN.equals(code)) return weekplan(caller, params);
log.warn("[widget] 未配置的数据键:{}", code);
return null;
}
@@ -132,54 +149,74 @@ public class WidgetDataService {
query.put("schId", String.valueOf(caller.getSchId()));
JsonNode data = openCall.get(TARGET_ACASYLLABU, PATH_TIMETABLE, query, JsonNode.class);
Object value = (data != null && data.isArray()) ? data : Collections.emptyList();
- cache(key, value, now + SYLLABUS_TTL_MS, now);
+ cache(syllabusCache, SYLLABUS_CACHE_MAX, key, value, now + SYLLABUS_TTL_MS, now);
return value;
} catch (Exception e) {
log.warn("[widget] 课表 oapi 不可达(降级空)user={} role={} sch={}:{}",
caller.getUserId(), caller.getRoleId(), caller.getSchId(), e.toString());
// 失败退避:短 TTL 空结果,避免下游停摆时每次进桌面都吃一次超时
- cache(key, Collections.emptyList(), now + SYLLABUS_FAIL_BACKOFF_MS, now);
+ cache(syllabusCache, SYLLABUS_CACHE_MAX, key, Collections.emptyList(), now + SYLLABUS_FAIL_BACKOFF_MS, now);
return Collections.emptyList();
}
}
/**
- * 一周安排:{Data:[{date, list:[{contents, times}]}], OtherData:{week, schId}},入参 iweek(-1/0/1)。
- * // TODO 接入 oapi: openCall.get(TARGET_USERBASE, "/oapi/...", query, Vo.class)
+ * 一周安排:WorkWeekPlan {@code GET /oapi/workplan/Get?userid=&schId=&week=}(SDK 出站,签名自动)。
+ * 全校共享数据(不区分角色),原样透传单个周对象 {@code data}(含 {@code days[7]});
+ * 缺身份 / 不可达 / 验签失败 / week 越界(oapi {@code code:2},SDK 抛异常)均降级空对象(不抛 500)。
+ *
+ * {@code week} 为**相对本周的偏移**(0=本周、-1=上一周、+1=下一周),合法范围由响应
+ * {@code minWeek}/{@code maxWeek} 提示(前端据此驱动翻页边界);注意与数据字段 {@code data.week}
+ * (绝对周次)同名不同义。
+ *
+ * userid 仅用于 oapi 侧审计、不影响返回内容,故缓存按 {@code schId|week偏移}
+ * (全校共享、与身份无关,但不同周内容不同,不可共用单键)。
*/
- private Map weekplan(String params, Integer schId) {
- int iweek = Math.max(-1, Math.min(1, intParam(params, "iweek", 0)));
- LocalDate monday = LocalDate.now().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
- .plusWeeks(iweek);
- List