feat: 登录和用户接口typescript类型声明

This commit is contained in:
郝先瑞
2022-03-12 00:18:21 +08:00
parent 7d46ff1224
commit 27bbd35057
8 changed files with 415 additions and 393 deletions

View File

@@ -1,10 +1,12 @@
import { LoginRequestParam, LoginResponseData } from "@/types";
import request from "@/utils/request"; import request from "@/utils/request";
import { AxiosPromise } from "axios";
/** /**
* 登录 * 登录
* @param data * @param data
*/ */
export function login(data: object) { export function login(data: LoginRequestParam): AxiosPromise<LoginResponseData> {
return request({ return request({
url: '/youlai-auth/oauth/token', url: '/youlai-auth/oauth/token',
method: 'post', method: 'post',
@@ -15,16 +17,6 @@ export function login(data: object) {
}) })
} }
/**
* 登录成功后获取用户信息(包括用户头像、权限列表等)
*/
export function getUserInfo() {
return request({
url: '/youlai-admin/api/v1/users/me',
method: 'get'
})
}
/** /**
* 注销 * 注销
*/ */
@@ -38,7 +30,7 @@ export function logout() {
/** /**
* 获取图片验证码 * 获取图片验证码
*/ */
export function getCaptcha() { export function getCaptcha(): AxiosPromise<string> {
return request({ return request({
url: '/captcha?t=' + (new Date()).getTime().toString(), url: '/captcha?t=' + (new Date()).getTime().toString(),
method: 'get' method: 'get'

View File

@@ -1,11 +1,24 @@
import request from "@/utils/request"; import request from "@/utils/request";
import { AxiosPromise } from "axios";
import { UserInfo, UserQueryParam } from "@/types";
/**
* 登录成功后获取用户信息(包括用户头像、权限列表等)
*/
export function getUserInfo(): AxiosPromise<UserInfo> {
return request({
url: '/youlai-admin/api/v1/users/me',
method: 'get'
})
}
/** /**
* 获取用户分页列表 * 获取用户分页列表
* *
* @param queryParams * @param queryParams
*/ */
export function listUsersWithPage(queryParams: any) { export function listUserPages(queryParams: UserQueryParam) {
return request({ return request({
url: '/youlai-admin/api/v1/users/page', url: '/youlai-admin/api/v1/users/page',
method: 'get', method: 'get',

View File

@@ -1,8 +1,9 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { UserState } from "@/store/interface"; import { UserState } from "@/store/interface";
import { localStorage } from "@/utils/storage"; import { localStorage } from "@/utils/storage";
import {getUserInfo, login, logout} from "@/api/login"; import { login, logout } from "@/api/login";
import { resetRouter } from "@/router"; import { resetRouter } from "@/router";
import { getUserInfo } from "@/api/system/user";
const useUserStore = defineStore({ const useUserStore = defineStore({
id: "user", id: "user",

11
src/types/api/base.d.ts vendored Normal file
View File

@@ -0,0 +1,11 @@
export interface Page {
pageNum: number,
pageSize: number
}
export interface PageResult<T> {
data: T,
total: number
}

18
src/types/api/login.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
/**
* 登录请求参数
*/
export interface LoginRequestParam {
username: string,
password: string,
grant_type: string,
code: string,
uuid: string,
}
/**
* 登录响应参数
*/
export interface LoginResponseData {
access_token: string,
token_type: string
}

20
src/types/api/user.d.ts vendored Normal file
View File

@@ -0,0 +1,20 @@
import { Page, PageResult } from "./base"
/**
* 用户信息
*/
export interface UserInfo {
nickname: string,
avatar: string,
roles: string[],
perms: string[]
}
/**
* 用户查询参数
*/
export interface UserQueryParam extends Page {
keywords: String | undefined,
status: number | undefined ,
deptId: number | undefined
}

2
src/types/index.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
export * from './api/login'
export * from './api/user'

View File

@@ -1,11 +1,8 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-row :gutter="20"> <el-row :gutter="20">
<!-- 部门数据 --> <!-- 部门 -->
<el-col <el-col :span="4" :xs="24">
:span="4"
:xs="24"
>
<el-card class="box-card"> <el-card class="box-card">
<el-input <el-input
v-model="deptName" v-model="deptName"
@@ -28,16 +25,9 @@
</el-col> </el-col>
<!-- 用户数据 --> <!-- 用户数据 -->
<el-col <el-col :span="20" :xs="24">
:span="20"
:xs="24"
>
<el-card class="box-card"> <el-card class="box-card">
<el-form <el-form ref="queryFormRef" :model="queryParams" :inline="true">
ref="queryFormRef"
:model="queryParams"
:inline="true"
>
<el-form-item> <el-form-item>
<el-button <el-button
type="success" type="success"
@@ -81,19 +71,10 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button <el-button type="primary" :icon="Search" @click="handleQuery">
type="primary"
:icon="Search"
@click="handleQuery"
>
搜索 搜索
</el-button> </el-button>
<el-button <el-button :icon="Refresh" @click="resetQuery"> 重置 </el-button>
:icon="Refresh"
@click="resetQuery"
>
重置
</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -102,11 +83,7 @@
:data="pageList" :data="pageList"
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column <el-table-column type="selection" width="50" align="center" />
type="selection"
width="50"
align="center"
/>
<el-table-column <el-table-column
key="id" key="id"
label="用户编号" label="用户编号"
@@ -139,16 +116,12 @@
width="120" width="120"
/> />
<el-table-column <el-table-column label="状态" align="center" prop="status">
label="状态"
align="center"
prop="status"
>
<template #default="scope"> <template #default="scope">
<el-switch <el-switch
v-model="scope.row.status" v-model="scope.row.status"
:inactive-value=0 :inactive-value="0"
:active-value=1 :active-value="1"
@change="handleStatusChange(scope.row)" @change="handleStatusChange(scope.row)"
/> />
</template> </template>
@@ -160,11 +133,7 @@
width="180" width="180"
> >
</el-table-column> </el-table-column>
<el-table-column <el-table-column label="操作" align="center" width="150">
label="操作"
align="center"
width="150"
>
<template #default="scope"> <template #default="scope">
<el-button <el-button
type="primary" type="primary"
@@ -221,11 +190,7 @@
:rules="rules" :rules="rules"
label-width="80px" label-width="80px"
> >
<el-form-item label="用户名" prop="username">
<el-form-item
label="用户名"
prop="username"
>
<el-input <el-input
:readonly="!!formData.id" :readonly="!!formData.id"
v-model="formData.username" v-model="formData.username"
@@ -233,20 +198,11 @@
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="用户昵称" prop="nickname">
label="用户昵称" <el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
prop="nickname"
>
<el-input
v-model="formData.nickname"
placeholder="请输入用户昵称"
/>
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="归属部门" prop="deptId">
label="归属部门"
prop="deptId"
>
<tree-select <tree-select
v-model="formData.deptId" v-model="formData.deptId"
:options="deptOptions" :options="deptOptions"
@@ -254,10 +210,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="手机号码" prop="mobile">
label="手机号码"
prop="mobile"
>
<el-input <el-input
v-model="formData.mobile" v-model="formData.mobile"
placeholder="请输入手机号码" placeholder="请输入手机号码"
@@ -265,10 +218,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item <el-form-item label="邮箱" prop="email">
label="邮箱"
prop="email"
>
<el-input <el-input
v-model="formData.email" v-model="formData.email"
placeholder="请输入邮箱" placeholder="请输入邮箱"
@@ -284,10 +234,7 @@
</el-form-item> </el-form-item>
<el-form-item label="用户性别" prop="gender"> <el-form-item label="用户性别" prop="gender">
<el-select <el-select v-model="formData.gender" placeholder="请选择">
v-model="formData.gender"
placeholder="请选择"
>
<el-option label="未知" :value="0" /> <el-option label="未知" :value="0" />
<el-option label="男" :value="1" /> <el-option label="男" :value="1" />
<el-option label="女" :value="2" /> <el-option label="女" :value="2" />
@@ -295,11 +242,7 @@
</el-form-item> </el-form-item>
<el-form-item label="角色" prop="roleIds"> <el-form-item label="角色" prop="roleIds">
<el-select <el-select v-model="formData.roleIds" multiple placeholder="请选择">
v-model="formData.roleIds"
multiple
placeholder="请选择"
>
<el-option <el-option
v-for="item in roleOptions" v-for="item in roleOptions"
:key="item.id" :key="item.id"
@@ -311,15 +254,8 @@
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button <el-button type="primary" @click="submitForm"> </el-button>
type="primary" <el-button @click="cancel"> </el-button>
@click="submitForm"
>
</el-button>
<el-button @click="cancel">
</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
@@ -328,22 +264,44 @@
<script setup lang='ts'> <script setup lang='ts'>
// Vue依赖 // Vue依赖
import {reactive, ref, unref, watchEffect, onMounted, getCurrentInstance, toRefs} from 'vue' import {
reactive,
ref,
unref,
watchEffect,
onMounted,
getCurrentInstance,
toRefs,
} from "vue";
// API依赖 // API依赖
import {listUsersWithPage, getUserFormDetail, deleteUsers, addUser, updateUser, updateUserPart} from '@/api/system/user' import {
import {listDeptSelect} from '@/api/system/dept' listUserPages,
import {listRoles} from '@/api/system/role' getUserFormDetail,
deleteUsers,
addUser,
updateUser,
updateUserPart,
} from "@/api/system/user";
import { listDeptSelect } from "@/api/system/dept";
import { listRoles } from "@/api/system/role";
// 组件依赖 // 组件依赖
import {ElMessage, ElMessageBox, ElTree, ElForm} from 'element-plus' import { ElMessage, ElMessageBox, ElTree, ElForm } from "element-plus";
import {Search, Plus, Edit, Refresh, Delete, Lock} from '@element-plus/icons-vue' import {
import TreeSelect from '@/components/TreeSelect/index.vue' Search,
Plus,
Edit,
Refresh,
Delete,
Lock,
} from "@element-plus/icons-vue";
import TreeSelect from "@/components/TreeSelect/index.vue";
// DOM元素的引用声明定义 // DOM元素的引用声明定义
const deptTreeRef = ref(ElTree) // 变量名和DOM的ref属性值一致 const deptTreeRef = ref(ElTree); // 变量名和DOM的ref属性值一致
const queryFormRef = ref(ElForm) const queryFormRef = ref(ElForm);
const dataFormRef = ref(ElForm) const dataFormRef = ref(ElForm);
const { proxy }: any = getCurrentInstance(); const { proxy }: any = getCurrentInstance();
@@ -362,8 +320,8 @@ const state = reactive({
pageList: [], pageList: [],
// 弹窗属性 // 弹窗属性
dialog: { dialog: {
title: '', title: "",
visible: false visible: false,
}, },
deptName: undefined, deptName: undefined,
// 部门树选项 // 部门树选项
@@ -379,13 +337,13 @@ const state = reactive({
deptId: undefined, deptId: undefined,
username: undefined, username: undefined,
nickname: undefined, nickname: undefined,
password: '', password: "",
mobile: undefined, mobile: undefined,
email: undefined, email: undefined,
gender: undefined, gender: undefined,
status: 1, status: 1,
remark: undefined, remark: undefined,
roleIds: [] roleIds: [],
}, },
// 查询参数 // 查询参数
queryParams:{ queryParams:{
@@ -393,38 +351,32 @@ const state = reactive({
pageSize: 10, pageSize: 10,
keywords: undefined, keywords: undefined,
status: undefined, status: undefined,
deptId: undefined deptId: undefined,
}, },
// 表单校验 // 表单校验
rules: { rules: {
username: [ username: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
{required: true, message: '用户名不能为空', trigger: 'blur'}
],
nickname: [ nickname: [
{required: true, message: '用户昵称不能为空', trigger: 'blur'} { required: true, message: "用户昵称不能为空", trigger: "blur" },
],
deptId: [
{required: true, message: '归属部门不能为空', trigger: 'blur'}
],
roleId: [
{required: true, message: '用户角色不能为空', trigger: 'blur'}
], ],
deptId: [{ required: true, message: "归属部门不能为空", trigger: "blur" }],
roleId: [{ required: true, message: "用户角色不能为空", trigger: "blur" }],
email: [ email: [
{ {
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/, pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
message: '请输入正确的邮箱地址', message: "请输入正确的邮箱地址",
trigger: 'blur' trigger: "blur",
} },
], ],
mobile: [ mobile: [
{ {
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: '请输入正确的手机号码', message: "请输入正确的手机号码",
trigger: 'blur' trigger: "blur",
} },
] ],
} },
}) });
const { const {
loading, loading,
@@ -438,238 +390,251 @@ const {
rules, rules,
deptName, deptName,
deptOptions, deptOptions,
roleOptions roleOptions,
} = toRefs(state) } = toRefs(state);
/** /**
* 部门筛选 * 部门筛选
**/ */
watchEffect(() => { watchEffect(
const deptTree = unref(deptTreeRef) () => {
deptTree.filter(state.deptName) const deptTree = unref(deptTreeRef);
}, { deptTree.filter(state.deptName);
flush: 'post' // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行 },
}) {
flush: "post", // watchEffect会在DOM挂载或者更新之前就会触发此属性控制在DOM元素更新后运行
}
);
function filterDeptNode(value: string, data: any) { function filterDeptNode(value: string, data: any) {
if (!value) { if (!value) {
return true return true;
} }
return data.label.indexOf(value) !== -1 return data.label.indexOf(value) !== -1;
} }
/** /**
* 部门树节点点击事件 * 部门树节点点击事件
*/ */
function handleDeptNodeClick(data: { [key: string]: any }) { function handleDeptNodeClick(data: { [key: string]: any }) {
state.queryParams.deptId = data.id state.queryParams.deptId = data.id;
handleQuery() handleQuery();
} }
/** /**
* 加载角色数据 * 加载角色数据
*/ */
async function loadRoleOptions() { async function loadRoleOptions() {
listRoles().then(response => { listRoles().then((response) => {
state.roleOptions = response.data state.roleOptions = response.data;
}) });
} }
/** /**
* 用户状态修改 * 用户状态修改
*/ */
function handleStatusChange(row: { [key: string]: any }) { function handleStatusChange(row: { [key: string]: any }) {
const text = row.status === 1 ? '启用' : '停用' const text = row.status === 1 ? "启用" : "停用";
ElMessageBox.confirm('确认要' + text + '' + row.username + '用户吗?', '警告', { ElMessageBox.confirm(
confirmButtonText: '确定', "确认要" + text + "" + row.username + "用户吗?",
cancelButtonText: '取消', "警告",
type: 'warning' {
}).then(() => { confirmButtonText: "确定",
return updateUserPart(row.id, {status: row.status}) cancelButtonText: "取消",
}).then(() => { type: "warning",
ElMessage.success(text + '成功') }
}).catch(() => { )
row.status = row.status === 1 ? 0 : 1 .then(() => {
return updateUserPart(row.id, { status: row.status });
}) })
.then(() => {
ElMessage.success(text + "成功");
})
.catch(() => {
row.status = row.status === 1 ? 0 : 1;
});
} }
/** /**
* 用户查询 * 用户查询
**/ **/
function handleQuery() { function handleQuery() {
state.loading = true state.loading = true;
listUsersWithPage(state.queryParams).then(response => { listUserPages(state.queryParams).then((response) => {
const {data, total} = response as any const { data, total } = response as any;
state.pageList = data state.pageList = data;
state.total = total state.total = total;
state.loading = false state.loading = false;
}) });
} }
/** /**
* 重置查询 * 重置查询
*/ */
function resetQuery() { function resetQuery() {
const queryForm = unref(queryFormRef) const queryForm = unref(queryFormRef);
queryForm.resetFields() queryForm.resetFields();
handleQuery() handleQuery();
} }
/** /**
* 表格行选中事件 * 表格行选中事件
**/ */
function handleSelectionChange(selection: any) { function handleSelectionChange(selection: any) {
state.ids = selection.map((item: any) => item.id) state.ids = selection.map((item: any) => item.id);
state.single = selection.length !== 1 state.single = selection.length !== 1;
state.multiple = !selection.length state.multiple = !selection.length;
} }
/** /**
* 密码重置 * 密码重置
**/ */
function resetPassword(row: { [key: string]: any }) { function resetPassword(row: { [key: string]: any }) {
ElMessageBox.prompt('请输入用户「' + row.username + '」的新密码', '重置密码', { ElMessageBox.prompt(
confirmButtonText: '确定', "请输入用户「" + row.username + "」的新密码",
cancelButtonText: '取消' "重置密码",
}).then(({value}) => { {
confirmButtonText: "确定",
cancelButtonText: "取消",
}
)
.then(({ value }) => {
if (!value) { if (!value) {
ElMessage.warning("请输入新密码") ElMessage.warning("请输入新密码");
return false return false;
} }
updateUserPart(row.id, { updateUserPart(row.id, {
password: value password: value,
}).then(() => { }).then(() => {
ElMessage.success('修改成功,新密码是:' + value) ElMessage.success("修改成功,新密码是:" + value);
}) });
}).catch(() => {
}) })
.catch(() => {});
} }
/** /**
* 添加用户 * 添加用户
**/ **/
async function handleAdd() { async function handleAdd() {
await loadDeptOptions() await loadDeptOptions();
await loadRoleOptions() await loadRoleOptions();
state.dialog = { state.dialog = {
title: '添加用户', title: "添加用户",
visible: true visible: true,
} };
} }
/** /**
* 修改用户 * 修改用户
**/ **/
async function handleUpdate(row: { [key: string]: any }) { async function handleUpdate(row: { [key: string]: any }) {
const userId = row.id || state.ids const userId = row.id || state.ids;
await loadDeptOptions() await loadDeptOptions();
await loadRoleOptions() await loadRoleOptions();
state.dialog = { state.dialog = {
title: '修改用户', title: "修改用户",
visible: true visible: true,
} };
getUserFormDetail(userId).then((response: any) => { getUserFormDetail(userId).then((response: any) => {
state.formData = response.data state.formData = response.data;
}) });
} }
/** /**
* 表单提交 * 表单提交
**/ */
function submitForm() { function submitForm() {
const dataForm = unref(dataFormRef) const dataForm = unref(dataFormRef);
dataForm.validate((valid: any) => { dataForm.validate((valid: any) => {
if (valid) { if (valid) {
const userId = state.formData.id const userId = state.formData.id;
if (userId) { if (userId) {
updateUser(userId, state.formData).then(() => { updateUser(userId, state.formData).then(() => {
ElMessage.success('修改用户成功') ElMessage.success("修改用户成功");
state.dialog.visible = false state.dialog.visible = false;
resetForm() resetForm();
handleQuery() handleQuery();
}) });
} else { } else {
addUser(state.formData).then((response: any) => { addUser(state.formData).then((response: any) => {
ElMessage.success('新增用户成功') ElMessage.success("新增用户成功");
state.dialog.visible = false state.dialog.visible = false;
resetForm() resetForm();
handleQuery() handleQuery();
}) });
} }
} }
}) });
} }
/** /**
* 重置表单 * 重置表单
*/ */
function resetForm() { function resetForm() {
dataFormRef.value.resetFields() dataFormRef.value.resetFields();
} }
/** /**
* 删除用户 * 删除用户
**/ **/
function handleDelete(row: { [key: string]: any }) { function handleDelete(row: { [key: string]: any }) {
const userIds = row.id || state.ids.join(',') const userIds = row.id || state.ids.join(",");
ElMessageBox.confirm('是否确认删除用户编号为「' + userIds + '」的数据项?', '警告', { ElMessageBox.confirm(
confirmButtonText: '确定', "是否确认删除用户编号为「" + userIds + "」的数据项?",
cancelButtonText: '取消', "警告",
type: 'warning' {
}).then(function () { confirmButtonText: "确定",
deleteUsers(userIds).then(() => { cancelButtonText: "取消",
ElMessage.success('删除成功') type: "warning",
handleQuery() }
})
}).catch(() =>
ElMessage.info('已取消删除')
) )
.then(function () {
deleteUsers(userIds).then(() => {
ElMessage.success("删除成功");
handleQuery();
});
})
.catch(() => ElMessage.info("已取消删除"));
} }
/** /**
* 取消关闭 * 取消关闭
*/ */
function cancel() { function cancel() {
state.dialog.visible = false state.dialog.visible = false;
resetForm() resetForm();
} }
/** /**
* 加载部门数据 * 加载部门数据
**/ **/
async function loadDeptOptions() { async function loadDeptOptions() {
listDeptSelect().then(response => { listDeptSelect().then((response) => {
state.deptOptions = response.data state.deptOptions = response.data;
}) });
} }
/** /**
* 加载性别字典数据 * 加载性别字典数据
*/ */
function loadGenderOptions() { function loadGenderOptions() {
proxy.$listDictsByCode('gender').then((response: any) => { proxy.$listDictsByCode("gender").then((response: any) => {
state.genderOptions = response?.data state.genderOptions = response?.data;
}) });
} }
/** /**
* 初始化数据 * 初始化数据
*/ */
function loadData() { function loadData() {
loadGenderOptions() loadGenderOptions();
loadDeptOptions() loadDeptOptions();
handleQuery() handleQuery();
} }
onMounted(() => { onMounted(() => {
loadData();
loadData() });
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>