feat(壁纸): 三级默认壁纸——sch_settings.wallpaper_url 两级配置 + getUserSettings 兜底链(个人未自选:本校默认→平台默认→池内最新)(LOGO文字与主题JSON化增补)
build / build-push (push) Successful in 1m13s
build / build-push (push) Successful in 1m13s
This commit is contained in:
@@ -181,6 +181,38 @@ public class SchSettingsController {
|
||||
schSettingsService.save(schSettings);
|
||||
}
|
||||
|
||||
// ===== 默认壁纸(平台/学校两级,壁纸三级默认轮 2026-10-09):与 LOGO 文字同模式 =====
|
||||
|
||||
/** 默认壁纸读(已登录可读):{wallpaperUrl: string|null, schId=实际命中层}。本校空 → 平台层 → null。 */
|
||||
@GetMapping("schWallpaper")
|
||||
public Map<String, Object> schWallpaper(BoaUser authUserWithDept) {
|
||||
ISchSettingsService.LayerValue hit =
|
||||
schSettingsService.readWallpaperWithFallback(schSettingsService.resolveThemeSchId(authUserWithDept, null));
|
||||
Map<String, Object> out = new HashMap<>();
|
||||
out.put("wallpaperUrl", hit.getValue());
|
||||
out.put("schId", hit.getHitSchId());
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 保存默认壁纸(仅学校管理员/超管):trim 后落本级(超管=平台层 0,校管=本校);空串存 null(=清空)。
|
||||
* URL 为管理池返回的绝对地址原样存(与 user_settings.wallpaper_url 同口径),≤255。 */
|
||||
@PostMapping("saveSchWallpaper")
|
||||
public void saveSchWallpaper(BoaUser authUserWithDept,
|
||||
@RequestParam("wallpaperUrl") String wallpaperUrl) {
|
||||
requireThemeAdmin(authUserWithDept);
|
||||
String url = wallpaperUrl == null ? "" : wallpaperUrl.trim();
|
||||
if (url.length() > 255) {
|
||||
throw new DException("壁纸地址不能超过 255 个字符");
|
||||
}
|
||||
Integer targetSchId = schSettingsService.resolveThemeSchId(authUserWithDept, null);
|
||||
SchSettings schSettings = schSettingsService.findBySchIdRaw(targetSchId).orElseGet(SchSettings::new);
|
||||
schSettings.setCDate(new Date());
|
||||
schSettings.setSchId(targetSchId);
|
||||
schSettings.setCId(authUserWithDept.getId());
|
||||
schSettings.setWallpaperUrl(url.isEmpty() ? null : url);
|
||||
schSettingsService.save(schSettings);
|
||||
}
|
||||
|
||||
@PostMapping("saveSchTheme")
|
||||
public void saveSchTheme(BoaUser authUserWithDept, String themeName, @RequestParam(name = "schId", defaultValue = "0") Integer schId) {
|
||||
if (schId == null || schId == 0) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.yunhai.userhome.enums.LightAppGroup;
|
||||
import com.yunhai.userhome.enums.LinkOpenType;
|
||||
import com.yunhai.userhome.model.AppIconEntryVo;
|
||||
import com.yunhai.userhome.service.AppIconKeyService;
|
||||
import com.yunhai.userhome.service.ISchSettingsService;
|
||||
import com.yunhai.userhome.service.IUserCurrentRoleService;
|
||||
import com.yunhai.userhome.service.IUserSettingsService;
|
||||
import com.yunhai.userhome.service.UsedAppService;
|
||||
@@ -52,6 +53,9 @@ public class UserSettingsController {
|
||||
@Autowired
|
||||
private IUserSettingsService userSettingsService;
|
||||
|
||||
@Autowired
|
||||
private ISchSettingsService schSettingsService;
|
||||
|
||||
@Autowired
|
||||
private IUserCurrentRoleService userCurrentRoleService;
|
||||
|
||||
@@ -305,13 +309,20 @@ public class UserSettingsController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底壁纸(用户未设置时):本地学校壁纸第一张 → 超管全局壁纸第一张。
|
||||
* 兜底壁纸(用户未自选时,壁纸三级默认轮 2026-10-09):本校默认(sch_settings.wallpaper_url,管理员选定)
|
||||
* → 平台默认(schId=0 行)→ 本地学校壁纸池最新一张 → 平台池最新一张(历史兜底,两级皆未配置时保持原体验)。
|
||||
* <p>学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。</p>
|
||||
*/
|
||||
private String resolveFallbackWallpaper(BoaUser authUserWithDept, Integer schId) {
|
||||
// 1/2. 管理员选定的默认壁纸(本校 → 平台 级联,读侧 LayerValue)
|
||||
ISchSettingsService.LayerValue wallHit = schSettingsService.readWallpaperWithFallback(schId);
|
||||
if (wallHit.getValue() != null) {
|
||||
return wallHit.getValue();
|
||||
}
|
||||
// 3/4. 历史兜底:壁纸池最新(校 type=1 → 平台 type=0)
|
||||
List<Wallpaper> wallList = userSettingsService.findWallList(authUserWithDept.getId());
|
||||
if (schId != null) {
|
||||
// 1. 本地学校壁纸第一张(type=1,取最新)
|
||||
// 3. 本地学校壁纸第一张(type=1,取最新)
|
||||
Optional<Wallpaper> schWall = wallList.stream()
|
||||
.filter(w -> w.getType() != null && w.getType() == 1
|
||||
&& w.getSchId() != null && w.getSchId().equals(schId))
|
||||
@@ -320,7 +331,7 @@ public class UserSettingsController {
|
||||
return FILE_WEB_PATH + schWall.get().getWallpaperUrl().replace("/upload", "");
|
||||
}
|
||||
}
|
||||
// 2. 超管全局壁纸第一张(type=0,取最新)
|
||||
// 4. 超管全局壁纸第一张(type=0,取最新)
|
||||
Optional<Wallpaper> sysWall = wallList.stream()
|
||||
.filter(w -> w.getType() != null && w.getType() == 0)
|
||||
.max(Comparator.comparing(Wallpaper::getId));
|
||||
|
||||
@@ -41,6 +41,11 @@ public class SchSettings {
|
||||
@Column(name = "logo_text")
|
||||
private String logoText;
|
||||
|
||||
/** 默认壁纸(壁纸三级默认轮 2026-10-09;绝对 URL,管理员从本级壁纸池选定;NULL=未配置回落上级。
|
||||
* 个人未自选时生效链:本校默认 → 平台默认(schId=0 行)→ 壁纸池最新一张(历史兜底) */
|
||||
@Column(name = "wallpaper_url")
|
||||
private String wallpaperUrl;
|
||||
|
||||
@Column(name = "home_img_url")
|
||||
private String homeImgUrl;
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ public interface ISchSettingsService {
|
||||
/** LOGO 文字读侧级联(LOGO 文字轮 2026-10-09):本校空 → 平台层 → null。 */
|
||||
LayerValue readLogoTextWithFallback(Integer schId);
|
||||
|
||||
/** 默认壁纸读侧级联(壁纸三级默认轮 2026-10-09):本校空 → 平台层 → null。 */
|
||||
LayerValue readWallpaperWithFallback(Integer schId);
|
||||
|
||||
/** 级联读命中结果:{@code value}=命中的档位值(两级都无则 null),{@code hitSchId}=实际命中层的 schId
|
||||
* (回落发生时是 0,不是解析出的本校 schId)。设置中心读端点的响应体 schId 即此语义——
|
||||
* 前端据此区分「本校已配置」与「本校未配置、正在回落平台默认」。 */
|
||||
|
||||
@@ -115,6 +115,25 @@ public class SchSettingsServiceImpl implements ISchSettingsService {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISchSettingsService.LayerValue readWallpaperWithFallback(Integer schId) {
|
||||
String url = readWallpaperAt(schId);
|
||||
if (url != null || schId == null || schId == ISchSettingsService.PLATFORM_SCH_ID) {
|
||||
return new ISchSettingsService.LayerValue(url, schId);
|
||||
}
|
||||
return new ISchSettingsService.LayerValue(readWallpaperAt(ISchSettingsService.PLATFORM_SCH_ID),
|
||||
ISchSettingsService.PLATFORM_SCH_ID);
|
||||
}
|
||||
|
||||
/** 原样读某层默认壁纸(查无行/空白 → null;trim 后存储口径,URL 为管理员从池中选定的原值) */
|
||||
private String readWallpaperAt(Integer schId) {
|
||||
return schSettingsRepository.findFirstBySchId(schId)
|
||||
.map(SchSettings::getWallpaperUrl)
|
||||
.map(String::trim)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/** 原样读某层主题档并解码(查无行/旧格式/脏值 → null) */
|
||||
private String decodeTheme(Integer schId) {
|
||||
return schSettingsRepository.findFirstBySchId(schId)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.yunhai.userhome.service;
|
||||
|
||||
import com.yunhai.userhome.entity.SchSettings;
|
||||
import com.yunhai.userhome.repository.SchSettingsRepository;
|
||||
import com.yunhai.userhome.service.impl.SchSettingsServiceImpl;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* sch_settings 读侧级联单测(LOGO 文字轮 2026-10-09 / 壁纸三级默认轮 2026-10-09):
|
||||
* 本校未配置 → 平台层(schId=0)回落,LayerValue.hitSchId 标记实际命中层;两级皆空 → null。
|
||||
*/
|
||||
class SchSettingsServiceTest {
|
||||
|
||||
private SchSettingsRepository schSettingsRepository;
|
||||
private SchSettingsServiceImpl service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
schSettingsRepository = Mockito.mock(SchSettingsRepository.class);
|
||||
service = new SchSettingsServiceImpl();
|
||||
ReflectionTestUtils.setField(service, "schSettingsRepository", schSettingsRepository);
|
||||
}
|
||||
|
||||
private SchSettings row(Integer schId, String logoText, String wallpaperUrl) {
|
||||
SchSettings s = new SchSettings();
|
||||
s.setSchId(schId);
|
||||
s.setLogoText(logoText);
|
||||
s.setWallpaperUrl(wallpaperUrl);
|
||||
return s;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("默认壁纸:本校已配置 → 命中本校层(hitSchId=本校)")
|
||||
void wallpaperSchoolHit() {
|
||||
when(schSettingsRepository.findFirstBySchId(3))
|
||||
.thenReturn(Optional.of(row(3, null, "http://base.test/upl/sch.png")));
|
||||
ISchSettingsService.LayerValue hit = service.readWallpaperWithFallback(3);
|
||||
assertEquals("http://base.test/upl/sch.png", hit.getValue());
|
||||
assertEquals(3, hit.getHitSchId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("默认壁纸:本校未配置 → 回落平台层(hitSchId=0)")
|
||||
void wallpaperFallsToPlatform() {
|
||||
when(schSettingsRepository.findFirstBySchId(3)).thenReturn(Optional.empty());
|
||||
when(schSettingsRepository.findFirstBySchId(0))
|
||||
.thenReturn(Optional.of(row(0, null, "http://base.test/upl/platform.png")));
|
||||
ISchSettingsService.LayerValue hit = service.readWallpaperWithFallback(3);
|
||||
assertEquals("http://base.test/upl/platform.png", hit.getValue());
|
||||
assertEquals(0, hit.getHitSchId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("默认壁纸:本校空白 → 回落平台层,平台也未配置 → value=null、hitSchId=0(命中层口径)")
|
||||
void wallpaperBothEmpty() {
|
||||
when(schSettingsRepository.findFirstBySchId(3)).thenReturn(Optional.of(row(3, null, " ")));
|
||||
when(schSettingsRepository.findFirstBySchId(0)).thenReturn(Optional.empty());
|
||||
ISchSettingsService.LayerValue hit = service.readWallpaperWithFallback(3);
|
||||
assertNull(hit.getValue());
|
||||
assertEquals(0, hit.getHitSchId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("默认壁纸:schId 已是平台层(0)→ 不二次自查,直接返回该层值/null")
|
||||
void wallpaperPlatformLayerNoDoubleFallback() {
|
||||
when(schSettingsRepository.findFirstBySchId(0)).thenReturn(Optional.empty());
|
||||
ISchSettingsService.LayerValue hit = service.readWallpaperWithFallback(0);
|
||||
assertNull(hit.getValue());
|
||||
assertEquals(0, hit.getHitSchId());
|
||||
Mockito.verify(schSettingsRepository, Mockito.times(1)).findFirstBySchId(Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LOGO 文字:本校空 → 平台回落(级联读同构回归)")
|
||||
void logoTextFallsToPlatform() {
|
||||
when(schSettingsRepository.findFirstBySchId(3)).thenReturn(Optional.empty());
|
||||
when(schSettingsRepository.findFirstBySchId(0))
|
||||
.thenReturn(Optional.of(row(0, "云海教育平台", null)));
|
||||
ISchSettingsService.LayerValue hit = service.readLogoTextWithFallback(3);
|
||||
assertEquals("云海教育平台", hit.getValue());
|
||||
assertEquals(0, hit.getHitSchId());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user