feat(appearance): 开放接口 GET /oapi/appearance(生效值合成)+ 级联下沉 service(oapi 代理轮)
build / build-push (push) Successful in 3m18s
build / build-push (push) Successful in 3m18s
- 新增 controller/oapi/OapiAppearanceController:userId 入参,出参 {theme, avatar, logoUrl} 当前用户生效值
(个人→学校→平台级联合成,层级知识不外露);出参裸 payload,Map 禁 String
- readThemeWithFallback/readAvatarWithFallback 从 SchSettingsController 下沉 ISchSettingsService(行为等价),
供 schTheme 读端点与 oapi 合成共享——顺带修复「appearance 无学校→平台级联」审计缺陷 C
- OpenApiAuthEnforceConfiguration:/oapi/* 强制应用签名(无签名 401,对齐 UserMsg/UserBase 同名配置)
- oapi schId 解析走本地 user_current_role(不引 identity 跨仓);超管临时切校角色场景与 /api 版有差,登记偏差
- 单测:生效值合成 3 例(个人优先不触级联/级联命中/脏值+无角色落平台层),60/60 绿
This commit is contained in:
@@ -5,10 +5,12 @@ import com.yunhai.platform.utils.model.BoaUser;
|
||||
import com.yunhai.userhome.entity.Logo;
|
||||
import com.yunhai.userhome.entity.SchSettings;
|
||||
import com.yunhai.userhome.entity.UserAppearance;
|
||||
import com.yunhai.userhome.entity.UserCurrentRole;
|
||||
import com.yunhai.userhome.repository.LogoRepository;
|
||||
import com.yunhai.userhome.repository.UserAppearanceRepository;
|
||||
import com.yunhai.userhome.service.IAppearanceService;
|
||||
import com.yunhai.userhome.service.ISchSettingsService;
|
||||
import com.yunhai.userhome.service.IUserCurrentRoleService;
|
||||
import com.yunhai.userhome.utils.ThemeCodec;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@@ -42,6 +44,9 @@ public class AppearanceServiceImpl implements IAppearanceService {
|
||||
@Autowired
|
||||
private ISchSettingsService schSettingsService;
|
||||
|
||||
@Autowired
|
||||
private IUserCurrentRoleService userCurrentRoleService;
|
||||
|
||||
@Autowired
|
||||
private LogoRepository logoRepository;
|
||||
|
||||
@@ -83,6 +88,57 @@ public class AppearanceServiceImpl implements IAppearanceService {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前用户生效外观(oapi 代理轮 2026-10-08,{@code /oapi/appearance} 出参真源):
|
||||
* {@code {theme, avatar, logoUrl}}——主题/头像为【合成后的生效值】(个人自选 → 学校默认 → 平台默认(schId=0)
|
||||
* 级联,层级知识留在 UserHome 内部,对外不拆 my/sch);logoUrl 为本校 type=1 → 平台 type=0 择优。
|
||||
*
|
||||
* <p>schId 解析走本地 user_current_role(oapi 入参只有 userId,不引 identity 跨仓):roleId 当前角色学校,
|
||||
* 无角色/跨校态回落 0(平台层)。与 /api/appearance 的 resolveThemeSchId(超管强制 0)仅在「超管临时切入
|
||||
* 某校角色」场景不同——该场景按当前角色学校取默认反而更贴近其当下观感,属登记偏差而非回归。</p>
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getEffectiveAppearance(Integer userId) {
|
||||
Map<String, Object> out = new HashMap<>();
|
||||
out.put("theme", null);
|
||||
out.put("avatar", null);
|
||||
out.put("logoUrl", null);
|
||||
if (userId == null) {
|
||||
return out;
|
||||
}
|
||||
Integer schId = userCurrentRoleService.findById(userId)
|
||||
.map(UserCurrentRole::getSchId)
|
||||
.filter(s -> s != null && s > 0)
|
||||
.orElse(ISchSettingsService.PLATFORM_SCH_ID);
|
||||
String myTheme = null;
|
||||
String myAvatar = null;
|
||||
try {
|
||||
Optional<UserAppearance> ua = userAppearanceRepository.findByUserId(userId);
|
||||
if (ua.isPresent()) {
|
||||
myTheme = validCompactTheme(ua.get().getThemeState());
|
||||
myAvatar = validAvatarStyle(ua.get().getAvatarStyle());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 个人段降级:myTheme/myAvatar 保持 null,不影响学校/平台段
|
||||
}
|
||||
String theme = myTheme;
|
||||
String avatar = myAvatar;
|
||||
try {
|
||||
if (theme == null) {
|
||||
theme = schSettingsService.readThemeWithFallback(schId).getValue();
|
||||
}
|
||||
if (avatar == null) {
|
||||
avatar = schSettingsService.readAvatarWithFallback(schId).getValue();
|
||||
}
|
||||
out.put("logoUrl", resolveLogoUrl(schId));
|
||||
} catch (Exception e) {
|
||||
// 学校/平台段降级:theme/avatar/logoUrl 保持已得值或 null
|
||||
}
|
||||
out.put("theme", theme);
|
||||
out.put("avatar", avatar);
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMyTheme(Integer userId, String themeState) {
|
||||
UserAppearance ua = loadOrCreate(userId);
|
||||
|
||||
Reference in New Issue
Block a user