Files
UserhomeService/src/main/java/com/yunhai/userhome/controller/api/UserSettingsController.java
T

663 lines
31 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.yunhai.userhome.controller.api;
import com.yunhai.platform.apistd.BizException;
import com.yunhai.platform.openapi.base.OpenApiUserClient;
import com.yunhai.platform.openapi.base.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.*;
import com.yunhai.userhome.enums.DesktopAppType;
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;
import com.yunhai.userhome.utils.EnumUtil;
import com.yunhai.userhome.utils.FileUtil;
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.multipart.MultipartFile;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
/**
* 用户设置控制器(对齐旧 UserHome contorller.api.UserSettingsController)。
*
* <p>待确认接口(已写入待确认清单):
* <ul>
* <li>getUserSettings 中 bschBaseOpenApi.getPcGrzxPage —— 新框架 YschBaseOpenApi 是否有此方法待确认</li>
* </ul>
*/
@RestController
@RequestMapping(Config.API_PATH)
public class UserSettingsController {
@Value("${FILE_PATH:./upload/}")
private String FILE_PATH;
@Value("${FILE_WEB_PATH:}")
private String FILE_WEB_PATH;
@Autowired
private IUserSettingsService userSettingsService;
@Autowired
private ISchSettingsService schSettingsService;
@Autowired
private IUserCurrentRoleService userCurrentRoleService;
@Autowired
private UsedAppService usedAppService;
@Autowired
private OpenApiUserClient openApiUserClient;
@Autowired
private AppIconKeyService appIconKeyService;
// ==================== 壁纸 ====================
/**
* 上传壁纸(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,
@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;
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();
wallpaper.setSchId(targetSchId);
wallpaper.setWallpaperUrl(uploadUrl);
wallpaper.setUserId(authUserWithDept.getId());
wallpaper.setType(type);
userSettingsService.saveWallpaper(wallpaper);
}
@PostMapping(value = "iconUpload", produces = "application/json")
public Map<String, String> iconUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) {
checkFile(file);
Map<String, String> result = new HashMap<>();
result.put("url", this.upload(file, "icon"));
return result;
}
@PostMapping(value = "deleteWallById", produces = "application/json")
public void deleteWallById(BoaUser authUserWithDept, Integer id) {
userSettingsService.deleteWallById(id, authUserWithDept);
}
@PostMapping(value = "checkWallpaper", produces = "application/json")
public void checkWallpaper(BoaUser authUserWithDept, @RequestBody Map res) {
String wallpaperUrl = res.get("wallpaperUrl").toString();
// 校验 URL 属于该用户可见壁纸集合(本地 wallpaper 表),防止设置任意字符串
String normalized = normalizeWallpaperUrl(wallpaperUrl);
Set<String> visible = new HashSet<>();
userSettingsService.findWallList(authUserWithDept.getId())
.forEach(w -> visible.add(w.getWallpaperUrl()));
if (!visible.contains(normalized)) {
throw new BizException(ErrorCode.FORBIDDEN, "壁纸不存在或无权使用");
}
userSettingsService.checkWallpaper(authUserWithDept.getId(), wallpaperUrl);
}
@GetMapping(value = "getUserWallpaperList")
public List<Map> getUserWallpaperList(BoaUser authUserWithDept, Integer schId) {
List<Map> result = new ArrayList<>();
List<Wallpaper> list = userSettingsService.findWallList(authUserWithDept.getId());
list = list.stream().sorted(Comparator.comparing(Wallpaper::getId).reversed()).collect(Collectors.toList());
list.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 ====================
@PostMapping(value = "logoUpload", produces = "application/json")
public void logoUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file,
@RequestParam(value = "schId", required = false) Integer schId) {
// 仅超管(系统默认/指定学校)与校管理员(本校)可上传,普通用户无权设置 Logo
Integer type;
Integer targetSchId;
if (authUserWithDept.getType() == 1) {
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));
if (!OtherUtil.isAdminById(currentRole.getRoleId())) {
throw new BizException(ErrorCode.FORBIDDEN, "无权设置Logo");
}
type = 1;
targetSchId = currentRole.getSchId();
}
checkFile(file);
String uploadUrl = this.upload(file, "logo");
Logo logo = new Logo();
logo.setType(type);
logo.setSchId(targetSchId);
logo.setLogoUrl(uploadUrl);
logo.setUserId(authUserWithDept.getId());
userSettingsService.saveLogo(logo);
}
@GetMapping(value = "getLogoList")
public List<Map> getLogoList(BoaUser authUserWithDept) {
List<Map> result = new ArrayList<>();
List<Logo> list = userSettingsService.findLogoList(authUserWithDept.getId());
list.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;
}
@PostMapping(value = "deleteLogoById", produces = "application/json")
public void deleteLogoById(BoaUser authUserWithDept, Integer id) {
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")
public UserSettings getUserSettings(BoaUser authUserWithDept) {
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId());
Integer schId = currentRoleOpt.isPresent() ? currentRoleOpt.get().getSchId() : null;
UserSettings model = new UserSettings();
Optional<UserSettings> optional = userSettingsService.findUserSettings(authUserWithDept.getId());
// TODO 待确认:bschBaseOpenApi.getPcGrzxPage —— 新框架 YschBaseOpenApi 是否有此方法待确认
// 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, wallList));
}
List<Map> mapList = appPageList.stream().map(boaApp -> {
Map map = new HashMap<>();
map.put("id", boaApp.getId());
map.put("appId", boaApp.getId());
map.put("name", boaApp.getName());
map.put("url", boaApp.getWebAddr());
return map;
}).collect(Collectors.toList());
model.setWidgetAppList(mapList);
return model;
}
/**
* 兜底壁纸(用户未自选时,壁纸三级默认轮 2026-10-09):本校默认(sch_settings.wallpaper_url,管理员选定)
* → 平台默认(schId=0 行)→ 本地学校壁纸池第一张 → 平台池第一张(历史兜底,两级皆未配置时保持原体验)。
* <p>学校壁纸完全本地管理(wallpaper 表 type=1),不再依赖跨仓 schConfig。
* 管理员选定默认返回前校验其仍在壁纸池中——被删池视为未配置继续下落,避免兜底本身返回死 URL(2026-10-09 白板修复)。</p>
*/
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 && poolUrls.contains(normalizeWallpaperUrl(wallHit.getValue()))) {
return wallHit.getValue();
}
// 3/4. 历史兜底:壁纸池第一张(校 type=1 → 平台 type=0,最早上传者优先)
if (schId != null) {
// 3. 本地学校壁纸第一张(type=1)
Optional<Wallpaper> schWall = wallList.stream()
.filter(w -> w.getType() != null && w.getType() == 1
&& w.getSchId() != null && w.getSchId().equals(schId))
.min(Comparator.comparing(Wallpaper::getId));
if (schWall.isPresent()) {
return FILE_WEB_PATH + schWall.get().getWallpaperUrl().replace("/upload", "");
}
}
// 4. 超管全局壁纸第一张(type=0)
Optional<Wallpaper> sysWall = wallList.stream()
.filter(w -> w.getType() != null && w.getType() == 0)
.min(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());
if (!currentRoleOpt.isPresent()) {
return new ArrayList<>();
}
UserCurrentRole currentRole = currentRoleOpt.get();
Optional<UserSettings> optional = userSettingsService.findUserSettings(authUserWithDept.getId());
Integer schId = currentRole.getSchId(), userId = currentRole.getUserId();
UserSettings model = new UserSettings();
List<UserSettingsDesktopApp> desktopAppList = new ArrayList<>();
List<Map> result = new ArrayList<>();
if (optional.isPresent()) model = optional.get();
// 初始化设置为常用应用
if (model.getDesktopApps().isEmpty()) desktopAppList = getUserUsedByUserId(authUserWithDept.getId());
else desktopAppList = model.getDesktopApps();
List<BoaApp> bschAllList = new ArrayList<>();
List<LightApp> lightAllList = new ArrayList<>();
List<Integer> bschAppIds = desktopAppList.stream()
.filter(x -> x.getAppType() == DesktopAppType.Bsch)
.map(UserSettingsDesktopApp::getAppId)
.collect(Collectors.toList());
List<Integer> lightAppIds = desktopAppList.stream()
.filter(x -> x.getAppType() == DesktopAppType.Light)
.map(UserSettingsDesktopApp::getAppId)
.collect(Collectors.toList());
if (bschAppIds.size() > 0) {
List<BoaAppType> appTypeList = YschBaseOpenApi.getUserApp(authUserWithDept.getId(), ClientEnum.PC_BROWSER);
for (BoaAppType mode : appTypeList) bschAllList.addAll(mode.getApps());
}
if (lightAppIds.size() > 0) {
lightAllList = userSettingsService.findLightAppList(schId, userId);
}
desktopAppList = desktopAppList.stream()
.sorted(Comparator.comparing(UserSettingsDesktopApp::getOrderNum, Comparator.nullsLast(Integer::compareTo)))
.collect(Collectors.toList());
for (UserSettingsDesktopApp desktopApp : desktopAppList) {
Map map = new HashMap();
map.put("id", desktopApp.getId());
map.put("appId", desktopApp.getAppId());
if (desktopApp.getAppType() == DesktopAppType.Bsch) {
Optional<BoaApp> optionalBoaApp = bschAllList.stream()
.filter(boa -> desktopApp.getAppId().equals(boa.getId())).findFirst();
if (!optionalBoaApp.isPresent()) continue;
map.put("name", optionalBoaApp.get().getName());
map.put("icon", optionalBoaApp.get().getIcon());
map.put("url", optionalBoaApp.get().getWebAddr());
map.put("type", DesktopAppType.Bsch.getKey());
map.put("linkType", LinkOpenType.Open.getKey());
map.put("layout", null);
// 矢量图标键(AppIcon 通道;未配置为 null,前端按空走原 img 回退)
AppIconEntryVo iconEntry = appIconKeyService.byId(optionalBoaApp.get().getId());
map.put("iconKey", iconEntry == null ? null : iconEntry.getIconKey());
map.put("iconColor", iconEntry == null ? null : iconEntry.getIconColor());
} else if (desktopApp.getAppType() == DesktopAppType.Light) {
Optional<LightApp> optionalLightApp = lightAllList.stream()
.filter(app -> desktopApp.getAppId().equals(app.getId())).findFirst();
if (!optionalLightApp.isPresent()) continue;
map.put("name", optionalLightApp.get().getName());
map.put("icon", optionalLightApp.get().getIcon());
map.put("url", optionalLightApp.get().getUrl());
map.put("type", DesktopAppType.Light.getKey());
map.put("linkType", optionalLightApp.get().getLinkOpenType());
map.put("layout", optionalLightApp.get().getLayout());
}
result.add(map);
}
return result;
}
@PostMapping(value = "saveUserWidget", produces = "application/json")
public void saveUserWidget(BoaUser authUserWithDept, @RequestBody UserSettings userSettings) {
userSettings.setUserId(authUserWithDept.getId());
userSettingsService.saveUserWidget(userSettings);
}
@PostMapping(value = "toggleWidgetShow", produces = "application/json")
public void toggleWidgetShow(BoaUser authUserWithDept, @RequestBody Map<String, Integer> params) {
Integer id = params.get("id");
userSettingsService.toggleWidgetShow(id, authUserWithDept.getId());
}
@PostMapping(value = "saveUserAppIds", produces = "application/json")
public void saveUserAppIds(BoaUser authUserWithDept, @RequestBody Map<String, String> params) {
Integer id = null;
if (params.get("id") != null) id = Integer.parseInt(params.get("id"));
String appIds = params.get("appIds");
userSettingsService.saveUserAppIds(id, authUserWithDept.getId(), appIds);
}
// ==================== 轻应用 ====================
@GetMapping(value = "getLightAppGroup")
public Object getLightAppGroup(BoaUser authUserWithDept) {
return EnumUtil.toMapList(LightAppGroup.class);
}
@GetMapping(value = "getLightAppList", produces = "application/json")
public List<LightApp> getLightAppList(BoaUser authUserWithDept) {
Integer schId, userId = null;
if (authUserWithDept.getType() == 1) {
schId = 0;
} else {
Optional<UserCurrentRole> currentRoleOpt = userCurrentRoleService.findById(authUserWithDept.getId());
if (!currentRoleOpt.isPresent()) {
return new ArrayList<>();
}
UserCurrentRole currentRole = currentRoleOpt.get();
if (currentRole.getRoleId() == 7 || currentRole.getRoleId() == 2) {
schId = currentRole.getSchId();
} else {
schId = currentRole.getSchId();
userId = currentRole.getUserId();
}
}
return userSettingsService.findLightAppList(schId, userId);
}
@PostMapping(value = "saveLightApp", produces = "application/json")
public void saveLightApp(BoaUser authUserWithDept, @RequestBody LightApp lightApp) {
UserCurrentRole currentRole = userCurrentRoleService.findById(authUserWithDept.getId())
.orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR));
Integer schId, userId = null;
if (authUserWithDept.getType() == 1) {
schId = 0;
} else if (currentRole.getRoleId() == 7 || currentRole.getRoleId() == 2) {
schId = currentRole.getSchId();
} else {
schId = currentRole.getSchId();
userId = currentRole.getUserId();
}
lightApp.setUserId(userId);
lightApp.setSchId(schId);
lightApp.setCId(authUserWithDept.getId());
lightApp.setCDate(new Date());
userSettingsService.saveLightApp(lightApp);
}
@PostMapping(value = "deleteLightAppById", produces = "application/json")
public void deleteLightAppById(BoaUser authUserWithDept, Integer id) {
userSettingsService.deleteLightAppById(id);
}
// ==================== 桌面应用 ====================
@PostMapping(value = "saveUserDesktopAppById", produces = "application/json")
public void saveUserDesktopAppById(BoaUser authUserWithDept, @RequestBody Map<String, Integer> params) {
Integer id = params.get("id");
Integer type = params.get("type");
DesktopAppType desktopAppType = DesktopAppType.valueOf(type);
Optional<UserSettings> optional = userSettingsService.findUserSettings(authUserWithDept.getId());
if (!optional.isPresent() || optional.get().getDesktopApps().isEmpty()) {
initUserSettingsDesktopApp(authUserWithDept.getId());
optional = userSettingsService.findUserSettings(authUserWithDept.getId());
}
UserSettings userSettings = optional.get();
if (userSettings.getDesktopApps().stream().anyMatch(x -> x.getAppId().equals(id)))
throw new BizException(ErrorCode.CUSTOM, "该应用已存在于桌面,请勿重复添加!");
UserSettingsDesktopApp desktopApp = new UserSettingsDesktopApp();
desktopApp.setAppType(desktopAppType);
desktopApp.setAppId(id);
desktopApp.setUserSettingsId(userSettings.getId());
userSettingsService.saveDesktopApp(desktopApp);
}
@PostMapping(value = "deleteDesktopAppById", produces = "application/json")
public void deleteDesktopAppById(BoaUser authUserWithDept, @RequestBody Map<String, Integer> params) {
Integer id = params.get("id");
Integer appId = params.get("appId");
if (id != null) {
userSettingsService.deleteDesktopAppById(id);
} else {
Integer userId = authUserWithDept.getId();
Optional<UserSettings> optional = userSettingsService.findUserSettings(userId);
List<UserSettingsDesktopApp> desktopList = getUserUsedByUserId(userId);
desktopList = desktopList.stream().filter(x -> !x.getAppId().equals(appId)).collect(Collectors.toList());
UserSettings model;
if (!optional.isPresent()) model = userSettingsService.initUserSettings(userId);
else model = optional.get();
desktopList.forEach(x -> x.setUserSettingsId(model.getId()));
userSettingsService.saveDesktopAppList(desktopList);
}
}
@PostMapping(value = "sortUserDesktopApp", produces = "application/json")
public void sortUserDesktopApp(BoaUser authUserWithDept, @RequestBody Map<String, String> params) {
String idsStr = params.get("ids");
List<Integer> ids = Arrays.stream(idsStr.split(",")).map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
Optional<UserSettings> optional = userSettingsService.findUserSettings(authUserWithDept.getId());
List<UserSettingsDesktopApp> desktopApps = new ArrayList<>();
if (!optional.isPresent() || optional.get().getDesktopApps().isEmpty()) {
desktopApps = initUserSettingsDesktopApp(authUserWithDept.getId());
desktopApps.forEach(x -> {
Integer i = ids.indexOf(x.getAppId());
x.setOrderNum(i);
});
} else {
desktopApps = optional.get().getDesktopApps();
desktopApps.forEach(x -> {
Integer i = ids.indexOf(x.getId());
x.setOrderNum(i);
});
}
userSettingsService.saveDesktopAppList(desktopApps);
}
// ==================== 头像 ====================
/**
* 上传头像:校验后经 OpenAPI 转发至 UserBase 统一存储(压缩并写入 sys_user.profile_picture)。<br>
* 前端调用:UserInfoModal 更换头像 → POST /api/avatarUpload。<br>
* 注意不复用 checkFile(其 5MB 上限被壁纸/图标共用),头像单独限制 20MB(与前端一致,拍照原图普遍偏大)。
*/
@PostMapping(value = "avatarUpload", produces = "application/json")
public Map<String, String> avatarUpload(BoaUser authUserWithDept, @RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BizException(ErrorCode.CUSTOM, "请选择上传文件");
}
if (file.getSize() > 20L * 1024 * 1024) {
throw new BizException(ErrorCode.CUSTOM, "图片大小不能超过20MB");
}
String url;
try {
url = openApiUserClient.updateUserProfilePicture(
authUserWithDept.getId(), file.getBytes(), file.getOriginalFilename());
} catch (Exception e) {
throw new BizException(ErrorCode.CUSTOM, e.getMessage());
}
Map<String, String> result = new HashMap<>();
result.put("url", url);
return result;
}
// ==================== 私有方法 ====================
private String upload(@RequestParam("file") MultipartFile file, String pathName) {
File fl = new File(FILE_PATH + "/" + pathName + "/");
if (!fl.exists()) fl.mkdirs();
String fileName = FileUtil.uploadImg(file, FILE_PATH + "/" + pathName + "/");
return "/upload/" + pathName + "/" + fileName;
}
/**
* 上传文件前置校验:非空 + 大小上限(5MB)。扩展名白名单在 FileUtil 内校验。
*/
private void checkFile(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BizException(ErrorCode.CUSTOM, "请选择上传文件");
}
if (file.getSize() > 5 * 1024 * 1024) {
throw new BizException(ErrorCode.CUSTOM, "图片大小不能超过5MB");
}
}
/**
* 归一化前端回传的壁纸 URL:去掉 FILE_WEB_PATH 前缀,并还原 getUserWallpaperList
* 输出时被 replace("/upload","") 移除的 /upload 前缀,得到与 wall 表存储一致的形式。
*/
private String normalizeWallpaperUrl(String url) {
if (url == null) return null;
String u = url.trim();
if (FILE_WEB_PATH != null && !FILE_WEB_PATH.isEmpty() && u.startsWith(FILE_WEB_PATH)) {
u = u.substring(FILE_WEB_PATH.length());
}
if (u.startsWith("/wallpaper/") || u.startsWith("/icon/") || u.startsWith("/logo/")) {
u = "/upload" + u;
}
return u;
}
/**
* 将某个人常用应用转化为桌面应用
*/
private List<UserSettingsDesktopApp> initUserSettingsDesktopApp(Integer userId) {
Optional<UserSettings> optional = userSettingsService.findUserSettings(userId);
List<UserSettingsDesktopApp> desktopList = getUserUsedByUserId(userId);
UserSettings model;
if (!optional.isPresent()) model = userSettingsService.initUserSettings(userId);
else model = optional.get();
desktopList.forEach(x -> x.setUserSettingsId(model.getId()));
return userSettingsService.saveDesktopAppList(desktopList);
}
/**
* 获取常用应用转化为桌面应用类型
*/
private List<UserSettingsDesktopApp> getUserUsedByUserId(Integer userId) {
UserCurrentRole currentRole = userCurrentRoleService.findById(userId)
.orElseThrow(() -> new BizException(ErrorCode.INTERNAL_SERVER_ERROR));
Optional<UsedApp> optionalUsedApp = usedAppService.findById(currentRole.getSchId(), currentRole.getUserId(), currentRole.getRoleId());
List<UserSettingsDesktopApp> desktopAppList = new ArrayList<>();
if (optionalUsedApp.isPresent() && optionalUsedApp.get().getAppIds() != null && !optionalUsedApp.get().getAppIds().isEmpty()) {
List<String> appIds = Arrays.asList(optionalUsedApp.get().getAppIds().split(","));
List<Integer> bschAppIds = appIds.stream().mapToInt(Integer::parseInt).boxed().collect(Collectors.toList());
Integer i = 0;
for (Integer appId : bschAppIds) {
UserSettingsDesktopApp desktopApp = new UserSettingsDesktopApp();
desktopApp.setAppId(appId);
desktopApp.setAppType(DesktopAppType.Bsch);
desktopApp.setOrderNum(i);
desktopAppList.add(desktopApp);
i++;
}
}
return desktopAppList;
}
}