feat: ✨ 工作台页面和用户分页列表页面完善
This commit is contained in:
95
src/api/system/user.ts
Normal file
95
src/api/system/user.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
const USER_BASE_URL = "/api/v1/users";
|
||||
|
||||
const UserAPI = {
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @returns 登录用户昵称、头像信息,包括角色和权限
|
||||
*/
|
||||
getUserInfo(): Promise<UserInfo> {
|
||||
return request<UserInfo>({
|
||||
url: `${USER_BASE_URL}/me`,
|
||||
method: "GET",
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取用户分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
*/
|
||||
getPage(queryParams: UserPageQuery) {
|
||||
return request<PageResult<Record<string, any>[]>>({
|
||||
url: `${USER_BASE_URL}/page`,
|
||||
method: "GET",
|
||||
data: queryParams,
|
||||
});
|
||||
},
|
||||
};
|
||||
export default UserAPI;
|
||||
|
||||
/** 登录用户信息 */
|
||||
export interface UserInfo {
|
||||
/** 用户ID */
|
||||
userId?: number;
|
||||
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
|
||||
/** 昵称 */
|
||||
nickname?: string;
|
||||
|
||||
/** 头像URL */
|
||||
avatar?: string;
|
||||
|
||||
/** 角色 */
|
||||
roles: string[];
|
||||
|
||||
/** 权限 */
|
||||
perms: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户分页查询对象
|
||||
*/
|
||||
export interface UserPageQuery extends PageQuery {
|
||||
/** 搜索关键字 */
|
||||
keywords?: string;
|
||||
|
||||
/** 用户状态 */
|
||||
status?: number;
|
||||
|
||||
/** 部门ID */
|
||||
deptId?: number;
|
||||
|
||||
/** 开始时间 */
|
||||
createTime?: [string, string];
|
||||
}
|
||||
|
||||
/** 用户分页对象 */
|
||||
export interface UserPageVO {
|
||||
/** 用户头像URL */
|
||||
avatar?: string;
|
||||
/** 创建时间 */
|
||||
createTime?: Date;
|
||||
/** 部门名称 */
|
||||
deptName?: string;
|
||||
/** 用户邮箱 */
|
||||
email?: string;
|
||||
/** 性别 */
|
||||
gender?: number;
|
||||
/** 用户ID */
|
||||
id?: number;
|
||||
/** 手机号 */
|
||||
mobile?: string;
|
||||
/** 用户昵称 */
|
||||
nickname?: string;
|
||||
/** 角色名称,多个使用英文逗号(,)分割 */
|
||||
roleNames?: string;
|
||||
/** 用户状态(1:启用;0:禁用) */
|
||||
status?: number;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
const USER_BASE_URL = "/api/v1/users";
|
||||
|
||||
const UserAPI = {
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @returns 登录用户昵称、头像信息,包括角色和权限
|
||||
*/
|
||||
getUserInfo(): Promise<UserInfo> {
|
||||
return request<UserInfo>({
|
||||
url: `${USER_BASE_URL}/me`,
|
||||
method: "GET",
|
||||
});
|
||||
},
|
||||
};
|
||||
export default UserAPI;
|
||||
|
||||
/** 登录用户信息 */
|
||||
export interface UserInfo {
|
||||
/** 用户ID */
|
||||
userId?: number;
|
||||
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
|
||||
/** 昵称 */
|
||||
nickname?: string;
|
||||
|
||||
/** 头像URL */
|
||||
avatar?: string;
|
||||
|
||||
/** 角色 */
|
||||
roles: string[];
|
||||
|
||||
/** 权限 */
|
||||
perms: string[];
|
||||
}
|
||||
@@ -36,6 +36,18 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人资料"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/user/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用户管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/work/user/edit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑用户"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
|
||||
@@ -47,23 +47,29 @@ const userStore = useUserStore();
|
||||
|
||||
// 登录处理
|
||||
const handleLogin = () => {
|
||||
loginFormRef.value
|
||||
.validate()
|
||||
.then(async ({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
try {
|
||||
userStore.login(loginFormData.value).then(() => {
|
||||
uni.showToast({ title: "登录成功", icon: "success" });
|
||||
uni.navigateBack();
|
||||
loginFormRef.value.validate().then(async ({ valid }: { valid: boolean }) => {
|
||||
if (valid) {
|
||||
try {
|
||||
await userStore.login(loginFormData.value); // 等待登录和获取用户信息完成
|
||||
await userStore.getInfo(); // 等待用户信息获取完成
|
||||
uni.showToast({ title: "登录成功", icon: "success" });
|
||||
const pages = getCurrentPages(); // 获取当前的页面栈
|
||||
|
||||
console.log("pages", pages);
|
||||
if (pages.length > 1) {
|
||||
// 如果页面栈中有多个页面,则可以返回上一页
|
||||
uni.navigateBack();
|
||||
} else {
|
||||
// 如果页面栈中只有一个页面(通常是首页),则可以跳转到指定页面,避免 navigateBack 无法返回的问题
|
||||
uni.reLaunch({
|
||||
url: "/pages/index/index", // 替换为你想要跳转的页面路径
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.log("登录失败", error.message);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log("登录失败", error.message);
|
||||
}
|
||||
})
|
||||
.error(({ errors }: { errors: any }) => {
|
||||
console.log("errors", errors);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,99 +1,87 @@
|
||||
<template>
|
||||
<view class="work">
|
||||
<!-- 系统管理区域 -->
|
||||
<wd-card title="系统管理">
|
||||
<wd-grid :column="4">
|
||||
<wd-grid-item v-for="(item, index) in systemManagementList" :key="index" use-slot>
|
||||
<view class="p-2">
|
||||
<image class="slot-img" :src="item.icon" />
|
||||
</view>
|
||||
<view class="text">{{ item.text }}</view>
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
</wd-card>
|
||||
|
||||
<!-- 系统监控区域 -->
|
||||
<wd-card title="系统监控">
|
||||
<wd-grid :column="4">
|
||||
<wd-grid-item v-for="(item, index) in systemMonitoringList" :key="index" use-slot>
|
||||
<view class="p-2">
|
||||
<image class="slot-img" :src="item.icon" />
|
||||
</view>
|
||||
<view class="text">{{ item.text }}</view>
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
</wd-card>
|
||||
<template v-for="item in gridList">
|
||||
<wd-card :title="item.title">
|
||||
<wd-grid clickable :column="4">
|
||||
<wd-grid-item
|
||||
v-for="(child, index) in item.children"
|
||||
:key="index"
|
||||
use-slot
|
||||
link-type="navigateTo"
|
||||
:url="child.url"
|
||||
>
|
||||
<view class="p-2">
|
||||
<image class="w-80rpx h-80rpx rounded-8rpx" :src="child.icon" />
|
||||
</view>
|
||||
<view class="text">{{ child.title }}</view>
|
||||
</wd-grid-item>
|
||||
</wd-grid>
|
||||
</wd-card>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from "vue";
|
||||
const gridList = reactive([
|
||||
{
|
||||
title: "系统管理",
|
||||
children: [
|
||||
{
|
||||
icon: "/static/icons/user.png",
|
||||
title: "用户管理",
|
||||
url: "/pages/work/user/index",
|
||||
},
|
||||
|
||||
// 系统管理的宫格列表
|
||||
const systemManagementList = reactive([
|
||||
{
|
||||
icon: "/static/icons/user.png",
|
||||
text: "用户管理",
|
||||
title: "用户管理系统",
|
||||
{
|
||||
icon: "/static/icons/role.png",
|
||||
title: "角色管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/menu.png",
|
||||
title: "菜单管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dept.png",
|
||||
title: "部门管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dict.png",
|
||||
title: "字典管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/config.png",
|
||||
title: "系统配置",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/notice.png",
|
||||
title: "通知公告",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/more.png",
|
||||
title: "更多模块",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/role.png",
|
||||
text: "角色管理",
|
||||
title: "角色管理系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/menu.png",
|
||||
text: "菜单管理",
|
||||
title: "菜单管理系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dept.png",
|
||||
text: "部门管理",
|
||||
title: "部门管理系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/dict.png",
|
||||
text: "字典管理",
|
||||
title: "字典管理系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/config.png",
|
||||
text: "系统配置",
|
||||
title: "系统配置管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/notice.png",
|
||||
text: "通知公告",
|
||||
title: "通知公告管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/more.png",
|
||||
text: "更多模块",
|
||||
title: "更多模块管理",
|
||||
},
|
||||
]);
|
||||
|
||||
// 系统监控的宫格列表
|
||||
const systemMonitoringList = reactive([
|
||||
{
|
||||
icon: "/static/icons/monitor.png",
|
||||
text: "实时监控",
|
||||
title: "实时监控系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/logs.png",
|
||||
text: "日志管理",
|
||||
title: "系统日志管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/performance.png",
|
||||
text: "性能监控",
|
||||
title: "性能监控系统",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/alerts.png",
|
||||
text: "警报设置",
|
||||
title: "警报设置系统",
|
||||
title: "系统监控",
|
||||
children: [
|
||||
{
|
||||
icon: "/static/icons/monitor.png",
|
||||
title: "实时监控",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/log.png",
|
||||
title: "日志管理",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/performance.png",
|
||||
title: "性能监控",
|
||||
},
|
||||
{
|
||||
icon: "/static/icons/more.png",
|
||||
title: "更多模块",
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
@@ -106,12 +94,6 @@ page {
|
||||
/* stylelint-enable selector-type-no-unknown */
|
||||
|
||||
.work {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.slot-img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
13
src/pages/work/user/edit.vue
Normal file
13
src/pages/work/user/edit.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<view> 编辑用户,ID:{{ id }} </view>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
// uniapp 获取url参数 id 不使用vue-router
|
||||
|
||||
const pages = getCurrentPages();
|
||||
const currentPage = pages[pages.length - 1];
|
||||
const options = (currentPage as any).options;
|
||||
const id = ref(options.id);
|
||||
console.log("ID:", id);
|
||||
</script>
|
||||
@@ -1,9 +1,97 @@
|
||||
<template>
|
||||
<view class="user">
|
||||
<text class="text-cyan font-bold text-lg">用户</text>
|
||||
<wd-table :data="dataList" @sort-method="handleSort">
|
||||
<wd-table-col prop="username" label="用户名" :fixed="true" width="150rpx" :sortable="true" />
|
||||
<wd-table-col prop="nickname" label="昵称" />
|
||||
<wd-table-col prop="" label="性别" width="120rpx">
|
||||
<template #value="{ row }">
|
||||
<wd-tag v-if="row.gender == 1" type="primary" mark plain>男</wd-tag>
|
||||
<wd-tag v-else-if="row.gender == 2" type="danger" mark plain>女</wd-tag>
|
||||
<wd-tag v-else mark plain>未知</wd-tag>
|
||||
</template>
|
||||
</wd-table-col>
|
||||
<wd-table-col prop="deptName" label="部门" />
|
||||
<wd-table-col prop="mobile" width="220rpx" label="手机号码" />
|
||||
<wd-table-col prop="" label="状态" width="120rpx">
|
||||
<template #value="{ row }">
|
||||
<wd-tag v-if="row.status == 1" type="success" mark plain>正常</wd-tag>
|
||||
<wd-tag v-else type="danger" mark plain>停用</wd-tag>
|
||||
</template>
|
||||
</wd-table-col>
|
||||
<wd-table-col prop="createTime" label="创建时间" />
|
||||
<wd-table-col prop="" :fixed="true" label="操作">
|
||||
<template #value="{ row }">
|
||||
<wd-text type="primary" class="cursor-pointer" text="编辑" @click="handleEdit(row)" />
|
||||
<wd-text
|
||||
type="error"
|
||||
class="ml-2 cursor-pointer"
|
||||
text="删除"
|
||||
@click="handleDelete(row)"
|
||||
/>
|
||||
</template>
|
||||
</wd-table-col>
|
||||
</wd-table>
|
||||
|
||||
<wd-loadmore :state="state" @reload="loadmore" />
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup></script>
|
||||
<script lang="ts" setup>
|
||||
import { LoadMoreState } from "wot-design-uni/components/wd-loadmore/types";
|
||||
import UserAPI, { type UserPageQuery, UserPageVO } from "@/api/system/user";
|
||||
|
||||
const state = ref<LoadMoreState>("loading"); // 加载状态 loading, finished:, error
|
||||
const dataList = ref<Record<string, any>[]>([]);
|
||||
|
||||
const queryParams: UserPageQuery = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
|
||||
const total = ref(0); // 总数
|
||||
|
||||
onReachBottom(() => {
|
||||
if (queryParams.pageNum * queryParams.pageSize < total.value) {
|
||||
loadmore();
|
||||
} else if (queryParams.pageNum * queryParams.pageSize >= total.value) {
|
||||
state.value = "finished";
|
||||
}
|
||||
});
|
||||
|
||||
function loadmore() {
|
||||
state.value = "loading";
|
||||
UserAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
dataList.value = data.list;
|
||||
total.value = data.total;
|
||||
queryParams.pageNum++;
|
||||
})
|
||||
.finally(() => {
|
||||
state.value = "finished";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
function handleSort() {
|
||||
dataList.value = dataList.value?.reverse();
|
||||
}
|
||||
|
||||
function handleEdit(row: UserPageVO) {
|
||||
console.log("编辑", row);
|
||||
uni.navigateTo({
|
||||
url: `/pages/work/user/edit?id=${row.id}`,
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(row: UserPageVO) {
|
||||
console.log("删除", row);
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
loadmore();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* stylelint-disable selector-type-no-unknown */
|
||||
@@ -11,4 +99,12 @@ page {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
/* stylelint-enable selector-type-no-unknown */
|
||||
|
||||
.custom-class {
|
||||
display: flex;
|
||||
flex-direction: col;
|
||||
align-items: center;
|
||||
width: 220rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
BIN
src/static/icons/log.png
Normal file
BIN
src/static/icons/log.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
BIN
src/static/icons/monitor.png
Normal file
BIN
src/static/icons/monitor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 4.7 KiB |
BIN
src/static/icons/performance.png
Normal file
BIN
src/static/icons/performance.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
@@ -1,6 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import AuthAPI, { type LoginFormData } from "@/api/auth";
|
||||
import UserAPI, { type UserInfo } from "@/api/user";
|
||||
import UserAPI, { type UserInfo } from "@/api/system/user";
|
||||
import { setToken, getUserInfo, setUserInfo, clearAll } from "@/utils/cache";
|
||||
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
@@ -12,21 +12,28 @@ export const useUserStore = defineStore("user", () => {
|
||||
AuthAPI.login(data)
|
||||
.then((data) => {
|
||||
setToken(data.accessToken);
|
||||
getInfo();
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("登录失败", error);
|
||||
reject(error); // 将错误抛出
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 获取用户信息
|
||||
const getInfo = () => {
|
||||
UserAPI.getUserInfo().then((data) => {
|
||||
setUserInfo(data);
|
||||
userInfo.value = data;
|
||||
return new Promise((resolve, reject) => {
|
||||
UserAPI.getUserInfo()
|
||||
.then((data) => {
|
||||
setUserInfo(data);
|
||||
userInfo.value = data;
|
||||
resolve(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("获取用户信息失败", error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -46,6 +53,6 @@ export const useUserStore = defineStore("user", () => {
|
||||
userInfo,
|
||||
login,
|
||||
logout,
|
||||
getUserInfo,
|
||||
getInfo,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getToken } from "@/utils/cache";
|
||||
import { getToken, clearAll } from "@/utils/cache";
|
||||
import { ResultCodeEnum } from "@/enums/ResultCodeEnum";
|
||||
|
||||
export default function request<T>(options: UniApp.RequestOptions): Promise<T> {
|
||||
@@ -26,21 +26,14 @@ export default function request<T>(options: UniApp.RequestOptions): Promise<T> {
|
||||
}
|
||||
// 令牌失效或过期处理
|
||||
else if (resData.code === ResultCodeEnum.TOKEN_INVALID) {
|
||||
uni.showToast({
|
||||
title: resData.msg || "令牌无效或过期",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
console.log("令牌失效或过期处理");
|
||||
clearAll();
|
||||
// 跳转到登录页
|
||||
uni.reLaunch({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
|
||||
// 此处不强制跳转到登录页,可以让调用方决定下一步操作
|
||||
reject({
|
||||
message: resData.msg || "令牌无效或过期",
|
||||
code: resData.code,
|
||||
action: "TOKEN_INVALID", // 提供一个 action 用于后续调用方判断
|
||||
});
|
||||
}
|
||||
// 其他业务处理失败
|
||||
else {
|
||||
} else {
|
||||
// 其他业务处理失败
|
||||
uni.showToast({
|
||||
title: resData.msg || "业务处理失败",
|
||||
icon: "none",
|
||||
|
||||
Reference in New Issue
Block a user