Skip to content

Commit

Permalink
feat: 增加删除用户接口,完成用户删除操作流程对接
Browse files Browse the repository at this point in the history
后端:
- 增加删除用户接口
- 渠道解绑dal支持批量处理

前端
- 管理后台预留个人信息入口
- 删除用户操作增加二次确认
- 删除用户后主动关闭抽屉,重新加载列表
  • Loading branch information
jorben committed Jul 15, 2024
1 parent 585211c commit 96bf79d
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 15 deletions.
4 changes: 4 additions & 0 deletions common/errs/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const (
ErrDbSelect = -10901 // 查询异常
ErrParam = -10902 // 参数错误,缺少必要参数
ErrDbUpdate = -10903 // 数据库更新异常
ErrDbDelete = -10904 // 数据库删除异常
ErrLogic = -10905 // 逻辑错误
)

// 定义错误码对应的错误描述
Expand All @@ -34,6 +36,8 @@ var errorMsg = map[int]string{
ErrDbSelect: "查询失败,请稍后重试",
ErrParam: "缺少必要参数或参数错误",
ErrDbUpdate: "更新失败,请稍后重试",
ErrDbDelete: "删除失败,请稍后重试",
ErrLogic: "逻辑错误",
}

// GetErrorMsg 获取错误码对应的错误描述
Expand Down
36 changes: 28 additions & 8 deletions dal/userdal.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,39 @@ func (u *UserDal) UpdateUser(user *model.User) (int64, error) {
return result.RowsAffected, nil
}

// DeleteUser 删除用户
func (u *UserDal) DeleteUser(user *model.User) (bool, error) {
result := u.db.Model(user).Delete(user)
if result.Error != nil {
return false, result.Error
}
return result.RowsAffected > 0, nil
}

