fix(壁纸): 删除选中壁纸后白板修复——删除清理按 raw+展示双形态匹配、getUserSettings 悬空引用自愈回落兜底链、管理员选定默认被删池自动跳过、池兜底改取第一张(min id,与用户口径及原注释一致)
build / build-push (push) Successful in 1m56s

This commit is contained in:
chenxing
2026-10-09 14:53:12 +08:00
parent 570b593293
commit 977b5c90a4
3 changed files with 35 additions and 15 deletions
@@ -292,8 +292,16 @@ public class UserSettingsController {
// List<BoaApp> appPageList = bschBaseOpenApi.getPcGrzxPage(authUserWithDept.getId(), schId);
List<BoaApp> appPageList = Collections.emptyList();
if (optional.isPresent()) model = optional.get();
// 壁纸池一次取全:悬空自愈判定与兜底选择共用
List<Wallpaper> wallList = userSettingsService.findWallList(authUserWithDept.getId());
// 悬空引用自愈:自选壁纸已被删除(删除清理修复前的存量脏数据)时视为未自选,避免返回死 URL 白板
String chosenUrl = normalizeWallpaperUrl(model.getWallpaperUrl());
if (model.getWallpaperUrl() != null && !model.getWallpaperUrl().isEmpty()
&& wallList.stream().noneMatch(w -> chosenUrl != null && chosenUrl.equals(w.getWallpaperUrl()))) {
model.setWallpaperUrl(null);
}
if (model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) {
model.setWallpaperUrl(resolveFallbackWallpaper(authUserWithDept, schId));
model.setWallpaperUrl(resolveFallbackWallpaper(authUserWithDept, schId, wallList));
}
List<Map> mapList = appPageList.stream().map(boaApp -> {
Map map = new HashMap<>();
@@ -310,31 +318,33 @@ public class UserSettingsController {
/**
* 兜底壁纸(用户未自选时,壁纸三级默认轮 2026-10-09):本校默认(sch_settings.wallpaper_url,管理员选定)
* → 平台默认(schId=0 行)→ 本地学校壁纸池最新一张 → 平台池最新一张(历史兜底,两级皆未配置时保持原体验)。
* <p>学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。</p>
* → 平台默认(schId=0 行)→ 本地学校壁纸池第一张 → 平台池第一张(历史兜底,两级皆未配置时保持原体验)。
* <p>学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。
* 管理员选定默认返回前校验其仍在壁纸池中——被删池视为未配置继续下落,避免兜底本身返回死 URL(2026-10-09 白板修复)。</p>
*/
private String resolveFallbackWallpaper(BoaUser authUserWithDept, Integer schId) {
private String resolveFallbackWallpaper(BoaUser authUserWithDept, Integer schId, List<Wallpaper> wallList) {
Set<String> poolUrls = new HashSet<>();
wallList.forEach(w -> poolUrls.add(w.getWallpaperUrl()));
// 1/2. 管理员选定的默认壁纸(本校 → 平台 级联,读侧 LayerValue)
ISchSettingsService.LayerValue wallHit = schSettingsService.readWallpaperWithFallback(schId);
if (wallHit.getValue() != null) {
if (wallHit.getValue() != null && poolUrls.contains(normalizeWallpaperUrl(wallHit.getValue()))) {
return wallHit.getValue();
}
// 3/4. 历史兜底:壁纸池最新(校 type=1 → 平台 type=0)
List<Wallpaper> wallList = userSettingsService.findWallList(authUserWithDept.getId());
// 3/4. 历史兜底:壁纸池第一张(校 type=1 → 平台 type=0,最早上传者优先)
if (schId != null) {
// 3. 本地学校壁纸第一张(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))
.max(Comparator.comparing(Wallpaper::getId));
.min(Comparator.comparing(Wallpaper::getId));
if (schWall.isPresent()) {
return FILE_WEB_PATH + schWall.get().getWallpaperUrl().replace("/upload", "");
}
}
// 4. 超管全局壁纸第一张(type=0,取最新)
// 4. 超管全局壁纸第一张(type=0)
Optional<Wallpaper> sysWall = wallList.stream()
.filter(w -> w.getType() != null && w.getType() == 0)
.max(Comparator.comparing(Wallpaper::getId));
.min(Comparator.comparing(Wallpaper::getId));
if (sysWall.isPresent()) {
return FILE_WEB_PATH + sysWall.get().getWallpaperUrl().replace("/upload", "");
}
@@ -8,6 +8,7 @@ import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Collection;
import java.util.Optional;
public interface UserSettingsRepository extends JpaRepository<UserSettings, Integer>, JpaSpecificationExecutor<UserSettings> {
@@ -21,8 +22,10 @@ public interface UserSettingsRepository extends JpaRepository<UserSettings, Inte
/**
* 删除壁纸时将被删除壁纸引用的用户设置 wallpaper_url 置空,避免裂图(调用方需处于事务中)。
* user_settings 存展示形态(FILE_WEB_PATH 前缀 + 去 /upload),wall 表存原始形态,
* 两种形态都需传入匹配,漏形态会留下悬空引用(读侧拿到已删壁纸的死 URL 白板)。
*/
@Modifying
@Query("update UserSettings u set u.wallpaperUrl = null where u.wallpaperUrl = :url")
int clearWallpaperUrl(@Param("url") String url);
@Query("update UserSettings u set u.wallpaperUrl = null where u.wallpaperUrl in :urls")
int clearWallpaperUrl(@Param("urls") Collection<String> urls);
}
@@ -53,6 +53,10 @@ public class UserSettingsServiceImpl implements IUserSettingsService {
@Value("${FILE_PATH:./upload/}")
private String FILE_PATH;
/** 与 UserSettingsController 同源:展示形态 = 该前缀 + 去掉 /upload 的池内原始路径 */
@Value("${FILE_WEB_PATH:}")
private String FILE_WEB_PATH;
@Override
public List<Wallpaper> findWallList(Integer userId) {
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(userId);
@@ -136,8 +140,11 @@ public class UserSettingsServiceImpl implements IUserSettingsService {
if (!(superAdmin || ownPersonal || schAdminOwn)) {
throw new BizException(ErrorCode.FORBIDDEN);
}
// 使用中清理:被删壁纸被用户设置引用时置空,避免裂图
userSettingsRepository.clearWallpaperUrl(wallpaper.getWallpaperUrl());
// 使用中清理:被删壁纸被用户设置引用时置空,避免裂图。
// user_settings 存展示形态(FILE_WEB_PATH 前缀 + 去 /upload),与 wall 表原始形态不同,两种都清
String rawUrl = wallpaper.getWallpaperUrl();
String displayUrl = (FILE_WEB_PATH == null ? "" : FILE_WEB_PATH) + rawUrl.replace("/upload", "");
userSettingsRepository.clearWallpaperUrl(java.util.Arrays.asList(rawUrl, displayUrl));
// 清理物理文件(非本地上传的跨仓地址静默跳过)
FileUtil.deleteFile(FILE_PATH, wallpaper.getWallpaperUrl());
wallpaperRepository.delete(wallpaper);