zjk
8 小时以前 a4afcfdb179e62a498b62cc6860d8cd46701a08f
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
package com.ruoyi.user.controller;
 
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.user.domain.AccountAddress;
import com.ruoyi.user.domain.dto.AccountAddressDto;
import com.ruoyi.user.domain.dto.AccountCertificationApplyDto;
import com.ruoyi.user.domain.dto.AccountUserAvatarDto;
import com.ruoyi.user.domain.dto.CompanyCertificationApplyDto;
import com.ruoyi.user.domain.vo.AccountAddressVo;
import com.ruoyi.user.domain.vo.AccountCertificationStatusVo;
import com.ruoyi.user.domain.vo.AccountInviteeVo;
import com.ruoyi.user.domain.vo.AccountReferrerVo;
import com.ruoyi.user.domain.vo.AccountUserInfoVo;
import com.ruoyi.user.domain.vo.CompanyCertificationStatusVo;
import com.ruoyi.user.domain.vo.InviteCodeVo;
import com.ruoyi.user.service.IAccountCertificationApplyService;
import com.ruoyi.user.service.IAccountUserService;
 
/**
 * C端会员 个人中心接口
 *
 * 网关前缀 /miniapp/account 由 StripPrefix=2 剥掉,故此处映射为 /user,
 * 外部实际路径为 /miniapp/account/user/**。
 *
 * 会员身份取自网关注入的登录态(SecurityUtils.getUserId),不接受前端传 userId,
 * 天然防止水平越权;未登录请求由网关直接以 401 拦截,故此处不处理未登录分支。
 *
 * @author hugray
 */
@RestController
@RequestMapping("/user")
public class AccountProfileController extends BaseController
{
    @Autowired
    private IAccountUserService accountUserService;
 
    @Autowired
    private IAccountCertificationApplyService accountCertificationApplyService;
 
    /**
     * 查询当前登录会员的个人中心信息
     *
     * 返回昵称、头像、会员等级与收益汇总(今日 / 本月 / 累计,单位分)。
     *
     * @return 会员信息展示对象
     */
    @GetMapping("/info")
    public R<AccountUserInfoVo> info()
    {
        return R.ok(accountUserService.getAccountUserInfo(SecurityUtils.getUserId()));
    }
 
    /**
     * 更新当前登录会员头像
     *
     * 头像文件由小程序直传文件服务(POST /file/upload)后,将返回的 url 通过本接口写回;
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @param dto 头像更新入参(仅含 avatar)
     * @return 操作结果
     */
    @PostMapping("/avatar")
    public R<Void> updateAvatar(@Validated @RequestBody AccountUserAvatarDto dto)
    {
        accountUserService.updateAvatar(SecurityUtils.getUserId(), dto.getAvatar());
        return R.ok();
    }
 
    /**
     * 查询当前登录会员的实名认证状态
     *
     * 供实名认证页进入时回填:姓名、身份证号、审核状态(0待审核/1已通过/2已驳回)与驳回原因。
     * 从未提交过申请时返回各字段为空的对象,前端按「未认证」渲染空表单。
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 认证状态(realName / idCard / auditStatus / auditRemark)
     */
    @GetMapping("/certification")
    public R<AccountCertificationStatusVo> certification()
    {
        return R.ok(accountCertificationApplyService.getCertificationStatus(SecurityUtils.getUserId()));
    }
 
    /**
     * 提交实名认证(个人主体)
     *
     * 只做基础的姓名必填与身份证号格式校验(@Validated 拦下非法入参),不做三方实名核验;
     * 提交后落一条待审核的认证申请,出现在管理后台「主体认证审核」列表。
     * 会员身份取自登录态,不接受前端传入 userId;已有待审核申请时拒绝重复提交。
     *
     * @param dto 认证申请入参(仅含 realName、idCard)
     * @return 操作结果
     */
    @PostMapping("/certification")
    public R<Void> submitCertification(@Validated @RequestBody AccountCertificationApplyDto dto)
    {
        accountCertificationApplyService.submitPersonalCertification(
            SecurityUtils.getUserId(), dto.getRealName(), dto.getIdCard());
        return R.ok();
    }
 
    /**
     * 查询当前登录会员的企业/个体认证状态
     *
     * 供企业认证向导页进入时回填:整份企业资料 + 审核状态(0待审核/1已通过/2已驳回)与驳回原因。
     * 从未提交过申请时返回各字段为空的对象,前端按「未认证」渲染空表单。
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 企业/个体认证状态(整份资料 + auditStatus / auditRemark)
     */
    @GetMapping("/company-certification")
    public R<CompanyCertificationStatusVo> companyCertification()
    {
        return R.ok(accountCertificationApplyService.getCompanyCertificationStatus(SecurityUtils.getUserId()));
    }
 
    /**
     * 提交企业/个体工商户认证(主体类型 2/3)
     *
     * 只做最基础的必填校验(@Validated 拦下空值与非法枚举),不做格式与三方核验,真实性由后台人工审核把关;
     * 提交后落一条待审核的认证申请,出现在管理后台「主体认证审核」列表。
     * 会员身份取自登录态,不接受前端传入 userId;已有待审核的企业申请时拒绝重复提交。
     *
     * @param dto 企业认证申请入参
     * @return 操作结果
     */
    @PostMapping("/company-certification")
    public R<Void> submitCompanyCertification(@Validated @RequestBody CompanyCertificationApplyDto dto)
    {
        accountCertificationApplyService.submitCompanyCertification(SecurityUtils.getUserId(), dto);
        return R.ok();
    }
 
