logo,壁纸修复,加入小应用管理,样式待调整
build / build-push (push) Successful in 2m11s

This commit is contained in:
chenxing
2026-08-28 14:24:46 +08:00
parent 567c8b7786
commit 759b120f2a
22 changed files with 813 additions and 163 deletions
@@ -1,13 +1,12 @@
package com.yunhai.userhome.controller.api;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yunhai.platform.apistd.BizException;
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
import com.yunhai.platform.utils.enums.ClientEnum;
import com.yunhai.platform.utils.exception.ErrorCode;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaGroup;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.config.Config;
import com.yunhai.userhome.entity.*;
@@ -23,7 +22,6 @@ import com.yunhai.userhome.utils.OtherUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@@ -36,7 +34,6 @@ import java.util.stream.Collectors;
* <p>待确认接口(已写入待确认清单):
* <ul>
* <li>getUserSettings 中 bschBaseOpenApi.getPcGrzxPage —— 新框架 YschBaseOpenApi 是否有此方法待确认</li>
* <li>GetSchSettingsWallpaper 依赖 SCH_CONF_URL —— 需确认环境地址</li>
* </ul>
*/
@RestController
@@ -49,9 +46,6 @@ public class UserSettingsController {
@Value("${FILE_WEB_PATH:}")
private String FILE_WEB_PATH;
@Value("${SCH_CONF_URL:}")
private String SCH_CONF_URL;
@Autowired
private IUserSettingsService userSettingsService;
@@ -61,21 +55,38 @@ public class UserSettingsController {
@Autowired
private UsedAppService usedAppService;
private final RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();
// ==================== 壁纸 ====================
/**
* 上传壁纸(Header 弹窗与系统设置页共用)。
*
* <p>超管:可选 schId 参数——传 schId&gt;0 归属该校(type=1),不传/0 维持系统级(type=0);
* 校管理员:忽略入参固定本校(type=1);普通用户维持个人壁纸(type=2)。</p>
*/
@PostMapping(value = "wallpaperUpload", produces = "application/json")
public void wallpaperUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) {
public void wallpaperUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file,
@RequestParam(value = "schId", required = false) Integer schId) {
checkFile(file);
String uploadUrl = this.upload(file, "wallpaper");
UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId())
.orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR));
Integer type = authUserWithDept.getType() == 1 ? 0 : OtherUtil.isAdminById(currentRole.getRoleId()) ? 1 : 2;
Integer type;
Integer targetSchId;
if (authUserWithDept.getType() == 1) {
if (schId != null && schId > 0) {
type = 1;
targetSchId = schId;
} else {
// 超管上传的系统壁纸 schId 强制 0,避免切学校身份后产生孤儿数据
type = 0;
targetSchId = 0;
}
} else {
type = OtherUtil.isAdminById(currentRole.getRoleId()) ? 1 : 2;
targetSchId = currentRole.getSchId();
}
Wallpaper wallpaper = new Wallpaper();
// 超管上传的系统壁纸 schId 强制 0,避免切学校身份后产生孤儿数据
wallpaper.setSchId(type == 0 ? 0 : currentRole.getSchId());
wallpaper.setSchId(targetSchId);
wallpaper.setWallpaperUrl(uploadUrl);
wallpaper.setUserId(authUserWithDept.getId());
wallpaper.setType(type);
@@ -98,16 +109,11 @@ public class UserSettingsController {
@PostMapping(value = "checkWallpaper", produces = "application/json")
public void checkWallpaper(BoaUser authUserWithDept, @RequestBody Map res) {
String wallpaperUrl = res.get("wallpaperUrl").toString();
// 校验 URL 属于该用户可见壁纸集合,防止设置任意字符串
// 校验 URL 属于该用户可见壁纸集合(本地 wallpaper 表),防止设置任意字符串
String normalized = normalizeWallpaperUrl(wallpaperUrl);
Set<String> visible = new HashSet<>();
userSettingsService.findWallList(authUserWithDept.getId())
.forEach(w -> visible.add(w.getWallpaperUrl()));
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId());
Integer schId = currentRoleOpt.isPresent() ? currentRoleOpt.get().getSchId() : null;
if (schId != null) {
getSchSettingsWallpaper(schId).forEach(visible::add);
}
if (!visible.contains(normalized)) {
throw new BizException(ErrorCode.FORBIDDEN, "壁纸不存在或无权使用");
}
@@ -127,35 +133,25 @@ public class UserSettingsController {
map.put("isEdit", model.getIsEdit());
result.add(map);
});
if (authUserWithDept.getType() != 1 && !list.stream().anyMatch(x -> x.getType() == 1)) {
// schId 以当前激活角色为准,忽略前端传参(防传他校 id 看他校壁纸)
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId());
Integer curSchId = currentRoleOpt.isPresent() ? currentRoleOpt.get().getSchId() : null;
if (curSchId != null) {
List<String> schList = getSchSettingsWallpaper(curSchId);
for (String schWall : schList) {
Map map = new HashMap();
map.put("id", null);
map.put("type", 1);
map.put("url", schWall);
map.put("isEdit", false);
result.add(map);
}
}
}
return result;
}
// ==================== Logo ====================
@PostMapping(value = "logoUpload", produces = "application/json")
public void logoUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) {
// 仅超管(系统默认)与校管理员(本校)可上传,普通用户无权设置 Logo
public void logoUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file,
@RequestParam(value = "schId", required = false) Integer schId) {
// 仅超管(系统默认/指定学校)与校管理员(本校)可上传,普通用户无权设置 Logo
Integer type;
Integer schId;
Integer targetSchId;
if (authUserWithDept.getType() == 1) {
type = 0;
schId = 0;
if (schId != null && schId > 0) {
type = 1;
targetSchId = schId;
} else {
type = 0;
targetSchId = 0;
}
} else {
UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId())
.orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR));
@@ -163,13 +159,13 @@ public class UserSettingsController {
throw new BizException(ErrorCode.FORBIDDEN, "无权设置Logo");
}
type = 1;
schId = currentRole.getSchId();
targetSchId = currentRole.getSchId();
}
checkFile(file);
String uploadUrl = this.upload(file, "logo");
Logo logo = new Logo();
logo.setType(type);
logo.setSchId(schId);
logo.setSchId(targetSchId);
logo.setLogoUrl(uploadUrl);
logo.setUserId(authUserWithDept.getId());
userSettingsService.saveLogo(logo);
@@ -195,6 +191,82 @@ public class UserSettingsController {
userSettingsService.deleteLogoById(id, authUserWithDept);
}
// ==================== 系统设置(学校维度管理视图) ====================
/**
* 机构树(仅超管,403 兜底):YschBaseOpenApi.getGroupTree() → 递归裁剪到学校层
* (对齐原 systemsetting SysController.RecursionGroup:type==1 普通组跳过、type==2 学校组置叶子)。
*/
@GetMapping(value = "getSchTree")
public BoaGroup getSchTree(BoaUser authUserWithDept) {
if (authUserWithDept.getType() != 1) {
throw new BizException(ErrorCode.FORBIDDEN);
}
BoaGroup group = YschBaseOpenApi.getGroupTree();
return recursionGroup(group);
}
/**
* 壁纸管理列表(系统设置页):系统壁纸(type=0) + 目标学校壁纸(type=1),不含个人壁纸(type=2)。
* <p>超管可传任意 schId(不传按 0 即平台默认);校管理员忽略入参固定本校,系统壁纸仅超管可删。</p>
*/
@GetMapping(value = "getSchWallpaperManageList")
public List<Map> getSchWallpaperManageList(BoaUser authUserWithDept, Integer schId) {
List<Map> result = new ArrayList<>();
userSettingsService.findSchWallpaperManageList(authUserWithDept, schId).forEach(model -> {
Map map = new HashMap();
map.put("id", model.getId());
map.put("url", FILE_WEB_PATH + model.getWallpaperUrl().replace("/upload", ""));
map.put("type", model.getType());
map.put("isEdit", model.getIsEdit());
result.add(map);
});
return result;
}
/**
* Logo 管理列表(系统设置页):系统默认(type=0) + 目标学校(type=1)。
* <p>同 getSchWallpaperManageList 权限语义;logo 单张,前端取第一张显示,上传即覆盖。</p>
*/
@GetMapping(value = "getSchLogoManageList")
public List<Map> getSchLogoManageList(BoaUser authUserWithDept, Integer schId) {
List<Map> result = new ArrayList<>();
userSettingsService.findSchLogoManageList(authUserWithDept, schId).forEach(model -> {
Map map = new HashMap();
map.put("id", model.getId());
map.put("url", FILE_WEB_PATH + model.getLogoUrl().replace("/upload", ""));
map.put("type", model.getType());
map.put("isEdit", model.getIsEdit());
result.add(map);
});
return result;
}
/**
* 递归裁剪机构树到学校层(对齐原 systemsetting SysController.RecursionGroup)。
*/
private BoaGroup recursionGroup(BoaGroup group) {
// 组类型:1 普通组 2 学校组 3 年级组 4 班级组 5 区域组 6 学段组 7 教师组 8 学生组
List<BoaGroup> list = new ArrayList<>();
List<BoaGroup> children = group.getChildren();
if (children == null) {
return group;
}
for (BoaGroup boaGroup : children) {
if (boaGroup.getType() == null) continue;
if (boaGroup.getType() == 1) continue;
if (boaGroup.getType() == 2) {
boaGroup.setChildren(null);
list.add(boaGroup);
} else {
BoaGroup model = this.recursionGroup(boaGroup);
list.add(model);
}
}
group.setChildren(list);
return group;
}
// ==================== 用户设置 ====================
@GetMapping(value = "getUserSettings")
@@ -207,9 +279,8 @@ public class UserSettingsController {
// List<BoaApp> appPageList = bschBaseOpenApi.getPcGrzxPage(authUserWithDept.getId(), schId);
List<BoaApp> appPageList = Collections.emptyList();
if (optional.isPresent()) model = optional.get();
if ((model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) && schId != null) {
List<String> schList = getSchSettingsWallpaper(schId);
if (schList.size() > 0) model.setWallpaperUrl(schList.get(0));
if (model.getWallpaperUrl() == null || model.getWallpaperUrl().isEmpty()) {
model.setWallpaperUrl(resolveFallbackWallpaper(authUserWithDept, schId));
}
List<Map> mapList = appPageList.stream().map(boaApp -> {
Map map = new HashMap<>();
@@ -224,6 +295,32 @@ public class UserSettingsController {
return model;
}
/**
* 兜底壁纸(用户未设置时):本地学校壁纸第一张 → 超管全局壁纸第一张。
* <p>学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。</p>
*/
private String resolveFallbackWallpaper(BoaUser authUserWithDept, Integer schId) {
List<Wallpaper> wallList = userSettingsService.findWallList(authUserWithDept.getId());
if (schId != null) {
// 1. 本地学校壁纸第一张(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));
if (schWall.isPresent()) {
return FILE_WEB_PATH + schWall.get().getWallpaperUrl().replace("/upload", "");
}
}
// 2. 超管全局壁纸第一张(type=0,取最新)
Optional<Wallpaper> sysWall = wallList.stream()
.filter(w -> w.getType() != null && w.getType() == 0)
.max(Comparator.comparing(Wallpaper::getId));
if (sysWall.isPresent()) {
return FILE_WEB_PATH + sysWall.get().getWallpaperUrl().replace("/upload", "");
}
return null;
}
@GetMapping(value = "getUserDesktopAppList")
public List<Map> getUserDesktopAppList(BoaUser authUserWithDept) {
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId());
@@ -465,37 +562,6 @@ public class UserSettingsController {
return u;
}
/**
* 获取学校设置的壁纸集合(对齐旧 UserHome GetSchSettingsWallpaper,fastjson → Jackson)。
*/
private List<String> getSchSettingsWallpaper(Integer schId) {
if (SCH_CONF_URL == null || SCH_CONF_URL.isEmpty()) return Collections.emptyList();
String apiPath = SCH_CONF_URL + "/oapi/getSchSetting?schId=" + schId;
List<String> result = new ArrayList<>();
try {
String resultStr = restTemplate.getForObject(apiPath, String.class);
if (resultStr == null || resultStr.isEmpty()) return result;
JsonNode root = objectMapper.readTree(resultStr);
JsonNode dataNode = root.get("data");
if (root.has("code") && "0".equals(root.get("code").asText()) && dataNode != null && !dataNode.isNull()) {
JsonNode appBgUrlNode = dataNode.get("appBackgroundUrl");
if (appBgUrlNode == null) appBgUrlNode = dataNode.get("appBgUrl");
String appBgUrlStr = appBgUrlNode != null ? appBgUrlNode.asText("") : "";
if (appBgUrlStr.isEmpty()) return result;
String[] imgUrls = appBgUrlStr.split(",");
for (String imgUrl : imgUrls) {
if (!imgUrl.contains(SCH_CONF_URL))
result.add(SCH_CONF_URL + imgUrl);
else
result.add(imgUrl);
}
}
} catch (Exception e) {
// 跨仓调用失败时返回空列表
}
return result;
}
/**
* 将某个人常用应用转化为桌面应用
*/