UserService.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. package com.zxyj.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  3. import com.zxyj.config.JwtConfig;
  4. import com.zxyj.dto.*;
  5. import com.zxyj.dto.RegisterWithIdCardDTO;
  6. import com.zxyj.entity.Child;
  7. import com.zxyj.entity.Family;
  8. import com.zxyj.entity.User;
  9. import com.zxyj.mapper.ChildMapper;
  10. import com.zxyj.mapper.FamilyMapper;
  11. import com.zxyj.mapper.UserMapper;
  12. import com.zxyj.service.VerificationCodeService;
  13. import javax.annotation.Resource;
  14. import org.springframework.stereotype.Service;
  15. import org.springframework.util.DigestUtils;
  16. import java.nio.charset.StandardCharsets;
  17. import java.util.Date;
  18. import java.util.List;
  19. import java.util.UUID;
  20. @Service
  21. public class UserService {
  22. @Resource
  23. private UserMapper userMapper;
  24. @Resource
  25. private FamilyMapper familyMapper;
  26. @Resource
  27. private ChildMapper childMapper;
  28. @Resource
  29. private JwtConfig jwtConfig;
  30. @Resource
  31. private VerificationCodeService verificationCodeService;
  32. public LoginResultDTO wechatLogin(WechatLoginDTO dto) {
  33. // 模拟微信登录,实际需要调用微信API获取openid
  34. String openid = "mock_openid_" + dto.getCode();
  35. // 查询用户是否存在
  36. User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
  37. .eq(User::getOpenid, openid));
  38. if (user == null) {
  39. // 新用户,创建家庭和用户
  40. Family family = new Family();
  41. family.setName("我的家庭");
  42. family.setInviteCode(generateInviteCode());
  43. family.setCreatedAt(new Date());
  44. family.setUpdatedAt(new Date());
  45. familyMapper.insert(family);
  46. user = new User();
  47. user.setOpenid(openid);
  48. user.setUnionid("");
  49. user.setFamilyId(family.getId());
  50. user.setRole("parent");
  51. user.setNickname(dto.getNickname());
  52. user.setAvatar(dto.getAvatar());
  53. user.setPassword("");
  54. user.setCreatedAt(new Date());
  55. user.setUpdatedAt(new Date());
  56. userMapper.insert(user);
  57. }
  58. // 生成token
  59. String token = jwtConfig.generateToken(user.getId(), user.getRole());
  60. LoginResultDTO result = new LoginResultDTO();
  61. result.setToken(token);
  62. result.setUserId(user.getId());
  63. result.setRole(user.getRole());
  64. result.setFamilyId(user.getFamilyId());
  65. result.setNickname(user.getNickname());
  66. return result;
  67. }
  68. /**
  69. * 手机号验证码登录
  70. */
  71. public LoginResultDTO phoneLogin(PhoneLoginDTO dto) {
  72. // 使用手机号作为唯一标识
  73. String phone = dto.getPhone();
  74. // 查询用户是否存在
  75. User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
  76. .eq(User::getOpenid, "phone:" + phone));
  77. boolean isNewUser = false;
  78. if (user == null) {
  79. // 新用户,创建新家庭和用户
  80. isNewUser = true;
  81. Family family = new Family();
  82. family.setName("我的家庭");
  83. family.setInviteCode(generateInviteCode());
  84. family.setCreatedAt(new Date());
  85. family.setUpdatedAt(new Date());
  86. familyMapper.insert(family);
  87. user = new User();
  88. user.setOpenid("phone:" + phone);
  89. user.setUnionid("");
  90. user.setFamilyId(family.getId());
  91. // 默认角色为家长,可以被覆盖
  92. user.setRole(dto.getRole() != null ? dto.getRole() : "parent");
  93. user.setNickname(dto.getNickname() != null ? dto.getNickname() : "用户" + phone.substring(7));
  94. user.setAvatar(dto.getAvatar());
  95. user.setPhone(phone);
  96. user.setBirthday(dto.getBirthday());
  97. user.setGender(dto.getGender());
  98. user.setPassword("");
  99. user.setCreatedAt(new Date());
  100. user.setUpdatedAt(new Date());
  101. userMapper.insert(user);
  102. }
  103. // 生成token
  104. String token = jwtConfig.generateToken(user.getId(), user.getRole());
  105. LoginResultDTO result = new LoginResultDTO();
  106. result.setToken(token);
  107. result.setUserId(user.getId());
  108. result.setRole(user.getRole());
  109. result.setFamilyId(user.getFamilyId());
  110. result.setNickname(user.getNickname());
  111. result.setIsNewUser(isNewUser);
  112. return result;
  113. }
  114. public boolean setPassword(Long userId, String password) {
  115. User user = userMapper.selectById(userId);
  116. if (user == null) {
  117. return false;
  118. }
  119. user.setPassword(encryptPassword(password));
  120. user.setUpdatedAt(new Date());
  121. userMapper.updateById(user);
  122. return true;
  123. }
  124. public boolean verifyPassword(Long userId, String password) {
  125. User user = userMapper.selectById(userId);
  126. if (user == null || user.getPassword() == null) {
  127. return false;
  128. }
  129. return user.getPassword().equals(encryptPassword(password));
  130. }
  131. public User getUserInfo(Long userId) {
  132. return userMapper.selectById(userId);
  133. }
  134. public String switchMode(Long userId, String mode) {
  135. User user = userMapper.selectById(userId);
  136. if (user == null) {
  137. return null;
  138. }
  139. user.setRole(mode);
  140. user.setUpdatedAt(new Date());
  141. userMapper.updateById(user);
  142. return mode;
  143. }
  144. /**
  145. * 家长切换到指定孩子身份
  146. */
  147. public Long switchToChild(Long userId, Long childId) {
  148. User user = userMapper.selectById(userId);
  149. if (user == null || !"parent".equals(user.getRole())) {
  150. return null;
  151. }
  152. Child child = childMapper.selectById(childId);
  153. if (child == null || !child.getFamilyId().equals(user.getFamilyId())) {
  154. return null;
  155. }
  156. // 保存原用户ID到会话中,后续可以切回
  157. // 这里用简单的机制:存储到用户的 extended 字段或者新表
  158. // 为简化,先返回 childId,实际切换通过 setRole 实现
  159. // 实际切换角色为 child
  160. user.setRole("child");
  161. user.setUpdatedAt(new Date());
  162. userMapper.updateById(user);
  163. return childId;
  164. }
  165. /**
  166. * 孩子切换回家长身份
  167. */
  168. public boolean switchBackToParent(Long userId) {
  169. User user = userMapper.selectById(userId);
  170. if (user == null || !"child".equals(user.getRole())) {
  171. return false;
  172. }
  173. user.setRole("parent");
  174. user.setUpdatedAt(new Date());
  175. userMapper.updateById(user);
  176. return true;
  177. }
  178. public LoginResultDTO registerWithIdCard(RegisterWithIdCardDTO dto) {
  179. // 验证验证码
  180. boolean valid = verificationCodeService.verifyCode(dto.getPhone(), dto.getCode(), "login");
  181. if (!valid) {
  182. throw new RuntimeException("验证码错误或已过期");
  183. }
  184. // 通过身份证查找是否已有注册的用户
  185. User existingUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
  186. .eq(User::getIdCard, dto.getIdCard()));
  187. Family family;
  188. User user;
  189. if (existingUser != null) {
  190. // 如果存在相同身份证的用户,加入其家庭
  191. user = existingUser;
  192. family = familyMapper.selectById(user.getFamilyId());
  193. // 更新用户信息(昵称和头像可以更新)
  194. user.setNickname(dto.getNickname());
  195. user.setAvatar(dto.getAvatar());
  196. // 手机号也可以更新(如果需要)
  197. user.setOpenid("phone:" + dto.getPhone());
  198. user.setUpdatedAt(new Date());
  199. userMapper.updateById(user);
  200. } else {
  201. // 创建新家庭和用户
  202. family = new Family();
  203. family.setName("我的家庭");
  204. family.setInviteCode(generateInviteCode());
  205. family.setCreatedAt(new Date());
  206. family.setUpdatedAt(new Date());
  207. familyMapper.insert(family);
  208. user = new User();
  209. user.setOpenid("phone:" + dto.getPhone());
  210. user.setUnionid("");
  211. user.setFamilyId(family.getId());
  212. user.setRole("parent");
  213. user.setNickname(dto.getNickname());
  214. user.setAvatar(dto.getAvatar());
  215. user.setIdCard(dto.getIdCard());
  216. user.setRealName(dto.getRealName());
  217. user.setPassword(""); // 初始密码为空,需要后续设置
  218. user.setCreatedAt(new Date());
  219. user.setUpdatedAt(new Date());
  220. userMapper.insert(user);
  221. }
  222. // 生成token
  223. String token = jwtConfig.generateToken(user.getId(), user.getRole());
  224. LoginResultDTO result = new LoginResultDTO();
  225. result.setToken(token);
  226. result.setUserId(user.getId());
  227. result.setRole(user.getRole());
  228. result.setFamilyId(user.getFamilyId());
  229. result.setNickname(user.getNickname());
  230. return result;
  231. }
  232. public ChildInfoDTO createChild(Long userId, CreateChildDTO dto) {
  233. User user = userMapper.selectById(userId);
  234. if (user == null) {
  235. return null;
  236. }
  237. Child child = new Child();
  238. child.setUserId(userId);
  239. child.setFamilyId(user.getFamilyId());
  240. child.setNickname(dto.getNickname());
  241. child.setAge(dto.getAge());
  242. child.setBirthday(dto.getBirthday());
  243. child.setGender(dto.getGender());
  244. child.setDanLevel(dto.getDanLevel());
  245. // 根据年龄设置扣分开关:6岁以下默认关闭,6岁及以上默认开启
  246. child.setPenaltyEnabled(dto.getAge() >= 6 ? 1 : 0);
  247. child.setTheme("default");
  248. child.setTotalPoints(0);
  249. child.setStreakDays(0);
  250. child.setFocusMaxDaily(3);
  251. child.setFocusRemaining(3);
  252. child.setFocusResetDate(new Date());
  253. child.setCreatedAt(new Date());
  254. child.setUpdatedAt(new Date());
  255. childMapper.insert(child);
  256. return toChildInfoDTO(child);
  257. }
  258. public List<ChildInfoDTO> getChildren(Long userId) {
  259. User user = userMapper.selectById(userId);
  260. if (user == null) {
  261. return null;
  262. }
  263. List<Child> children = childMapper.selectList(new LambdaQueryWrapper<Child>()
  264. .eq(Child::getFamilyId, user.getFamilyId()));
  265. return children.stream().map(this::toChildInfoDTO).collect(java.util.stream.Collectors.toList());
  266. }
  267. public boolean updateChild(Long childId, UpdateChildDTO dto) {
  268. Child child = childMapper.selectById(childId);
  269. if (child == null) {
  270. return false;
  271. }
  272. if (dto.getNickname() != null) {
  273. child.setNickname(dto.getNickname());
  274. }
  275. if (dto.getAge() != null) {
  276. child.setAge(dto.getAge());
  277. }
  278. if (dto.getDanLevel() != null) {
  279. child.setDanLevel(dto.getDanLevel());
  280. }
  281. if (dto.getPenaltyEnabled() != null) {
  282. child.setPenaltyEnabled(dto.getPenaltyEnabled());
  283. }
  284. if (dto.getTheme() != null) {
  285. child.setTheme(dto.getTheme());
  286. }
  287. child.setUpdatedAt(new Date());
  288. childMapper.updateById(child);
  289. return true;
  290. }
  291. private String encryptPassword(String password) {
  292. return DigestUtils.md5DigestAsHex(("xzyj_salt_" + password).getBytes(StandardCharsets.UTF_8));
  293. }
  294. private String generateInviteCode() {
  295. return UUID.randomUUID().toString().substring(0, 8).toUpperCase();
  296. }
  297. private ChildInfoDTO toChildInfoDTO(Child child) {
  298. ChildInfoDTO dto = new ChildInfoDTO();
  299. dto.setId(child.getId());
  300. dto.setNickname(child.getNickname());
  301. dto.setAge(child.getAge());
  302. dto.setBirthday(child.getBirthday());
  303. dto.setGender(child.getGender());
  304. dto.setDanLevel(child.getDanLevel());
  305. dto.setPenaltyEnabled(child.getPenaltyEnabled());
  306. dto.setTheme(child.getTheme());
  307. dto.setTotalPoints(child.getTotalPoints());
  308. dto.setStreakDays(child.getStreakDays());
  309. dto.setFocusRemaining(child.getFocusRemaining());
  310. return dto;
  311. }
  312. /**
  313. * 更新用户信息
  314. */
  315. public boolean updateUserInfo(Long userId, UpdateUserDTO dto) {
  316. User user = userMapper.selectById(userId);
  317. if (user == null) {
  318. return false;
  319. }
  320. if (dto.getNickname() != null) {
  321. user.setNickname(dto.getNickname());
  322. }
  323. if (dto.getAvatar() != null) {
  324. user.setAvatar(dto.getAvatar());
  325. }
  326. if (dto.getRealName() != null) {
  327. user.setRealName(dto.getRealName());
  328. }
  329. user.setUpdatedAt(new Date());
  330. userMapper.updateById(user);
  331. return true;
  332. }
  333. /**
  334. * 通过邀请码加入家庭
  335. */
  336. public boolean joinFamily(Long userId, String inviteCode) {
  337. if (inviteCode == null || inviteCode.isEmpty()) {
  338. throw new RuntimeException("邀请码不能为空");
  339. }
  340. // 查找家庭
  341. Family family = familyMapper.selectOne(new LambdaQueryWrapper<Family>()
  342. .eq(Family::getInviteCode, inviteCode));
  343. if (family == null) {
  344. throw new RuntimeException("邀请码无效");
  345. }
  346. // 更新用户的家庭ID
  347. User user = userMapper.selectById(userId);
  348. if (user == null) {
  349. throw new RuntimeException("用户不存在");
  350. }
  351. user.setFamilyId(family.getId());
  352. user.setUpdatedAt(new Date());
  353. userMapper.updateById(user);
  354. return true;
  355. }
  356. /**
  357. * 为用户创建新家庭
  358. */
  359. public Long createFamilyForUser(Long userId, String familyName) {
  360. User user = userMapper.selectById(userId);
  361. if (user == null) {
  362. throw new RuntimeException("用户不存在");
  363. }
  364. // 创建新家庭
  365. Family family = new Family();
  366. family.setName(familyName);
  367. family.setInviteCode(generateInviteCode());
  368. family.setCreatedAt(new Date());
  369. family.setUpdatedAt(new Date());
  370. familyMapper.insert(family);
  371. // 更新用户的家庭ID
  372. user.setFamilyId(family.getId());
  373. user.setUpdatedAt(new Date());
  374. userMapper.updateById(user);
  375. return family.getId();
  376. }
  377. }