    /**
     * 查询本人邀请码
     *
     * 供「我的邀请」页「邀请码」Tab 展示;会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 邀请码展示对象
     */
    @GetMapping("/invite-code")
    public R<InviteCodeVo> inviteCode()
    {
        return R.ok(accountUserService.getInviteCode(SecurityUtils.getUserId()));
    }
 
    /**
     * 查询本人直接下级(被邀请人)列表
     *
     * 分页返回(pageNum 默认 1、pageSize 默认 10),按绑定时间倒序;
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 分页数据(rows 为 AccountInviteeVo 列表,total 为总数)
     */
    @GetMapping("/invitees")
    public TableDataInfo invitees()
    {
        startPage();
        List<AccountInviteeVo> list = accountUserService.getInvitees(SecurityUtils.getUserId());
        return getDataTable(list);
    }
 
    /**
     * 查询本人上级(推荐人)信息
     *
     * 供「我的邀请」页「邀请我的」Tab 展示;无上级时返回各字段为 null 的对象;
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 上级展示对象
     */
    @GetMapping("/referrer")
    public R<AccountReferrerVo> referrer()
    {
        return R.ok(accountUserService.getReferrer(SecurityUtils.getUserId()));
    }
 
    /**
     * 查询本人收货地址列表
     *
     * 默认地址排前,其余按 id 升序;地址数量少,不分页。
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @return 地址列表(无地址返回空集合)
     */
    @GetMapping("/addresses")
    public R<List<AccountAddressVo>> addressList()
    {
        List<AccountAddress> list = accountUserService.getAddressList(SecurityUtils.getUserId());
        return R.ok(toAddressVoList(list));
    }
 
    /**
     * 查询本人单条收货地址详情
     *
     * 供编辑页回填;校验归属,非本人地址抛业务异常。
     * 会员身份取自登录态,不接受前端传入 userId。
     *
     * @param id 地址ID
     * @return 地址详情
     */
    @GetMapping("/addresses/{id}")
    public R<AccountAddressVo> addressDetail(@PathVariable("id") Long id)
    {
        AccountAddress address = accountUserService.getAddressDetail(SecurityUtils.getUserId(), id);
        return R.ok(toAddressVo(address));
    }
 
    /**
     * 新增本人收货地址
     *
     * 首条地址自动设为默认;会员身份取自登录态,不接受前端传入 userId。
     *
     * @param dto 地址入参
     * @return 操作结果
     */
    @PostMapping("/addresses")
    public R<Void> createAddress(@Validated @RequestBody AccountAddressDto dto)
    {
        accountUserService.insertMyAddress(buildAddress(dto, SecurityUtils.getUserId()));
        return R.ok();
    }
 
    /**
     * 编辑本人收货地址
     *
     * 复用后台改地址事务逻辑(含默认唯一约束);会员身份取自登录态。
     *
     * @param dto 地址入参(必含 id)
     * @return 操作结果
     */
    @PutMapping("/addresses")
    public R<Void> updateAddress(@Validated @RequestBody AccountAddressDto dto)
    {
        if (dto.getId() == null)
        {
            throw new ServiceException("地址ID不能为空");
        }
        accountUserService.updateAccountAddress(buildAddress(dto, SecurityUtils.getUserId()));
        return R.ok();
    }
 
    /**
     * 删除本人收货地址
     *
     * 校验归属后逻辑删除;会员身份取自登录态,不接受前端传入 userId。
     *
     * @param id 地址ID
     * @return 操作结果
     */
    @DeleteMapping("/addresses/{id}")
    public R<Void> deleteAddress(@PathVariable("id") Long id)
    {
        accountUserService.deleteMyAddress(SecurityUtils.getUserId(), id);
        return R.ok();
    }
 
    /**
     * DTO 转实体(userId 由登录态注入,不接受前端传值)
     */
    private AccountAddress buildAddress(AccountAddressDto dto, Long userId)
    {
        AccountAddress address = new AccountAddress();
        address.setId(dto.getId());
        address.setUserId(userId);
        address.setConsignee(dto.getConsignee());
        address.setConsigneePhone(dto.getConsigneePhone());
        address.setAddress(dto.getAddress());
        address.setIsDefault(dto.getIsDefault());
        return address;
    }
 
    /**
     * 实体转出参 VO(列表)
     */
    private List<AccountAddressVo> toAddressVoList(List<AccountAddress> list)
    {
        List<AccountAddressVo> voList = new ArrayList<>(list.size());
        for (AccountAddress address : list)
        {
            voList.add(toAddressVo(address));
        }
        return voList;
    }
 
    /**
     * 实体转出参 VO(单条)
     */
    private AccountAddressVo toAddressVo(AccountAddress address)
    {
        AccountAddressVo vo = new AccountAddressVo();
        vo.setId(address.getId());
        vo.setConsignee(address.getConsignee());
        vo.setConsigneePhone(address.getConsigneePhone());
        vo.setAddress(address.getAddress());
        vo.setIsDefault(address.getIsDefault());
        return vo;
    }
}