package com.ruoyi.user.controller;
|
|
import java.util.List;
|
import jakarta.servlet.http.HttpServletResponse;
|
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.RequestParam;
|
import org.springframework.web.bind.annotation.RestController;
|
import com.ruoyi.common.core.utils.StringUtils;
|
import com.ruoyi.common.core.utils.poi.ExcelUtil;
|
import com.ruoyi.common.core.web.controller.BaseController;
|
import com.ruoyi.common.core.web.domain.AjaxResult;
|
import com.ruoyi.common.core.web.page.TableDataInfo;
|
import com.ruoyi.common.log.annotation.Log;
|
import com.ruoyi.common.log.enums.BusinessType;
|
import com.ruoyi.common.security.annotation.RequiresPermissions;
|
import com.ruoyi.common.security.utils.SecurityUtils;
|
import com.ruoyi.user.domain.AccountAddress;
|
import com.ruoyi.user.domain.AccountUser;
|
import com.ruoyi.user.service.IAccountUserService;
|
|
/**
|
* 会员用户 信息操作处理
|
*
|
* 网关前缀 /account 由 StripPrefix=1 剥掉,故此处映射为 /user,
|
* 外部实际路径是 /account/user/**。
|
*
|
* @author ruoyi
|
*/
|
@RestController
|
@RequestMapping("/user")
|
public class AccountUserController extends BaseController
|
{
|
@Autowired
|
private IAccountUserService accountUserService;
|
|
/**
|
* 查询会员列表
|
*/
|
@RequiresPermissions("member:user:list")
|
@GetMapping("/list")
|
public TableDataInfo list(AccountUser accountUser)
|
{
|
startPage();
|
List<AccountUser> list = accountUserService.selectAccountUserList(accountUser);
|
return getDataTable(list);
|
}
|
|
/**
|
* 导出会员列表
|
*/
|
@RequiresPermissions("member:user:export")
|
@Log(title = "会员管理", businessType = BusinessType.EXPORT)
|
@PostMapping("/export")
|
public void export(HttpServletResponse response, AccountUser accountUser)
|
{
|
List<AccountUser> list = accountUserService.selectAccountUserList(accountUser);
|
ExcelUtil<AccountUser> util = new ExcelUtil<AccountUser>(AccountUser.class);
|
util.exportExcel(response, list, "会员数据");
|
}
|
|
/**
|
* 获取会员详细信息
|
*/
|
@RequiresPermissions("member:user:query")
|
@GetMapping(value = "/{userId}")
|
public AjaxResult getInfo(@PathVariable Long userId)
|
{
|
return success(accountUserService.selectAccountUserById(userId));
|
}
|
|
/**
|
* 新增会员
|
*/
|
@RequiresPermissions("member:user:add")
|
@Log(title = "会员管理", businessType = BusinessType.INSERT)
|
@PostMapping
|
public AjaxResult add(@Validated @RequestBody AccountUser accountUser)
|
{
|
if (!accountUserService.checkUsernameUnique(accountUser))
|
{
|
return error("新增会员'" + accountUser.getUserName() + "'失败,用户名已存在");
|
}
|
if (!accountUserService.checkPhoneUnique(accountUser))
|
{
|
return error("新增会员'" + accountUser.getUserName() + "'失败,手机号已存在");
|
}
|
if (StringUtils.isEmpty(accountUser.getPassword()))
|
{
|
return error("密码不能为空");
|
}
|
accountUser.setCreateBy(SecurityUtils.getUsername());
|
return toAjax(accountUserService.insertAccountUser(accountUser));
|
}
|
|
/**
|
* 修改会员
|
*/
|
@RequiresPermissions("member:user:edit")
|
@Log(title = "会员管理", businessType = BusinessType.UPDATE)
|
@PutMapping
|
public AjaxResult edit(@Validated @RequestBody AccountUser accountUser)
|
{
|
if (!accountUserService.checkUsernameUnique(accountUser))
|
{
|
return error("修改会员'" + accountUser.getUserName() + "'失败,用户名已存在");
|
}
|
if (!accountUserService.checkPhoneUnique(accountUser))
|
{
|
return error("修改会员'" + accountUser.getUserName() + "'失败,手机号已存在");
|
}
|
accountUser.setUpdateBy(SecurityUtils.getUsername());
|
return toAjax(accountUserService.updateAccountUser(accountUser));
|
}
|
|
/**
|
* 删除会员
|
*/
|
@RequiresPermissions("member:user:remove")
|
@Log(title = "会员管理", businessType = BusinessType.DELETE)
|
@DeleteMapping("/{userIds}")
|
public AjaxResult remove(@PathVariable Long[] userIds)
|
{
|
return toAjax(accountUserService.deleteAccountUserByIds(userIds));
|
}
|
|
/**
|
* 获取会员详情(一次取回详情页各 Tab 的数据)
|
*
|
* 路径用 /detail/{userId} 而非 /{userId}/detail:后者在 Spring 的路径匹配下
|
* 会与 getInfo 的 /{userId} 就 "detail" 这个片段产生歧义。
|
*/
|
@RequiresPermissions("member:user:query")
|
@GetMapping(value = "/detail/{userId}")
|
public AjaxResult getDetail(@PathVariable Long userId)
|
{
|
return success(accountUserService.selectAccountUserDetail(userId));
|
}
|
|
/**
|
* 修改推荐人/供货人关系
|
*
|
* 与 edit 分开的风险点:edit 走 @Validated 全量校验(userName 必填 + 用户名/手机号查重),
|
* 只传关系字段必然 400,故必须有独立入口。
|
*
|
* 只改供货人时 referrerId 也要原样带上:服务层的 updateUserRelation 对它无条件赋值,
|
* 漏传即为「解除推荐关系」。供货人的等级校验在服务层(searchSupplierCandidates 只给合法候选,
|
* 这里再兜一道,绕开页面直接打接口也拦得住)。
|
*/
|
@RequiresPermissions("member:user:edit")
|
@Log(title = "会员管理", businessType = BusinessType.UPDATE)
|
@PutMapping("/relation")
|
public AjaxResult relation(@RequestBody AccountUser accountUser)
|
{
|
Long userId = accountUser.getUserId();
|
if (StringUtils.isNull(userId))
|
{
|
return error("会员ID不能为空");
|
}
|
// 防自环:把自己设成自己的推荐人/供货人会让层级计算陷入死循环
|
if (userId.equals(accountUser.getReferrerId()) || userId.equals(accountUser.getSupplierId()))
|
{
|
return error("推荐人/供货人不能是会员本人");
|
}
|
accountUser.setUpdateBy(SecurityUtils.getUsername());
|
return toAjax(accountUserService.updateAccountUserRelation(accountUser));
|
}
|
|
/**
|
* 搜索可指定为供货人的会员(等级严格高于该会员),供「修改供货人」弹窗的下拉使用
|
*
|
* 路径是字面量 /supplierSearch,与上面的 GET /{userId} 同为单段。Spring 的路径匹配按
|
* 「字面量优先于变量」排序,故不会被 /{userId} 抢走(否则会因 "supplierSearch" 无法转
|
* Long 而报 500)。
|
*
|
* 权限与 relation 一致:能打开这个弹窗的人本来就有 member:user:edit。
|
*/
|
@RequiresPermissions("member:user:edit")
|
@GetMapping("/supplierSearch")
|
public AjaxResult supplierSearch(@RequestParam(required = false) Long userId,
|
@RequestParam(required = false) String keyword)
|
{
|
if (StringUtils.isNull(userId))
|
{
|
return error("会员ID不能为空");
|
}
|
return success(accountUserService.searchSupplierCandidates(userId, keyword));
|
}
|
|
/**
|
* 修改收货地址
|
*
|
* 路径 /address 是字面量,与上面的 DELETE /{userIds} 不会打架:
|
* 后者只能匹配单段路径,/address/{ids} 是两段。
|
*/
|
@RequiresPermissions("member:user:edit")
|
@Log(title = "会员收货地址", businessType = BusinessType.UPDATE)
|
@PutMapping("/address")
|
public AjaxResult editAddress(@RequestBody AccountAddress accountAddress)
|
{
|
if (StringUtils.isNull(accountAddress.getId()))
|
{
|
return error("地址ID不能为空");
|
}
|
// 置默认前服务层要按 userId 清旧默认标记,userId 缺失会误清或报错,故必填
|
if (StringUtils.isNull(accountAddress.getUserId()))
|
{
|
return error("会员ID不能为空");
|
}
|
accountAddress.setUpdateBy(SecurityUtils.getUsername());
|
return toAjax(accountUserService.updateAccountAddress(accountAddress));
|
}
|
|
/**
|
* 删除收货地址
|
*/
|
@RequiresPermissions("member:user:edit")
|
@Log(title = "会员收货地址", businessType = BusinessType.DELETE)
|
@DeleteMapping("/address/{ids}")
|
public AjaxResult removeAddress(@PathVariable Long[] ids)
|
{
|
return toAjax(accountUserService.deleteAccountAddressByIds(ids));
|
}
|
|
/**
|
* 修改账户状态(禁用/启用)
|
*
|
* 只有「正常」与「禁用」能通过本接口互切;注销中/已注销由注销审核流程驱动,
|
* 服务层会拒绝这两态进出此接口。同样不能复用 PUT /user,原因见 relation 的注释。
|
*/
|
@RequiresPermissions("member:user:edit")
|
@Log(title = "会员管理", businessType = BusinessType.UPDATE)
|
@PutMapping("/changeStatus")
|
public AjaxResult changeStatus(@RequestBody AccountUser accountUser)
|
{
|
if (StringUtils.isNull(accountUser.getUserId()))
|
{
|
return error("会员ID不能为空");
|
}
|
if (StringUtils.isEmpty(accountUser.getStatus()))
|
{
|
return error("账户状态不能为空");
|
}
|
accountUser.setUpdateBy(SecurityUtils.getUsername());
|
return toAjax(accountUserService.changeStatus(accountUser));
|
}
|
}
|