// DeleteUserSource 删除用户登录渠道
func (u *UserDal) DeleteUserSource(info *model.UserSocialInfo) (bool, error) {
now := time.Now()

err := u.db.Transaction(func(tx *gorm.DB) error {
// 更新openid,增加删除时间戳,避免软删除后唯一索引冲突
if err := tx.Model(info).Where("source = ? AND bind_user_id = ?", info.Source, info.BindUserId).
UpdateColumn("open_id", gorm.Expr("CONCAT(open_id, '-', ?)", now)).Error; err != nil {
return err
}
if err := tx.Where("source = ? AND bind_user_id = ?", info.Source, info.BindUserId).
Delete(&model.UserSocialInfo{}).Error; err != nil {
return err
if len(info.Source) > 0 {
// 更新openid,增加删除时间戳,避免软删除后唯一索引冲突
if err := tx.Model(info).Where("source = ? AND bind_user_id = ?", info.Source, info.BindUserId).
UpdateColumn("open_id", gorm.Expr("CONCAT(open_id, '-', ?)", now)).Error; err != nil {
return err
}
if err := tx.Where("source = ? AND bind_user_id = ?", info.Source, info.BindUserId).
Delete(&model.UserSocialInfo{}).Error; err != nil {
return err
}
} else {
if err := tx.Model(info).Where("bind_user_id = ?", info.BindUserId).
UpdateColumn("open_id", gorm.Expr("CONCAT(open_id, '-', ?)", now)).Error; err != nil {
return err
}
if err := tx.Where("bind_user_id = ?", info.BindUserId).
Delete(&model.UserSocialInfo{}).Error; err != nil {
return err
}
}
return nil
})
Expand Down
23 changes: 23 additions & 0 deletions router/api/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,29 @@ func UserStatus(ctx *gin.Context) {

}

// UserDelete 删除用户
func UserDelete(ctx *gin.Context) {
c := context.CustomContext{Context: ctx}
param := &struct {
Id uint `json:"id"`
}{}
if err := ctx.ShouldBindBodyWithJSON(param); err != nil {
c.CJSON(errs.ErrParam, "用户id值不符合要求")
return
}
strId := ctx.Value("UserId").(string)
if strId == strconv.Itoa(int(param.Id)) {
c.CJSON(errs.ErrLogic, "该用户为当前账号,无法删除自己")
return
}
userService := service.NewUserService(ctx)
if _, err := userService.DeleteUser(param.Id); err != nil {
c.CJSON(errs.ErrDbDelete, err.Error())
return
}
c.CJSON(errs.Success)
}

// UserList 获取用户列表
func UserList(ctx *gin.Context) {
c := context.CustomContext{Context: ctx}
Expand Down
1 change: 1 addition & 0 deletions router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func SetupRouter(s *gin.Engine, feEmbed embed.FS) {
backendAdmin.GET("/user/detail", api.UserDetail)
backendAdmin.POST("/user/status", api.UserStatus)
backendAdmin.POST("/user/source", api.UserUnbind)
backendAdmin.POST("/user/delete", api.UserDelete)

s.Use(gzip.Gzip(gzip.DefaultCompression)).StaticFS("/static", getFileSystem(feEmbed, "web/build/static"))
s.NoRoute(func(ctx *gin.Context) {
Expand Down
17 changes: 17 additions & 0 deletions service/userservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ func NewUserService(ctx *gin.Context) *UserService {
}
}

func (u *UserService) DeleteUser(id uint) (bool, error) {
// 解绑所有该用户的登录渠道
if _, err := u.UnbindUserSource(id, ""); err != nil {
return false, err
}
// 删除用户主表记录
result, err := u.UserDal.DeleteUser(&model.User{
Model: gorm.Model{ID: id},
})
if err != nil {
log.Errorf(u.Ctx, "Delete user failed, err: %s", err.Error())
return false, err
}
log.Debugf(u.Ctx, "Delete user id: %d, result: %v", id, result)
return result, nil
}

// UnbindUserSource 解绑用户登录渠道
func (u *UserService) UnbindUserSource(id uint, source string) (bool, error) {
info := &model.UserSocialInfo{
Expand Down
4 changes: 4 additions & 0 deletions web/src/pages/admin/layout/AdminHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
MenuFoldOutlined,
MenuUnfoldOutlined,
LogoutOutlined,
IdcardOutlined,
} from "@ant-design/icons";
import {
Button,
Expand Down Expand Up @@ -30,6 +31,9 @@ const AdminHeader = ({ collapsed, setCollapsed }) => {

const menus = (
<Space direction="vertical">
<Button type="text" icon={<IdcardOutlined />}>
个人信息
</Button>
<Button
type="text"
icon={<LogoutOutlined />}
Expand Down
39 changes: 33 additions & 6 deletions web/src/pages/admin/user/UserDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Row,
Col,
message,
Popconfirm,
} from "antd";
import {
QuestionCircleOutlined,
Expand All @@ -24,7 +25,7 @@ import BrandIcon from "../../../components/BrandIcon";
import moment from "moment";
import { useNavigate } from "react-router-dom";

const UserDetail = ({ user }) => {
const UserDetail = ({ user, setOpenDrawer, setSearchParam, searchParam }) => {
const [messageApi, contextHolder] = message.useMessage();
const [reload, setReload] = React.useState(false);
const [userDetail, setUserDetail] = React.useState({
Expand Down Expand Up @@ -77,7 +78,7 @@ const UserDetail = ({ user }) => {
},
];

const unbindSource = (source) => {
const unbindSource = async (source) => {
const data = { id: userDetail?.ID, source: source };
ApiClient.post("/admin/user/source", data)
.then((response) => {
Expand All @@ -94,7 +95,7 @@ const UserDetail = ({ user }) => {
});
};

const updateStatus = (status) => {
const updateStatus = async (status) => {
const data = { id: userDetail?.ID, status: status };
ApiClient.post("/admin/user/status", data)
.then((response) => {
Expand All @@ -111,6 +112,24 @@ const UserDetail = ({ user }) => {
});
};

const deleteUser = async () => {
const data = { id: userDetail?.ID };
ApiClient.post("/admin/user/delete", data)
.then((response) => {
if (response.data?.code === 0) {
messageApi.success("删除用户成功");
setOpenDrawer(false);
setSearchParam({ ...searchParam });
} else {
messageApi.error(response.data?.message);
}
})
.catch((error) => {
console.log(error);
messageApi.error("请求失败,请稍后重试!");
});
};

const formatUserDetail = React.useCallback((user) => {
return {
...user,
Expand Down Expand Up @@ -287,9 +306,17 @@ const UserDetail = ({ user }) => {
</Space>
</Col>
<Col span={12} style={{ textAlign: "right" }}>
<Button type="primary" danger icon={<DeleteOutlined />}>
删除用户
</Button>
<Popconfirm
title="温馨提示"
description="确认删除该用户吗,删除后将无法恢复?"
onConfirm={deleteUser}
okText="确认删除"
cancelText="取消"
>
<Button type="primary" danger icon={<DeleteOutlined />}>
删除用户
</Button>
</Popconfirm>
</Col>
</Row>
{contextHolder}
Expand Down
7 changes: 6 additions & 1 deletion web/src/pages/admin/user/UserList.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,12 @@ const UserList = () => {
setSearchParam({ ...searchParam });
}}
>
<UserDetail user={showUser} />
<UserDetail
user={showUser}
setOpenDrawer={setOpenDrawer}
setSearchParam={setSearchParam}
searchParam={searchParam}
/>
</Drawer>
{contextHolder}
</>
Expand Down

0 comments on commit 96bf79d

Please sign in to comment.