diff --git a/backend/src/main/java/com/xly/erp/modules/usr/entity/UsrCompany.java b/backend/src/main/java/com/xly/erp/modules/usr/entity/UsrCompany.java new file mode 100644 index 0000000..d5041aa --- /dev/null +++ b/backend/src/main/java/com/xly/erp/modules/usr/entity/UsrCompany.java @@ -0,0 +1,42 @@ +package com.xly.erp.modules.usr.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.xly.erp.common.base.BaseEntity; + +/** + * 公司实体,映射 {@code usr_company}(docs/03 SSoT)。REQ-USR-004 T3。 + * + *
继承 {@link BaseEntity} 复用标准列({@code iIncrement}/{@code sId}/租户列/{@code tCreateDate}); + * 业务列 {@code sCompanyName}(公司名称,登录版本下拉显示来源)、{@code sVersion}(版本/账套标识,可空)。 + * 仅供登录流程只读(companyId 存在性校验 + 公司下拉列表)。
+ */ +@TableName("usr_company") +public class UsrCompany extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** 公司名称(登录页版本下拉的显示来源)。 */ + @TableField("sCompanyName") + private String sCompanyName; + + /** 版本 / 账套标识(可空)。 */ + @TableField("sVersion") + private String sVersion; + + public String getSCompanyName() { + return sCompanyName; + } + + public void setSCompanyName(String sCompanyName) { + this.sCompanyName = sCompanyName; + } + + public String getSVersion() { + return sVersion; + } + + public void setSVersion(String sVersion) { + this.sVersion = sVersion; + } +} diff --git a/backend/src/main/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapper.java b/backend/src/main/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapper.java new file mode 100644 index 0000000..c826fc7 --- /dev/null +++ b/backend/src/main/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapper.java @@ -0,0 +1,15 @@ +package com.xly.erp.modules.usr.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xly.erp.modules.usr.entity.UsrCompany; +import org.apache.ibatis.annotations.Mapper; + +/** + * 公司 Mapper(MyBatis-Plus)。REQ-USR-004 T3。 + * + *无自定义方法,复用 BaseMapper 的 {@code selectById}(companyId 存在性校验) + * 与 {@code selectList}(公司下拉列表)。
+ */ +@Mapper +public interface UsrCompanyMapper extends BaseMapper{@code token} 为 JWT(不含 {@code Bearer } 前缀);嵌套 {@code user} 为登录用户基础信息。 + * 严格不含 {@code sPassword} / 租户列。匈牙利前缀字段经 {@link JsonProperty} 锁小驼峰键。
+ */ +public class LoginVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** JWT 令牌(不含 Bearer 前缀,前端自行拼 Authorization 头)。 */ + private String token; + + /** 登录用户基础信息(嵌套对象 user{...})。 */ + private UserInfo user; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public UserInfo getUser() { + return user; + } + + public void setUser(UserInfo user) { + this.user = user; + } + + /** + * 登录用户基础信息(嵌套于 {@code user}),来源 usr_user,绝不含密码。 + */ + public static class UserInfo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 用户主键 iIncrement。 */ + private Integer id; + + /** 用户名。 */ + @JsonProperty("sUserName") + private String sUserName; + + /** 用户类型。 */ + @JsonProperty("sUserType") + private String sUserType; + + /** 界面语言。 */ + @JsonProperty("sLanguage") + private String sLanguage; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getSUserName() { + return sUserName; + } + + public void setSUserName(String sUserName) { + this.sUserName = sUserName; + } + + public String getSUserType() { + return sUserType; + } + + public void setSUserType(String sUserType) { + this.sUserType = sUserType; + } + + public String getSLanguage() { + return sLanguage; + } + + public void setSLanguage(String sLanguage) { + this.sLanguage = sLanguage; + } + } +} diff --git a/backend/src/test/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapperTest.java b/backend/src/test/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapperTest.java new file mode 100644 index 0000000..1940ecd --- /dev/null +++ b/backend/src/test/java/com/xly/erp/modules/usr/mapper/UsrCompanyMapperTest.java @@ -0,0 +1,52 @@ +package com.xly.erp.modules.usr.mapper; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.xly.erp.modules.usr.entity.UsrCompany; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +/** + * REQ-USR-004 T3:UsrCompanyMapper(BaseMapper)连库验证实体 ↔ usr_company 列映射。 + * + *@SpringBootTest 连测试库(Flyway 已 apply V1),@Transactional 测试回滚避免污染库。 + * 插 1 条公司 fixture(名前缀 IT4_CO_),验证 selectById / selectList 取回字段正确。
+ */ +@SpringBootTest +@ActiveProfiles("test") +@Transactional +class UsrCompanyMapperTest { + + @Autowired + private UsrCompanyMapper usrCompanyMapper; + + private UsrCompany insertFixture() { + UsrCompany c = new UsrCompany(); + c.setSCompanyName("IT4_CO_总部"); + c.setSVersion("企业版"); + usrCompanyMapper.insert(c); + return c; + } + + @Test + void selectByIdReturnsCompany() { + UsrCompany inserted = insertFixture(); + assertThat(inserted.getIIncrement()).isNotNull(); + + UsrCompany found = usrCompanyMapper.selectById(inserted.getIIncrement()); + assertThat(found).isNotNull(); + assertThat(found.getSCompanyName()).isEqualTo("IT4_CO_总部"); + assertThat(found.getSVersion()).isEqualTo("企业版"); + assertThat(found.getIIncrement()).isEqualTo(inserted.getIIncrement()); + } + + @Test + void selectListReturnsAll() { + UsrCompany inserted = insertFixture(); + assertThat(usrCompanyMapper.selectList(null)) + .anyMatch(c -> inserted.getIIncrement().equals(c.getIIncrement())); + } +} diff --git a/backend/src/test/java/com/xly/erp/modules/usr/vo/LoginVOJsonTest.java b/backend/src/test/java/com/xly/erp/modules/usr/vo/LoginVOJsonTest.java new file mode 100644 index 0000000..754d708 --- /dev/null +++ b/backend/src/test/java/com/xly/erp/modules/usr/vo/LoginVOJsonTest.java @@ -0,0 +1,43 @@ +package com.xly.erp.modules.usr.vo; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +/** + * REQ-USR-004 T3:LoginVO 序列化结构与键名(含嵌套 user,绝不含密码)。 + * + *验证顶层 {@code token} + 嵌套对象 {@code user{id,sUserName,sUserType,sLanguage}}, + * 匈牙利前缀字段经 {@code @JsonProperty} 锁小驼峰键;响应体不含 {@code sPassword}/{@code password} + * /大驼峰键 {@code SUserName}(spec § 3 规则 9 / 验收 11)。
+ */ +class LoginVOJsonTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void serializesTokenAndNestedUserNoPassword() throws Exception { + LoginVO.UserInfo user = new LoginVO.UserInfo(); + user.setId(1); + user.setSUserName("admin"); + user.setSUserType("超级管理员"); + user.setSLanguage("中文"); + + LoginVO vo = new LoginVO(); + vo.setToken("t.t.t"); + vo.setUser(user); + + String json = objectMapper.writeValueAsString(vo); + + assertThat(json).contains("\"token\":\"t.t.t\""); + assertThat(json).contains("\"user\":"); + assertThat(json).contains("\"id\":1"); + assertThat(json).contains("\"sUserName\":\"admin\""); + assertThat(json).contains("\"sUserType\":\"超级管理员\""); + assertThat(json).contains("\"sLanguage\":\"中文\""); + assertThat(json).doesNotContain("sPassword"); + assertThat(json).doesNotContain("password"); + assertThat(json).doesNotContain("SUserName"); + } +}