feat(用户管理): 添加角色管理和筛选功能

在用户管理模块中新增角色管理和筛选功能,包括:
1. 在用户查询和更新接口中添加 `roleId` 和 `sysRoleId` 字段
2. 在用户详情页添加角色修改功能
3. 在用户列表页添加角色筛选选项卡
This commit is contained in:
dzq 2025-05-21 10:33:58 +08:00
parent 53efdc88b7
commit ba7b027c7b
4 changed files with 141 additions and 20 deletions

View File

@ -67,6 +67,8 @@ export interface QyUserQuery extends BasePageQuery {
mobile?: string;
corpid?: string;
mainDepartment?: number;
roleId?: number;
sysRoleId?: number;
}
export interface AddQyUserCommand {
@ -77,6 +79,7 @@ export interface AddQyUserCommand {
/** 用户余额 */
balance?: number;
roleId?: number;
sysRoleId?: number;
}
export interface UpdateQyUserCommand extends AddQyUserCommand {

View File

@ -1,9 +1,10 @@
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { type QyUserDTO, getQyUserDetailApi } from "@/api/qy/qyUser";
import { type QyUserDTO, getQyUserDetailApi, updateQyUserApi } from "@/api/qy/qyUser";
import { getOrderListApi, type OrderDTO } from "@/api/shop/order";
import BalanceEditModal from "./BalanceEditModal.vue";
import { getRoleListApi, RoleDTO } from "@/api/system/role";
defineOptions({
name: "QyUserDetail"
@ -15,6 +16,9 @@ const userInfo = ref<QyUserDTO>({});
const loading = ref(false);
const balanceVisible = ref(false);
const currentBalance = ref(0);
const roleVisible = ref(false);
const roleList = ref<RoleDTO[]>([]);
const selectedRoleId = ref<number>();
//
const basicInfo = ref({
@ -56,6 +60,32 @@ watch(activeTab, (newVal) => {
}
});
async function handleModifyRole() {
try {
const { data } = await getRoleListApi({});
roleList.value = data.rows;
selectedRoleId.value = userInfo.value.roleId;
roleVisible.value = true;
} catch (error) {
console.error(error);
}
}
async function handleRoleConfirm() {
try {
await updateQyUserApi(userInfo.value.id!, {
...userInfo.value,
id: userInfo.value.id,
roleId: selectedRoleId.value,
sysRoleId: selectedRoleId.value
});
roleVisible.value = false;
await fetchUserDetail();
} catch (error) {
console.error(error);
}
}
async function fetchUserDetail() {
try {
loading.value = true;
@ -111,6 +141,8 @@ async function handleModifyBalance(row: QyUserDTO) {
</div>
<el-descriptions class="info-details" v-if="activeTab === 'basic'" :column="2" border>
<el-descriptions-item label="角色">{{ userInfo.roleName }} <el-button type="primary" size="small"
@click="handleModifyRole">修改</el-button></el-descriptions-item>
<el-descriptions-item label="用户ID">{{ userInfo.userid }}</el-descriptions-item>
<el-descriptions-item label="企业ID">{{ userInfo.corpid }}</el-descriptions-item>
<el-descriptions-item label="职务信息">{{ userInfo.position }}</el-descriptions-item>
@ -143,6 +175,15 @@ async function handleModifyBalance(row: QyUserDTO) {
</el-card>
</div>
<BalanceEditModal v-model:visible="balanceVisible" :row="userInfo" @refresh="fetchUserDetail" />
<el-drawer v-model="roleVisible" title="修改角色" direction="rtl" size="30%">
<el-select v-model="selectedRoleId" placeholder="请选择角色" style="width: 100%; margin: 20px 0">
<el-option v-for="item in roleList" :key="item.roleId" :label="item.roleName" :value="item.roleId" />
</el-select>
<div style="padding: 20px; text-align: right">
<el-button @click="roleVisible = false">取消</el-button>
<el-button type="primary" @click="handleRoleConfirm">确定</el-button>
</div>
</el-drawer>
</div>
</template>

View File

@ -31,6 +31,7 @@ export function useHook() {
mobile: undefined,
corpid: wxStore.corpid, // 企业ID
mainDepartment: undefined, // 主部门
sysRoleId: undefined // 角色ID
});
const timeRange = ref<[string, string]>(); // 时间范围选择
@ -163,6 +164,7 @@ export function useHook() {
handleViewDetail,
handleModifyBalance,
balanceVisible,
selectedUser
selectedUser,
roleOptions
};
}

View File

@ -25,9 +25,15 @@ const {
handleViewDetail,
handleModifyBalance,
balanceVisible,
selectedUser
selectedUser,
roleOptions,
} = useHook();
const handleTabChange = (roleId) => {
searchFormParams.sysRoleId = roleId;
onSearch();
};
watch(
() => searchFormParams.mainDepartment,
() => {
@ -41,6 +47,7 @@ watch(
<tree class="w-[17%] float-left" v-model="searchFormParams.mainDepartment" />
<div class="float-right w-[82%]">
<BalanceEditModal v-model:visible="balanceVisible" :row="selectedUser" @refresh="getList" />
<div class="search-form-container">
<el-form ref="formRef" :inline="true" :model="searchFormParams"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]">
<el-form-item label="姓名:" prop="name">
@ -56,6 +63,18 @@ watch(
</el-form-item>
</el-form>
<div class="custom-tabs">
<button class="tab-btn" :class="{ 'active': searchFormParams.sysRoleId === undefined }"
@click="handleTabChange(undefined)">
全部
</button>
<button v-for="role in roleOptions" :key="role.roleId" class="tab-btn"
:class="{ 'active': searchFormParams.sysRoleId === role.roleId }" @click="handleTabChange(role.roleId)">
{{ role.roleName }}
</button>
</div>
</div>
<div class="grid-container">
<el-row :gutter="12">
<el-col v-for="(item, index) in dataList" :key="index" :xs="24" :sm="12" :md="8" :lg="6">
@ -101,10 +120,66 @@ watch(
margin: 0;
}
.search-form {
.search-form-container {
.search-form {
:deep(.el-form-item) {
margin-bottom: 12px;
}
}
.custom-tabs {
padding: 0 20px;
background: var(--el-bg-color);
border-radius: 4px;
display: flex;
gap: 12px;
.tab-btn {
padding: 4px 10px;
border: none;
background: transparent;
cursor: pointer;
color: var(--el-text-color-regular);
position: relative;
border-radius: 4px 4px 0 0;
font-size: 14px;
transition: color 0.2s ease;
&.active {
color: var(--el-color-primary);
background-color: #f0f2f5;
border-bottom: none;
z-index: 1;
&::before,
&::after {
content: '';
position: absolute;
bottom: -6px;
width: 18px;
height: 18px;
background: transparent;
}
&::before {
left: -18px;
border-bottom-right-radius: 18px;
box-shadow: 9px 0 0 0 #f0f2f5;
}
&::after {
right: -18px;
border-bottom-left-radius: 18px;
box-shadow: -9px 0 0 0 #f0f2f5;
}
}
&:hover {
color: var(--el-color-primary);
text-shadow: 0 0 1px rgba(64, 158, 255, 0.3);
}
}
}
}
.user-card {