longz
2026-08-11 2a3c3cdbf2398695d61633e072f98ee2757e9e27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package com.sinata.appointment.controller;
 
import com.sinata.appointment.common.Result;
import com.sinata.appointment.common.ResultUtil;
import com.sinata.appointment.dto.MiniLoginResponse;
import com.sinata.appointment.dto.MiniOfficialBindPhoneRequest;
import com.sinata.appointment.dto.MiniOfficialLoginRequest;
import com.sinata.appointment.dto.MiniOfficialLoginResponse;
import com.sinata.appointment.dto.MiniPhoneLoginRequest;
import com.sinata.appointment.dto.MiniProfileUpdateRequest;
import com.sinata.appointment.dto.MiniWxLoginRequest;
import com.sinata.appointment.entity.MpUser;
import com.sinata.appointment.entity.SysDept;
import com.sinata.appointment.service.MiniAuthApplicationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.HashMap;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.sinata.appointment.mapper.SysDeptMapper;
import com.sinata.appointment.service.LocalImageUploadService;
import org.springframework.web.multipart.MultipartFile;
 
@Tag(name = "小程序认证")
@RestController
@RequestMapping("/api/mini/auth")
@RequiredArgsConstructor
public class MiniAuthController {
 
    private final MiniAuthApplicationService miniAuthApplicationService;
    private final SysDeptMapper sysDeptMapper;
    private final LocalImageUploadService localImageUploadService;
 
    @Operation(
            summary = "微信登录",
            description =
                    "wxCode 必传,先按 openId 直接登录;若 openId 未匹配到用户,再补传 getPhoneNumber 的 phoneCode 完成绑定/登录。")
    @PostMapping("/login")
    public Result<MiniLoginResponse> login(@Valid @RequestBody MiniWxLoginRequest request) {
        return ResultUtil.data(miniAuthApplicationService.loginByWx(request));
    }
 
    @Operation(summary = "临时手机号登录")
    @PostMapping("/phone-login")
    public Result<MiniLoginResponse> phoneLogin(@Valid @RequestBody MiniPhoneLoginRequest request) {
        return ResultUtil.data(miniAuthApplicationService.loginByPhone(request.getMobile()));
    }
 
    @Operation(summary = "公众号静默授权地址")
    @GetMapping("/official-oauth-url")
    public Result<Map<String, String>> officialOAuthUrl(
            @RequestParam("redirectUri") String redirectUri,
            @RequestParam(value = "state", required = false) String state) {
        return ResultUtil.data(
                Map.of("url", miniAuthApplicationService.buildOfficialOAuthUrl(redirectUri, state)));
    }
 
    @Operation(summary = "公众号静默授权登录")
    @PostMapping("/official-login")
    public Result<MiniOfficialLoginResponse> officialLogin(
            @Valid @RequestBody MiniOfficialLoginRequest request) {
        return ResultUtil.data(miniAuthApplicationService.loginByOfficialCode(request.getCode()));
    }
 
    @Operation(summary = "公众号首次登录手机号绑定")
    @PostMapping("/official-bind-phone")
    public Result<MiniLoginResponse> officialBindPhone(
            @Valid @RequestBody MiniOfficialBindPhoneRequest request) {
        return ResultUtil.data(
                miniAuthApplicationService.bindOfficialPhoneAndLogin(
                        request.getBindToken(), request.getMobile()));
    }
 
    @Operation(summary = "当前小程序用户")
    @GetMapping("/me")
    public Result<Map<String, Object>> me() {
        return ResultUtil.data(buildMeResponse(miniAuthApplicationService.currentMpUser()));
    }
 
    @Operation(summary = "更新当前小程序用户资料")
    @PutMapping("/profile")
    public Result<Map<String, Object>> updateProfile(
            @Valid @RequestBody MiniProfileUpdateRequest request) {
        return ResultUtil.data(buildMeResponse(miniAuthApplicationService.updateProfile(request)));
    }
 
    @Operation(summary = "小程序用户图片上传")
    @PostMapping("/upload/image")
    public Result<Map<String, String>> uploadImage(@RequestParam("file") MultipartFile file) {
        return ResultUtil.data(Map.of("url", localImageUploadService.uploadImage(file)));
    }
 
    @Operation(summary = "退出")
    @PostMapping("/logout")
    public Result<Void> logout() {
        miniAuthApplicationService.logout();
        return ResultUtil.success();
    }
 
    @Operation(summary = "解除当前小程序微信绑定")
    @PostMapping("/unbind-openid")
    public Result<Void> unbindOpenId() {
        miniAuthApplicationService.unbindMiniOpenIdAndLogout();
        return ResultUtil.success();
    }
 
    private Map<String, Object> buildMeResponse(MpUser u) {
        Map<String, Object> m = new HashMap<>();
        m.put("mpUserId", u.getId());
        m.put("userType", u.getUserType());
        m.put("deptId", u.getDeptId());
        SysDept dept = u.getDeptId() == null ? null : sysDeptMapper.selectById(u.getDeptId());
        m.put("deptName", dept == null ? null : dept.getDeptName());
        m.put("deptLeaderFlag", false);
        m.put("nickName", u.getNickName());
        m.put("avatarUrl", u.getAvatarUrl());
        m.put("mobile", u.getMobile());
        m.put("gender", u.getGender());
        m.put("companyName", u.getCompanyName());
        return m;
    }
}