| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083 |
- package com.zxyj.service;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.zxyj.config.JwtConfig;
- import com.zxyj.dto.*;
- import com.zxyj.dto.RegisterWithIdCardDTO;
- import com.zxyj.dto.RegisterWithInviteCodeDTO;
- import com.zxyj.entity.Child;
- import com.zxyj.entity.Family;
- import com.zxyj.entity.User;
- import com.zxyj.mapper.ChildMapper;
- import com.zxyj.mapper.FamilyMapper;
- import com.zxyj.mapper.UserMapper;
- import com.zxyj.service.VerificationCodeService;
- import com.zxyj.service.WechatService;
- import com.zxyj.service.api.UserServiceInterface;
- import javax.annotation.Resource;
- import org.springframework.stereotype.Service;
- import org.springframework.util.DigestUtils;
- import java.nio.charset.StandardCharsets;
- import java.util.*;
- @Service
- public class UserService implements UserServiceInterface {
- @Resource
- private UserMapper userMapper;
- @Resource
- private FamilyMapper familyMapper;
- @Resource
- private ChildMapper childMapper;
- @Resource
- private JwtConfig jwtConfig;
- @Resource
- private VerificationCodeService verificationCodeService;
- @Resource
- private WechatService wechatService;
- public LoginResultDTO wechatLogin(WechatLoginDTO dto) {
- // 模拟微信登录,实际需要调用微信API获取openid
- String openid = "mock_openid_" + dto.getCode();
-
- // 查询用户是否存在
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getOpenid, openid));
- if (user == null) {
- // 新用户,创建家庭和用户
- Family family = new Family();
- family.setName("我的家庭");
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- user = new User();
- user.setOpenid(openid);
- user.setUnionid("");
- user.setFamilyId(family.getId());
- user.setRole("parent");
- user.setNickname(dto.getNickname());
- user.setAvatar(dto.getAvatar());
- user.setPassword("");
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- } else {
- // 管理员不能登录小程序
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- }
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- populateTeacherFields(result, user);
- return result;
- }
- /**
- * 手机号验证码登录
- */
- public LoginResultDTO phoneLogin(PhoneLoginDTO dto) {
- // 使用手机号作为唯一标识
- String phone = dto.getPhone();
- // 先通过手机号查找用户(更准确的判断)
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getPhone, phone));
- // 管理员不能登录小程序
- if (user != null && "admin".equals(user.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- boolean isNewUser = false;
- if (user == null) {
- // 新用户,创建新家庭和用户
- isNewUser = true;
- Family family = new Family();
- family.setName("我的家庭");
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- user = new User();
- user.setOpenid("phone:" + phone);
- user.setUnionid("");
- user.setFamilyId(family.getId());
- // 默认角色为家长,可以被覆盖
- user.setRole(dto.getRole() != null ? dto.getRole() : "parent");
- user.setNickname(dto.getNickname() != null ? dto.getNickname() : "用户" + phone.substring(7));
- user.setAvatar(dto.getAvatar());
- user.setPhone(phone);
- user.setBirthday(dto.getBirthday());
- user.setGender(dto.getGender());
- user.setPassword("");
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- } else {
- // 老用户,更新信息(如果提供了)
- if (dto.getNickname() != null && !dto.getNickname().isEmpty()) {
- user.setNickname(dto.getNickname());
- }
- if (dto.getAvatar() != null && !dto.getAvatar().isEmpty()) {
- user.setAvatar(dto.getAvatar());
- }
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- }
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(isNewUser);
- result.setNeedsRoleSelect(isNewUser);
- populateTeacherFields(result, user);
- return result;
- }
- /**
- * 微信手机号登录(正确获取openid和手机号)
- */
- public LoginResultDTO wechatPhoneLogin(WechatPhoneLoginDTO dto) {
- // 1. 通过code获取openid
- Map<String, String> sessionData = wechatService.code2Session(dto.getCode());
- String openid = sessionData.get("openid");
- String unionid = sessionData.get("unionid");
- // 2. 通过手机号code获取真实手机号
- String phone = wechatService.getPhoneNumber(dto.getPhoneCode());
- // 3. 先通过openid查找用户
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getOpenid, openid));
- boolean isNewUser = false;
- if (user == null) {
- // 4. openid不存在,通过手机号查找
- user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getPhone, phone));
- if (user == null) {
- // 5. 全新用户,创建新家庭和用户
- isNewUser = true;
- Family family = new Family();
- family.setName("我的家庭");
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- user = new User();
- user.setOpenid(openid);
- user.setUnionid(unionid);
- user.setFamilyId(family.getId());
- user.setRole("parent");
- user.setNickname(dto.getNickname() != null ? dto.getNickname() : "用户" + phone.substring(7));
- user.setAvatar(dto.getAvatar());
- user.setPhone(phone);
- user.setPassword("");
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- } else {
- // 6. 手机号已存在但openid不同,绑定openid
- user.setOpenid(openid);
- user.setUnionid(unionid);
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- }
- } else {
- // 7. openid已存在,更新手机号(如果手机号变了)
- if (phone != null && !phone.equals(user.getPhone())) {
- user.setPhone(phone);
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- }
- }
- // 管理员不能登录小程序
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(isNewUser);
- result.setOpenid(openid);
- // 新用户需要完善信息(仅当需要选择角色时)
- result.setNeedsRoleSelect(isNewUser);
- populateTeacherFields(result, user);
- return result;
- }
- /**
- * 微信openid静默登录(用户再次打开小程序时自动登录)
- */
- public LoginResultDTO silentLogin(String code) {
- // 1. 通过code获取openid
- Map<String, String> sessionData = wechatService.code2Session(code);
- String openid = sessionData.get("openid");
- String unionid = sessionData.get("unionid");
- // 2. 查找用户
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getOpenid, openid));
- if (user == null) {
- throw new RuntimeException("用户不存在,请先登录");
- }
- // 管理员不能登录小程序
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- // 3. 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(false);
- result.setOpenid(openid);
- populateTeacherFields(result, user);
- return result;
- }
- /**
- * 通过openid自动登录(前端已缓存openid时调用)
- */
- public LoginResultDTO autoLoginByOpenid(String openid) {
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getOpenid, openid));
- if (user == null) {
- return null;
- }
- // 管理员不能登录小程序
- if ("admin".equals(user.getRole())) {
- return null;
- }
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(false);
- result.setOpenid(openid);
- populateTeacherFields(result, user);
- return result;
- }
- public boolean setPassword(Long userId, String password) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- user.setPassword(encryptPassword(password));
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return true;
- }
- public boolean verifyPassword(Long userId, String password) {
- User user = userMapper.selectById(userId);
- if (user == null || user.getPassword() == null) {
- return false;
- }
- return user.getPassword().equals(encryptPassword(password));
- }
- public User getUserInfo(Long userId) {
- return userMapper.selectById(userId);
- }
- /**
- * 检查手机号是否已注册
- * @param phone 手机号
- * @return true=已注册,false=未注册
- */
- public boolean isPhoneRegistered(String phone) {
- if (phone == null || phone.isEmpty()) {
- return false;
- }
- User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getPhone, phone));
- return user != null;
- }
- /**
- * 直接注册(测试环境:不验证验证码)
- */
- public LoginResultDTO directRegister(DirectRegisterDTO dto) {
- // 创建家庭
- Family family = new Family();
- family.setName("我的家庭");
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- // 创建用户
- User user = new User();
- user.setOpenid("phone:" + dto.getPhone());
- user.setUnionid("");
- user.setFamilyId(family.getId());
- user.setRole(dto.getRole() != null ? dto.getRole() : "parent");
- user.setNickname(dto.getNickname() != null ? dto.getNickname() : "用户" + dto.getPhone().substring(7));
- user.setAvatar(dto.getAvatar());
- user.setPhone(dto.getPhone());
- user.setBirthday(dto.getBirthday());
- user.setGender(dto.getGender());
- user.setPassword("");
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- // 如果有邀请码,加入家庭
- if (dto.getInviteCode() != null && !dto.getInviteCode().isEmpty()) {
- try {
- joinFamily(user.getId(), dto.getInviteCode());
- } catch (Exception e) {
- // 忽略邀请码错误,继续使用创建的家庭
- }
- }
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(true);
- populateTeacherFields(result, user);
- return result;
- }
- public String switchMode(Long userId, String mode) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return null;
- }
- // 管理员角色不允许切换
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("管理员角色不允许切换");
- }
- // 验证用户是否拥有该角色
- if (!hasRole(user, mode)) {
- return null;
- }
- user.setRole(mode);
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return mode;
- }
- /**
- * 切换用户当前角色 (支持 parent/child/teacher)
- * 用户需要先拥有该角色才能切换
- */
- public String switchRole(Long userId, String targetRole) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return null;
- }
- // 管理员角色不允许切换
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("管理员角色不允许切换");
- }
- if (!hasRole(user, targetRole)) {
- throw new RuntimeException("您没有该角色权限");
- }
- if (!isValidRole(targetRole)) {
- return null;
- }
- user.setRole(targetRole);
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return targetRole;
- }
- public LoginResultDTO switchRoleForLogin(Long userId, String role) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
- // 管理员角色不允许切换
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("管理员角色不允许切换");
- }
- if ("teacher".equals(role) && !hasRole(user, "teacher")) {
- throw new RuntimeException("您不是成长规划师,无法切换为规划师模式");
- }
- user.setRole(role);
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(false);
- populateTeacherFields(result, user);
- return result;
- }
- /**
- * 获取用户所有角色列表
- */
- public List<String> getUserRoles(Long userId) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return new ArrayList<>();
- }
- return parseRoles(user.getRoles());
- }
- /**
- * 检查用户是否拥有指定角色
- */
- public boolean hasRole(Long userId, String role) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- return hasRole(user, role);
- }
- /**
- * 添加角色到用户 (用于用户注册成为老师时)
- */
- public boolean addRole(Long userId, String newRole) {
- User user = userMapper.selectById(userId);
- if (user == null || !isValidRole(newRole)) {
- return false;
- }
- // 如果用户还没有roles字段,设置默认值
- if (user.getRoles() == null || user.getRoles().isEmpty()) {
- user.setRoles(user.getRole()); // 当前角色作为第一个角色
- }
- // 检查是否已拥有该角色
- if (hasRole(user, newRole)) {
- return true; // 已有该角色
- }
- // 添加新角色
- List<String> roleList = parseRoles(user.getRoles());
- roleList.add(newRole);
- user.setRoles(joinRoles(roleList));
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return true;
- }
- /**
- * 检查用户是否拥有指定角色 (内部方法)
- */
- private boolean hasRole(User user, String role) {
- List<String> roles = parseRoles(user.getRoles());
- return roles.contains(role);
- }
- /**
- * 解析角色字符串为列表
- */
- private List<String> parseRoles(String rolesStr) {
- List<String> result = new ArrayList<>();
- if (rolesStr == null || rolesStr.isEmpty()) {
- return result;
- }
- // 支持JSON数组格式或逗号分隔格式
- if (rolesStr.startsWith("[")) {
- // JSON格式解析
- rolesStr = rolesStr.replace("[", "").replace("]", "")
- .replace("\"", "").replace(" ", "");
- String[] arr = rolesStr.split(",");
- for (String r : arr) {
- if (!r.isEmpty()) {
- result.add(r.trim());
- }
- }
- } else {
- // 逗号分隔格式
- String[] arr = rolesStr.split(",");
- for (String r : arr) {
- if (!r.trim().isEmpty()) {
- result.add(r.trim());
- }
- }
- }
- return result;
- }
- /**
- * 将角色列表转换为字符串
- */
- private String joinRoles(List<String> roles) {
- return String.join(",", roles);
- }
- /**
- * 检查角色是否有效
- */
- private boolean isValidRole(String role) {
- return "parent".equals(role) || "child".equals(role) || "teacher".equals(role);
- }
- /**
- * 家长切换到指定孩子身份(视图切换,不修改用户的实际角色)
- * 家长可以在家长模式下查看孩子的任务和积分
- */
- public Long switchToChild(Long userId, Long childId) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return null;
- }
- Child child = childMapper.selectById(childId);
- if (child == null || !child.getFamilyId().equals(user.getFamilyId())) {
- return null;
- }
- // 注意:不修改用户的 role 字段,只是返回 childId 让前端切换视图
- // 前端应该使用 currentRole 或 viewMode 来控制显示模式
- return childId;
- }
- /**
- * 从孩子视图切换回家长视图
- * 这只是确认切换操作,不需要修改数据库
- */
- public boolean switchBackToParent(Long userId) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- // 不需要修改用户的 role 字段
- // 只是确认操作成功,前端切换视图
- return true;
- }
- public LoginResultDTO registerWithIdCard(RegisterWithIdCardDTO dto) {
- // 验证验证码
- boolean valid = verificationCodeService.verifyCode(dto.getPhone(), dto.getCode(), "login");
- if (!valid) {
- throw new RuntimeException("验证码错误或已过期");
- }
- // 通过身份证查找是否已有注册的用户
- User existingUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getIdCard, dto.getIdCard()));
-
- Family family;
- User user;
-
- if (existingUser != null) {
- // 管理员不能登录小程序
- if ("admin".equals(existingUser.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- // 如果存在相同身份证的用户,加入其家庭
- user = existingUser;
- family = familyMapper.selectById(user.getFamilyId());
-
- // 更新用户信息(昵称和头像可以更新)
- user.setNickname(dto.getNickname());
- user.setAvatar(dto.getAvatar());
- // 手机号也可以更新(如果需要)
- user.setOpenid("phone:" + dto.getPhone());
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- } else {
- // 创建新家庭和用户
- family = new Family();
- family.setName("我的家庭");
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- user = new User();
- user.setOpenid("phone:" + dto.getPhone());
- user.setUnionid("");
- user.setFamilyId(family.getId());
- user.setRole("parent");
- user.setNickname(dto.getNickname());
- user.setAvatar(dto.getAvatar());
- user.setIdCard(dto.getIdCard());
- user.setRealName(dto.getRealName());
- user.setPassword(""); // 初始密码为空,需要后续设置
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- }
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- populateTeacherFields(result, user);
- return result;
- }
- public ChildInfoDTO createChild(Long userId, CreateChildDTO dto) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return null;
- }
- if (dto.getNickname() == null || dto.getNickname().trim().isEmpty()) {
- throw new IllegalArgumentException("孩子昵称不能为空");
- }
- if (dto.getAge() == null || dto.getAge() < 1 || dto.getAge() > 18) {
- throw new IllegalArgumentException("请输入有效的年龄(1-18岁)");
- }
- Child child = new Child();
- child.setUserId(userId);
- child.setFamilyId(user.getFamilyId());
- child.setNickname(dto.getNickname().trim());
- child.setAge(dto.getAge());
- child.setBirthday(dto.getBirthday());
- child.setGender(dto.getGender());
- child.setDanLevel(dto.getDanLevel());
- child.setPhone(dto.getPhone());
- child.setIdCard(dto.getIdCard());
- // 扣分开关:优先使用传入值,否则根据年龄判断
- if (dto.getPenaltyEnabled() != null) {
- child.setPenaltyEnabled(dto.getPenaltyEnabled());
- } else {
- // 年龄可能为空,默认不扣分
- Integer age = dto.getAge();
- child.setPenaltyEnabled(age != null && age >= 6 ? 1 : 0);
- }
- child.setTheme("default");
- child.setTotalPoints(0);
- child.setStreakDays(0);
- child.setFocusMaxDaily(3);
- child.setFocusRemaining(3);
- child.setFocusResetDate(new Date());
- child.setCreatedAt(new Date());
- child.setUpdatedAt(new Date());
- childMapper.insert(child);
- return toChildInfoDTO(child);
- }
- public List<ChildInfoDTO> getChildren(Long userId) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return null;
- }
- List<Child> children = childMapper.selectList(new LambdaQueryWrapper<Child>()
- .eq(Child::getFamilyId, user.getFamilyId()));
- return children.stream().map(this::toChildInfoDTO).collect(java.util.stream.Collectors.toList());
- }
- public boolean updateChild(Long userId, Long childId, UpdateChildDTO dto) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- Child child = childMapper.selectById(childId);
- if (child == null || child.getFamilyId() == null || !child.getFamilyId().equals(user.getFamilyId())) {
- return false;
- }
- if (dto.getNickname() != null) {
- child.setNickname(dto.getNickname());
- }
- if (dto.getAge() != null) {
- child.setAge(dto.getAge());
- }
- if (dto.getBirthday() != null) {
- child.setBirthday(dto.getBirthday());
- }
- if (dto.getGender() != null) {
- child.setGender(dto.getGender());
- }
- if (dto.getDanLevel() != null) {
- child.setDanLevel(dto.getDanLevel());
- }
- if (dto.getPhone() != null) {
- child.setPhone(dto.getPhone());
- }
- if (dto.getIdCard() != null) {
- child.setIdCard(dto.getIdCard());
- }
- if (dto.getPenaltyEnabled() != null) {
- child.setPenaltyEnabled(dto.getPenaltyEnabled());
- }
- if (dto.getTheme() != null) {
- child.setTheme(dto.getTheme());
- }
- child.setUpdatedAt(new Date());
- childMapper.updateById(child);
- return true;
- }
- private String encryptPassword(String password) {
- return DigestUtils.md5DigestAsHex(("xzyj_salt_" + password).getBytes(StandardCharsets.UTF_8));
- }
- private String generateInviteCode() {
- return UUID.randomUUID().toString().substring(0, 8).toUpperCase();
- }
- private ChildInfoDTO toChildInfoDTO(Child child) {
- ChildInfoDTO dto = new ChildInfoDTO();
- dto.setId(child.getId());
- dto.setNickname(child.getNickname());
- dto.setAge(child.getAge());
- dto.setBirthday(child.getBirthday());
- dto.setGender(child.getGender());
- dto.setDanLevel(child.getDanLevel());
- dto.setPhone(child.getPhone());
- dto.setIdCard(child.getIdCard());
- dto.setPenaltyEnabled(child.getPenaltyEnabled());
- dto.setTheme(child.getTheme());
- dto.setTotalPoints(child.getTotalPoints());
- dto.setStreakDays(child.getStreakDays());
- dto.setFocusRemaining(child.getFocusRemaining());
- return dto;
- }
- /**
- * 更新用户信息
- */
- public boolean updateUserInfo(Long userId, UpdateUserDTO dto) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- // 管理员角色不允许修改
- if ("admin".equals(user.getRole())) {
- throw new RuntimeException("管理员角色不允许修改");
- }
- if (dto.getNickname() != null) {
- user.setNickname(dto.getNickname());
- }
- if (dto.getAvatar() != null) {
- user.setAvatar(dto.getAvatar());
- }
- if (dto.getRealName() != null) {
- user.setRealName(dto.getRealName());
- }
- // 更新角色
- if (dto.getRole() != null) {
- user.setRole(dto.getRole());
- }
- // 更新性别
- if (dto.getGender() != null) {
- user.setGender(dto.getGender());
- }
- // 更新生日(将字符串转换为Date)
- if (dto.getBirthday() != null && !dto.getBirthday().isEmpty()) {
- try {
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
- user.setBirthday(sdf.parse(dto.getBirthday()));
- } catch (Exception e) {
- // 忽略解析错误
- }
- }
- // 更新身份证号
- if (dto.getIdCard() != null && !dto.getIdCard().isEmpty()) {
- user.setIdCard(dto.getIdCard());
- // 如果没有手动设置生日,尝试从身份证号提取
- if (user.getBirthday() == null) {
- String birthdayFromIdCard = extractBirthdayFromIdCard(dto.getIdCard());
- if (birthdayFromIdCard != null) {
- try {
- java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
- user.setBirthday(sdf.parse(birthdayFromIdCard));
- } catch (Exception e) {
- // 忽略解析错误
- }
- }
- }
- }
- // 更新成长规划师信息
- if (dto.getTeacherNo() != null) {
- user.setTeacherNo(dto.getTeacherNo());
- }
- if (dto.getTeacherPhoto() != null) {
- user.setTeacherPhoto(dto.getTeacherPhoto());
- }
- if (dto.getCertificateImage() != null) {
- user.setCertificateImage(dto.getCertificateImage());
- }
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return true;
- }
- /**
- * 从身份证号提取生日
- * 15位:1985年07月08日 -> 1985-07-08
- * 18位:1985年07月08日 -> 1985-07-08
- */
- private String extractBirthdayFromIdCard(String idCard) {
- if (idCard == null || idCard.isEmpty()) {
- return null;
- }
- try {
- if (idCard.length() == 15) {
- // 15位身份证:出生日期在第6-12位
- String year = "19" + idCard.substring(6, 8);
- String month = idCard.substring(8, 10);
- String day = idCard.substring(10, 12);
- return String.format("%s-%s-%s", year, month, day);
- } else if (idCard.length() == 18) {
- // 18位身份证:出生日期在第6-14位
- String year = idCard.substring(6, 10);
- String month = idCard.substring(10, 12);
- String day = idCard.substring(12, 14);
- return String.format("%s-%s-%s", year, month, day);
- }
- } catch (Exception e) {
- // 忽略解析异常
- }
- return null;
- }
- /**
- * 通过邀请码加入家庭
- */
- public boolean joinFamily(Long userId, String inviteCode) {
- if (inviteCode == null || inviteCode.isEmpty()) {
- throw new RuntimeException("邀请码不能为空");
- }
- // 查找家庭
- Family family = familyMapper.selectOne(new LambdaQueryWrapper<Family>()
- .eq(Family::getInviteCode, inviteCode));
- if (family == null) {
- throw new RuntimeException("邀请码无效");
- }
- // 更新用户的家庭ID
- User user = userMapper.selectById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
- user.setFamilyId(family.getId());
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
-
- // 如果家庭绑定了成长规划师,自动将家庭ID添加到成长规划师的 teacherFamilyIds
- if (family.getTeacherId() != null) {
- User teacher = userMapper.selectById(family.getTeacherId());
- if (teacher != null && "teacher".equals(teacher.getRole())) {
- String currentIds = teacher.getTeacherFamilyIds();
- String newFamilyId = String.valueOf(family.getId());
- if (currentIds == null || !currentIds.contains(newFamilyId)) {
- String updatedIds = currentIds == null ? newFamilyId : currentIds + "," + newFamilyId;
- teacher.setTeacherFamilyIds(updatedIds);
- teacher.setUpdatedAt(new Date());
- userMapper.updateById(teacher);
- }
- }
- }
-
- return true;
- }
- /**
- * 为用户创建新家庭
- */
- public Long createFamilyForUser(Long userId, String familyName) {
- User user = userMapper.selectById(userId);
- if (user == null) {
- throw new RuntimeException("用户不存在");
- }
- // 创建新家庭
- Family family = new Family();
- family.setName(familyName);
- family.setInviteCode(generateInviteCode());
- family.setCreatedAt(new Date());
- family.setUpdatedAt(new Date());
- familyMapper.insert(family);
- // 更新用户的家庭ID
- user.setFamilyId(family.getId());
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- return family.getId();
- }
- /**
- * 使用邀请码注册并加入家庭
- */
- public LoginResultDTO registerWithInviteCode(RegisterWithInviteCodeDTO dto) {
- String phone = dto.getPhone();
- String inviteCode = dto.getInviteCode();
- String role = dto.getRole() != null ? dto.getRole() : "parent";
- String nickname = dto.getNickname() != null ? dto.getNickname() : "用户" + phone.substring(7);
-
- // 查找家庭
- Family family = familyMapper.selectOne(new LambdaQueryWrapper<Family>()
- .eq(Family::getInviteCode, inviteCode));
-
- User user;
- boolean isNewUser = false;
-
- if (family == null) {
- throw new RuntimeException("邀请码无效");
- }
-
- // 检查手机号是否已注册
- User existingUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
- .eq(User::getPhone, phone));
-
- if (existingUser != null) {
- // 管理员不能登录小程序
- if ("admin".equals(existingUser.getRole())) {
- throw new RuntimeException("该账号不允许登录小程序");
- }
- // 手机号已注册,加入家庭
- user = existingUser;
- user.setFamilyId(family.getId());
- user.setUpdatedAt(new Date());
- userMapper.updateById(user);
- } else {
- // 创建新用户并加入家庭
- isNewUser = true;
- user = new User();
- user.setOpenid("phone:" + phone);
- user.setUnionid("");
- user.setFamilyId(family.getId());
- user.setRole(role);
- user.setNickname(nickname);
- user.setPhone(phone);
- user.setPassword("");
- user.setCreatedAt(new Date());
- user.setUpdatedAt(new Date());
- userMapper.insert(user);
- }
-
- // 如果家庭绑定了成长规划师,自动将家庭ID添加到成长规划师的 teacherFamilyIds
- if (family.getTeacherId() != null) {
- User teacher = userMapper.selectById(family.getTeacherId());
- if (teacher != null && "teacher".equals(teacher.getRole())) {
- String currentIds = teacher.getTeacherFamilyIds();
- String newFamilyId = String.valueOf(family.getId());
- if (currentIds == null || !currentIds.contains(newFamilyId)) {
- String updatedIds = currentIds == null ? newFamilyId : currentIds + "," + newFamilyId;
- teacher.setTeacherFamilyIds(updatedIds);
- teacher.setUpdatedAt(new Date());
- userMapper.updateById(teacher);
- }
- }
- }
-
- // 生成token
- String token = jwtConfig.generateToken(user.getId(), user.getRole());
-
- LoginResultDTO result = new LoginResultDTO();
- result.setToken(token);
- result.setUserId(user.getId());
- result.setRole(user.getRole());
- result.setRoles(user.getRoles());
- result.setFamilyId(user.getFamilyId());
- result.setNickname(user.getNickname());
- result.setIsNewUser(isNewUser);
- populateTeacherFields(result, user);
-
- return result;
- }
- /**
- * 重置用户密码(管理员功能)
- * @param userId 用户ID
- * @param newPassword 新密码
- * @return 是否成功
- */
- public boolean resetPassword(Long userId, String newPassword) {
- if (userId == null || newPassword == null || newPassword.length() < 6) {
- return false;
- }
- User user = userMapper.selectById(userId);
- if (user == null) {
- return false;
- }
- user.setPassword(encryptPassword(newPassword));
- user.setUpdatedAt(new Date());
- return userMapper.updateById(user) > 0;
- }
- private void populateTeacherFields(LoginResultDTO result, User user) {
- result.setTeacherStatus(user.getTeacherStatus() != null ? user.getTeacherStatus() : "pending");
- result.setTeacherRejectReason(user.getTeacherRejectReason());
- boolean hasTeacher = hasRole(user, "teacher");
- result.setHasTeacherRole(hasTeacher);
- }
- }
|