“mitao”
2026-05-12 4f367056ab0e73d044e920d44b1d7dd0c8b65d80
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.tcm.training.admin.app.register.controller;
 
import com.tcm.training.admin.app.auth.dto.AppSmsCodeSendRequest;
import com.tcm.training.admin.app.auth.vo.AppLoginResponse;
import com.tcm.training.admin.app.auth.vo.AppSmsCodeSendResponse;
import com.tcm.training.admin.app.register.dto.AppRegisterOperatorCompleteRequest;
import com.tcm.training.admin.app.register.dto.AppRegisterOperatorPrepareRequest;
import com.tcm.training.admin.app.register.dto.AppRegisterUserRequest;
import com.tcm.training.admin.app.register.service.AppRegisterService;
import com.tcm.training.admin.app.register.vo.AppRegisterOperatorPrepareResponse;
import com.tcm.training.admin.app.register.vo.AppRegisterRegionDatasetVO;
import com.tcm.training.admin.app.register.vo.AppRegisterRegionOptionVO;
import com.tcm.training.admin.common.ApiResponse;
import com.tcm.training.admin.upload.ObsUploadService;
import com.tcm.training.admin.upload.UploadController;
import com.tcm.training.admin.upload.UploadFileResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import javax.validation.Valid;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
/**
 * APP 注册接口,统一承接用户注册、经营者注册和注册前附件上传。
 */
@Validated
@RestController
@RequestMapping({"/api/app/register", "/api/v1/app/register"})
public class AppRegisterController {
 
    private static final long MAX_SIZE = 5 * 1024 * 1024L;
    private static final Set<String> ALLOWED_TYPES = new HashSet<String>(
            Arrays.asList("image/jpeg", "image/png", "image/gif", "image/webp")
    );
 
    private final AppRegisterService appRegisterService;
    private final ObsUploadService obsUploadService;
 
    /**
     * 注入注册服务与注册阶段附件上传能力。
     */
    public AppRegisterController(AppRegisterService appRegisterService, ObsUploadService obsUploadService) {
        this.appRegisterService = appRegisterService;
        this.obsUploadService = obsUploadService;
    }
 
    /**
     * 发送注册短信验证码。
     */
    @PostMapping("/sms-code")
    public ApiResponse<AppSmsCodeSendResponse> sendSmsCode(@Valid @RequestBody AppSmsCodeSendRequest request) {
        return ApiResponse.ok(appRegisterService.sendRegisterCode(request.getPhone()));
    }
 
    /**
     * 查询 APP 注册三级联动行政区划。
     */
    @GetMapping("/regions")
    public ApiResponse<List<AppRegisterRegionOptionVO>> listRegions(@RequestParam(value = "parentCode", required = false) String parentCode) {
        return ApiResponse.ok(appRegisterService.listRegions(parentCode));
    }
 
    /**
     * 查询 APP 滚轮地区选择器使用的完整数据集。
     */
    @GetMapping("/region-dataset")
    public ApiResponse<AppRegisterRegionDatasetVO> getRegionDataset() {
        return ApiResponse.ok(appRegisterService.getRegionDataset());
    }
 
    /**
     * 提交普通用户注册。
     */
    @PostMapping("/user")
    public ApiResponse<AppLoginResponse> registerUser(@Valid @RequestBody AppRegisterUserRequest request) {
        return ApiResponse.ok(appRegisterService.registerUser(request));
    }
 
    /**
     * 校验经营者第一步并回填海诊通诊所资料。
     */
    @PostMapping("/operator/prepare")
    public ApiResponse<AppRegisterOperatorPrepareResponse> prepareOperator(@Valid @RequestBody AppRegisterOperatorPrepareRequest request) {
        return ApiResponse.ok(appRegisterService.prepareOperatorRegister(request));
    }
 
    /**
     * 提交经营者第二步并创建本地诊所与诊所用户。
     */
    @PostMapping("/operator/complete")
    public ApiResponse<AppLoginResponse> completeOperator(@Valid @RequestBody AppRegisterOperatorCompleteRequest request) {
        return ApiResponse.ok(appRegisterService.completeOperatorRegister(request));
    }
 
    /**
     * 上传经营者注册阶段的营业执照图片。
     */
    @PostMapping("/upload/license")
    public ApiResponse<UploadController.UploadResult> uploadLicense(@RequestParam("file") MultipartFile file) throws IOException {
        validateImage(file);
        UploadFileResult uploadResult = obsUploadService.upload(file, "register/license", null);
        return ApiResponse.ok(new UploadController.UploadResult(uploadResult.getUrl(), uploadResult.getFileName()));
    }
 
    /**
     * 校验营业执照图片的大小与类型。
     */
    private void validateImage(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("请选择要上传的文件");
        }
        if (file.getSize() > MAX_SIZE) {
            throw new IllegalArgumentException("文件大小超出限制");
        }
        String contentType = file.getContentType();
        if (contentType == null || !ALLOWED_TYPES.contains(contentType)) {
            throw new IllegalArgumentException("仅支持 JPG、PNG、GIF、WebP 格式");
        }
    }
}