外观偏好异步补齐A:用户外观偏好服务端真源(user_appearance 实体+Appearance 三端点)

- 新实体 user_appearance(per-user 一行,theme_state/avatar_style 紧凑编码,NULL=跟随学校默认)
- 新增 GET appearance 聚合出参 + saveMyTheme/saveMyAvatarStyle 双写端点(登录态 /api/** 链路)
- 聚合读永不抛:个人段/学校段独立降级(identity 跨仓故障→学校段 null),脏值视同未配置
- Logo 择优复用 findLogoList 口径(本校 type=1 → 系统 type=0 → null),URL 拼法对齐 getLogoList
- ThemeCodec 编解码下沉 + resolveThemeSchId/resolveSchId 下沉 SchSettingsService(行为等价重构,供共享)
- 单测:ThemeCodecTest 5 例 + AppearanceServiceTest 9 例(聚合降级/upsert 置 NULL/择优/校验从严)
This commit is contained in:
chenxing
2026-10-08 18:20:29 +08:00
parent 0e57022555
commit c6acd5d71a
11 changed files with 730 additions and 93 deletions
@@ -0,0 +1,50 @@
package com.yunhai.userhome.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import java.util.Date;
/**
* 用户外观偏好(user_appearance 表,外观偏好服务端化 2026-10-08)。
* <p>跨浏览器一致的真源,全局 per-user 一行(user_id 唯一)——与 localStorage 键同维度,
* 刻意不挂 user_settings 的 sch/role 维度。</p>
* <p>theme_state 存紧凑编码 {@code theme|sideDeep01|gradOn01|sideFollow01}(如 {@code ocean|1|0|1});
* avatar_style 取值 {@code text|silhouette};两列 NULL = 跟随学校默认。</p>
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@Table(name = "user_appearance", uniqueConstraints = {@UniqueConstraint(columnNames = "user_id", name = "uk_user")})
public class UserAppearance {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_id", nullable = false)
private Integer userId;
/** 用户自选主题档紧凑编码;NULL=跟随学校默认 */
@Column(name = "theme_state")
private String themeState;
/** 用户自选头像样式 text|silhouette;NULL=跟随学校默认 */
@Column(name = "avatar_style")
private String avatarStyle;
@Column(name = "c_date")
private Date cDate;
@Column(name = "u_date")
private Date uDate;
}