refactor: ♻️ 字典重构,系统权限模块优化
This commit is contained in:
@@ -5,9 +5,9 @@ VITE_APP_PORT = 3000
|
||||
VITE_APP_BASE_API = '/dev-api'
|
||||
|
||||
# 线上接口地址
|
||||
VITE_APP_API_URL = http://vapi.youlai.tech
|
||||
# VITE_APP_API_URL = http://vapi.youlai.tech
|
||||
# 开发接口地址
|
||||
# VITE_APP_API_URL = http://localhost:8989
|
||||
VITE_APP_API_URL = http://localhost:8989
|
||||
|
||||
# 是否启用 Mock 服务
|
||||
VITE_MOCK_DEV_SERVER = false
|
||||
|
||||
@@ -92,7 +92,7 @@ export default defineMock([
|
||||
},
|
||||
},
|
||||
|
||||
// 新增字典类型
|
||||
// 新增字典
|
||||
{
|
||||
url: "dict/types",
|
||||
method: ["POST"],
|
||||
@@ -100,12 +100,12 @@ export default defineMock([
|
||||
return {
|
||||
code: "00000",
|
||||
data: null,
|
||||
msg: "新增字典类型" + body.name + "成功",
|
||||
msg: "新增字典" + body.name + "成功",
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
// 获取字典类型表单数据
|
||||
// 获取字典表单数据
|
||||
{
|
||||
url: "dict/types/:id/form",
|
||||
method: ["GET"],
|
||||
@@ -118,7 +118,7 @@ export default defineMock([
|
||||
},
|
||||
},
|
||||
|
||||
// 修改字典类型
|
||||
// 修改字典
|
||||
{
|
||||
url: "dict/types/:id",
|
||||
method: ["PUT"],
|
||||
@@ -126,12 +126,12 @@ export default defineMock([
|
||||
return {
|
||||
code: "00000",
|
||||
data: null,
|
||||
msg: "修改字典类型" + body.name + "成功",
|
||||
msg: "修改字典" + body.name + "成功",
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
// 删除字典类型
|
||||
// 删除字典
|
||||
{
|
||||
url: "dict/types/:id",
|
||||
method: ["DELETE"],
|
||||
@@ -139,7 +139,7 @@ export default defineMock([
|
||||
return {
|
||||
code: "00000",
|
||||
data: null,
|
||||
msg: "删除字典类型" + params.id + "成功",
|
||||
msg: "删除字典" + params.id + "成功",
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -178,7 +178,7 @@ export default defineMock([
|
||||
return {
|
||||
code: "00000",
|
||||
data: null,
|
||||
msg: "修改字典类型" + body.name + "成功",
|
||||
msg: "修改字典" + body.name + "成功",
|
||||
};
|
||||
},
|
||||
},
|
||||
@@ -197,7 +197,7 @@ export default defineMock([
|
||||
},
|
||||
]);
|
||||
|
||||
// 字典类型映射表数据
|
||||
// 字典映射表数据
|
||||
const dictTypeMap: Record<string, any> = {
|
||||
1: {
|
||||
id: 1,
|
||||
|
||||
@@ -720,7 +720,7 @@ export default defineMock([
|
||||
{
|
||||
id: 79,
|
||||
parentId: 6,
|
||||
name: "字典类型新增",
|
||||
name: "字典新增",
|
||||
type: "BUTTON",
|
||||
path: "",
|
||||
component: null,
|
||||
@@ -734,7 +734,7 @@ export default defineMock([
|
||||
{
|
||||
id: 81,
|
||||
parentId: 6,
|
||||
name: "字典类型编辑",
|
||||
name: "字典编辑",
|
||||
type: "BUTTON",
|
||||
path: "",
|
||||
component: null,
|
||||
@@ -748,7 +748,7 @@ export default defineMock([
|
||||
{
|
||||
id: 84,
|
||||
parentId: 6,
|
||||
name: "字典类型删除",
|
||||
name: "字典删除",
|
||||
type: "BUTTON",
|
||||
path: "",
|
||||
component: null,
|
||||
@@ -1231,15 +1231,15 @@ export default defineMock([
|
||||
children: [
|
||||
{
|
||||
value: 79,
|
||||
label: "字典类型新增",
|
||||
label: "字典新增",
|
||||
},
|
||||
{
|
||||
value: 81,
|
||||
label: "字典类型编辑",
|
||||
label: "字典编辑",
|
||||
},
|
||||
{
|
||||
value: 84,
|
||||
label: "字典类型删除",
|
||||
label: "字典删除",
|
||||
},
|
||||
{
|
||||
value: 85,
|
||||
|
||||
72
src/api/auth.ts
Normal file
72
src/api/auth.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
const AUTH_BASE_URL = "/api/v1/auth";
|
||||
|
||||
class AuthAPI {
|
||||
/** 登录 接口*/
|
||||
static login(data: LoginData) {
|
||||
const formData = new FormData();
|
||||
formData.append("username", data.username);
|
||||
formData.append("password", data.password);
|
||||
formData.append("captchaKey", data.captchaKey);
|
||||
formData.append("captchaCode", data.captchaCode);
|
||||
return request<any, LoginResult>({
|
||||
url: `${AUTH_BASE_URL}/login`,
|
||||
method: "post",
|
||||
data: formData,
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** 注销 接口*/
|
||||
static logout() {
|
||||
return request({
|
||||
url: `${AUTH_BASE_URL}/logout`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
|
||||
/** 获取验证码 接口*/
|
||||
static getCaptcha() {
|
||||
return request<any, CaptchaResult>({
|
||||
url: `${AUTH_BASE_URL}/captcha`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthAPI;
|
||||
|
||||
/** 登录请求参数 */
|
||||
export interface LoginData {
|
||||
/** 用户名 */
|
||||
username: string;
|
||||
/** 密码 */
|
||||
password: string;
|
||||
/** 验证码缓存key */
|
||||
captchaKey: string;
|
||||
/** 验证码 */
|
||||
captchaCode: string;
|
||||
}
|
||||
|
||||
/** 登录响应 */
|
||||
export interface LoginResult {
|
||||
/** 访问token */
|
||||
accessToken?: string;
|
||||
/** 过期时间(单位:毫秒) */
|
||||
expires?: number;
|
||||
/** 刷新token */
|
||||
refreshToken?: string;
|
||||
/** token 类型 */
|
||||
tokenType?: string;
|
||||
}
|
||||
|
||||
/** 验证码响应 */
|
||||
export interface CaptchaResult {
|
||||
/** 验证码缓存key */
|
||||
captchaKey: string;
|
||||
/** 验证码图片Base64字符串 */
|
||||
captchaBase64: string;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
import { CaptchaResult, LoginData, LoginResult } from "./model";
|
||||
|
||||
const AUTH_BASE_URL = "/api/v1/auth";
|
||||
|
||||
class AuthAPI {
|
||||
/**
|
||||
* 登录API
|
||||
*
|
||||
* @param data 登录数据
|
||||
* @returns 登录结果
|
||||
*/
|
||||
static login(data: LoginData) {
|
||||
const formData = new FormData();
|
||||
formData.append("username", data.username);
|
||||
formData.append("password", data.password);
|
||||
formData.append("captchaKey", data.captchaKey || "");
|
||||
formData.append("captchaCode", data.captchaCode || "");
|
||||
return request<any, LoginResult>({
|
||||
url: `${AUTH_BASE_URL}/login`,
|
||||
method: "post",
|
||||
data: formData,
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销API
|
||||
*
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static logout() {
|
||||
return request({
|
||||
url: `${AUTH_BASE_URL}/logout`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*
|
||||
* @returns 验证码结果
|
||||
*/
|
||||
static getCaptcha() {
|
||||
return request<any, CaptchaResult>({
|
||||
url: `${AUTH_BASE_URL}/captcha`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default AuthAPI;
|
||||
@@ -1,59 +0,0 @@
|
||||
/**
|
||||
* 登录请求参数
|
||||
*/
|
||||
export interface LoginData {
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username: string;
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password: string;
|
||||
|
||||
/**
|
||||
* 验证码缓存key
|
||||
*/
|
||||
captchaKey?: string;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
captchaCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录响应
|
||||
*/
|
||||
export interface LoginResult {
|
||||
/**
|
||||
* 访问token
|
||||
*/
|
||||
accessToken?: string;
|
||||
/**
|
||||
* 过期时间(单位:毫秒)
|
||||
*/
|
||||
expires?: number;
|
||||
/**
|
||||
* 刷新token
|
||||
*/
|
||||
refreshToken?: string;
|
||||
/**
|
||||
* token 类型
|
||||
*/
|
||||
tokenType?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码响应
|
||||
*/
|
||||
export interface CaptchaResult {
|
||||
/**
|
||||
* 验证码缓存key
|
||||
*/
|
||||
captchaKey: string;
|
||||
/**
|
||||
* 验证码图片Base64字符串
|
||||
*/
|
||||
captchaBase64: string;
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import request from "@/utils/request";
|
||||
import { DeptForm, DeptQuery, DeptVO } from "./model";
|
||||
|
||||
const DEPT_BASE_URL = "/api/v1/dept";
|
||||
|
||||
class DeptAPI {
|
||||
/**
|
||||
* 获取部门树形表格列表
|
||||
* 获取部门列表
|
||||
*
|
||||
* @param queryParams 查询参数(可选)
|
||||
* @returns 部门树形表格数据
|
||||
@@ -18,11 +17,7 @@ class DeptAPI {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门下拉列表选项
|
||||
*
|
||||
* @returns 部门下拉列表选项
|
||||
*/
|
||||
/** 获取部门下拉列表 */
|
||||
static getOptions() {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${DEPT_BASE_URL}/options`,
|
||||
@@ -87,3 +82,47 @@ class DeptAPI {
|
||||
}
|
||||
|
||||
export default DeptAPI;
|
||||
|
||||
/** 部门查询参数 */
|
||||
export interface DeptQuery {
|
||||
/** 搜索关键字 */
|
||||
keywords?: string;
|
||||
/** 状态 */
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/** 部门类型 */
|
||||
export interface DeptVO {
|
||||
/** 子部门 */
|
||||
children?: DeptVO[];
|
||||
/** 创建时间 */
|
||||
createTime?: Date;
|
||||
/** 部门ID */
|
||||
id?: number;
|
||||
/** 部门名称 */
|
||||
name?: string;
|
||||
/** 部门编号 */
|
||||
code?: string;
|
||||
/** 父部门ID */
|
||||
parentId?: number;
|
||||
/** 排序 */
|
||||
sort?: number;
|
||||
/** 状态(1:启用;0:禁用) */
|
||||
status?: number;
|
||||
/** 修改时间 */
|
||||
updateTime?: Date;
|
||||
}
|
||||
|
||||
/** 部门表单类型 */
|
||||
export interface DeptForm {
|
||||
/** 部门ID(新增不填) */
|
||||
id?: number;
|
||||
/** 部门名称 */
|
||||
name?: string;
|
||||
/** 父部门ID */
|
||||
parentId: number;
|
||||
/** 排序 */
|
||||
sort?: number;
|
||||
/** 状态(1:启用;0:禁用) */
|
||||
status?: number;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* 部门查询参数
|
||||
*/
|
||||
export interface DeptQuery {
|
||||
keywords?: string;
|
||||
status?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门类型
|
||||
*/
|
||||
export interface DeptVO {
|
||||
/**
|
||||
* 子部门
|
||||
*/
|
||||
children?: DeptVO[];
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: Date;
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 父部门ID
|
||||
*/
|
||||
parentId?: number;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
updateTime?: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部门表单类型
|
||||
*/
|
||||
export interface DeptForm {
|
||||
/**
|
||||
* 部门ID(新增不填)
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 父部门ID
|
||||
*/
|
||||
parentId: number;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
}
|
||||
183
src/api/dict.ts
Normal file
183
src/api/dict.ts
Normal file
@@ -0,0 +1,183 @@
|
||||
import request from "@/utils/request";
|
||||
|
||||
const DICT_BASE_URL = "/api/v1/dict";
|
||||
|
||||
class DictAPI {
|
||||
/**
|
||||
* 获取字典分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 字典分页结果
|
||||
*/
|
||||
static getPage(queryParams: DictPageQuery) {
|
||||
return request<any, PageResult<DictPageVO[]>>({
|
||||
url: `${DICT_BASE_URL}/page`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典表单数据
|
||||
*
|
||||
* @param id 字典ID
|
||||
* @returns 字典表单数据
|
||||
*/
|
||||
static getFormData(id: number) {
|
||||
return request<any, ResponseData<DictForm>>({
|
||||
url: `${DICT_BASE_URL}/${id}/form`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典
|
||||
*
|
||||
* @param data 字典表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static add(data: DictForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典
|
||||
*
|
||||
* @param id 字典ID
|
||||
* @param data 字典表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static update(id: number, data: DictForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/${id}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典
|
||||
*
|
||||
* @param ids 字典ID,多个以英文逗号(,)分隔
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteByIds(ids: string) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/${ids}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典的数据项
|
||||
*
|
||||
* @param typeCode 字典编码
|
||||
* @returns 字典数据项
|
||||
*/
|
||||
static getOptions(code: string) {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${DICT_BASE_URL}/${code}/options`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default DictAPI;
|
||||
|
||||
/**
|
||||
* 字典查询参数
|
||||
*/
|
||||
export interface DictPageQuery extends PageQuery {
|
||||
/**
|
||||
* 关键字(字典名称/编码)
|
||||
*/
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典分页对象
|
||||
*/
|
||||
export interface DictPageVO {
|
||||
/**
|
||||
* 字典ID
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* 字典名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 字典编码
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* 字典状态(1-启用,0-禁用)
|
||||
*/
|
||||
status: number;
|
||||
/**
|
||||
* 字典项列表
|
||||
*/
|
||||
dictItems: DictItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典项
|
||||
*/
|
||||
export interface DictItem {
|
||||
/**
|
||||
* 字典项ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 字典项名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 字典项值
|
||||
*/
|
||||
value?: string;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 状态(1-启用,0-禁用)
|
||||
*/
|
||||
status?: number;
|
||||
}
|
||||
|
||||
// TypeScript 类型声明
|
||||
|
||||
/**
|
||||
* 字典
|
||||
*/
|
||||
export interface DictForm {
|
||||
/**
|
||||
* 字典ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 字典名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 字典编码
|
||||
*/
|
||||
code?: string;
|
||||
/**
|
||||
* 字典状态(1-启用,0-禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
/**
|
||||
* 字典数据项列表
|
||||
*/
|
||||
dictItems?: DictItem[];
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
import {
|
||||
DictTypeQuery,
|
||||
DictTypePageResult,
|
||||
DictTypeForm,
|
||||
DictQuery,
|
||||
DictForm,
|
||||
DictPageResult,
|
||||
} from "./model";
|
||||
|
||||
const DICT_BASE_URL = "/api/v1/dict";
|
||||
|
||||
class DictAPI {
|
||||
/**
|
||||
* 获取字典类型分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 字典类型分页结果
|
||||
*/
|
||||
static getDictTypePage(queryParams: DictTypeQuery) {
|
||||
return request<any, DictTypePageResult>({
|
||||
url: `${DICT_BASE_URL}/types/page`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典类型表单数据
|
||||
*
|
||||
* @param id 字典类型ID
|
||||
* @returns 字典类型表单数据
|
||||
*/
|
||||
static getDictTypeForm(id: number) {
|
||||
return request<any, ResponseData<DictTypeForm>>({
|
||||
url: `${DICT_BASE_URL}/types/${id}/form`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典类型
|
||||
*
|
||||
* @param data 字典类型表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static addDictType(data: DictTypeForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/types`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典类型
|
||||
*
|
||||
* @param id 字典类型ID
|
||||
* @param data 字典类型表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static updateDictType(id: number, data: DictTypeForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/types/${id}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典类型
|
||||
*
|
||||
* @param ids 字典类型ID,多个以英文逗号(,)分隔
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteDictTypes(ids: string) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/types/${ids}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典类型的数据项
|
||||
*
|
||||
* @param typeCode 字典类型编码
|
||||
* @returns 字典类型的数据项
|
||||
*/
|
||||
static getDictOptions(typeCode: string) {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${DICT_BASE_URL}/${typeCode}/options`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 字典分页结果
|
||||
*/
|
||||
static getDictPage(queryParams: DictQuery) {
|
||||
return request<any, DictPageResult>({
|
||||
url: `${DICT_BASE_URL}/page`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典表单数据
|
||||
*
|
||||
* @param id 字典项ID
|
||||
* @returns 字典表单数据
|
||||
*/
|
||||
static getDictFormData(id: number) {
|
||||
return request<any, DictForm>({
|
||||
url: `${DICT_BASE_URL}/${id}/form`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增字典
|
||||
*
|
||||
* @param data 字典表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static addDict(data: DictForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改字典项
|
||||
*
|
||||
* @param id 字典项ID
|
||||
* @param data 字典表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static updateDict(id: number, data: DictForm) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/${id}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字典
|
||||
*
|
||||
* @param ids 字典项ID,多个以英文逗号(,)分隔
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteDictByIds(ids: string) {
|
||||
return request({
|
||||
url: `${DICT_BASE_URL}/${ids}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default DictAPI;
|
||||
@@ -1,142 +0,0 @@
|
||||
/**
|
||||
* 字典类型查询参数
|
||||
*/
|
||||
export interface DictTypeQuery extends PageQuery {
|
||||
/**
|
||||
* 关键字(字典类型名称/编码)
|
||||
*/
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典类型分页对象
|
||||
*/
|
||||
export interface DictTypePageVO {
|
||||
/**
|
||||
* 字典类型ID
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
* 类型编码
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* 类型名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典分页项类型声明
|
||||
*/
|
||||
export type DictTypePageResult = PageResult<DictTypePageVO[]>;
|
||||
|
||||
/**
|
||||
* 字典表单类型声明
|
||||
*/
|
||||
export interface DictTypeForm {
|
||||
/**
|
||||
* 字典类型ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 类型名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 类型编码
|
||||
*/
|
||||
code?: string;
|
||||
/**
|
||||
* 类型状态:1:启用;0:禁用
|
||||
*/
|
||||
status: number;
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典查询参数
|
||||
*/
|
||||
export interface DictQuery extends PageQuery {
|
||||
/**
|
||||
* 字典项名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 字典类型编码
|
||||
*/
|
||||
typeCode?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典分页对象
|
||||
*/
|
||||
export interface DictPageVO {
|
||||
/**
|
||||
* 字典ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 字典名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 字典值
|
||||
*/
|
||||
value?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字典分页
|
||||
*/
|
||||
export type DictPageResult = PageResult<DictPageVO[]>;
|
||||
|
||||
/**
|
||||
* 字典表单
|
||||
*/
|
||||
export interface DictForm {
|
||||
/**
|
||||
* 字典ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 字典名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 类型编码
|
||||
*/
|
||||
typeCode?: string;
|
||||
/**
|
||||
* 值
|
||||
*/
|
||||
value?: string;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
remark?: string;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import request from "@/utils/request";
|
||||
import { FileInfo } from "./model";
|
||||
|
||||
class FileAPI {
|
||||
/**
|
||||
@@ -35,3 +34,13 @@ class FileAPI {
|
||||
}
|
||||
|
||||
export default FileAPI;
|
||||
|
||||
/**
|
||||
* 文件API类型声明
|
||||
*/
|
||||
export interface FileInfo {
|
||||
/** 文件名 */
|
||||
name: string;
|
||||
/** 文件路径 */
|
||||
url: string;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* 文件API类型声明
|
||||
*/
|
||||
export interface FileInfo {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
209
src/api/menu.ts
Normal file
209
src/api/menu.ts
Normal file
@@ -0,0 +1,209 @@
|
||||
import request from "@/utils/request";
|
||||
// 菜单基础URL
|
||||
const MENU_BASE_URL = "/api/v1/menus";
|
||||
|
||||
class MenuAPI {
|
||||
/**
|
||||
* 获取路由列表
|
||||
*
|
||||
* @returns 路由列表
|
||||
*/
|
||||
static getRoutes() {
|
||||
return request<any, RouteVO[]>({
|
||||
url: `${MENU_BASE_URL}/routes`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单树形列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 菜单树形列表
|
||||
*/
|
||||
static getList(queryParams: MenuQuery) {
|
||||
return request<any, MenuVO[]>({
|
||||
url: `${MENU_BASE_URL}`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉数据源
|
||||
*
|
||||
* @returns 菜单下拉数据源
|
||||
*/
|
||||
static getOptions() {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${MENU_BASE_URL}/options`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单表单数据
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @returns 菜单表单数据
|
||||
*/
|
||||
static getFormData(id: number) {
|
||||
return request<any, MenuForm>({
|
||||
url: `${MENU_BASE_URL}/${id}/form`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加菜单
|
||||
*
|
||||
* @param data 菜单表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static add(data: MenuForm) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @param data 菜单表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static update(id: string, data: MenuForm) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}/${id}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteById(id: number) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}/${id}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MenuAPI;
|
||||
|
||||
import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
|
||||
|
||||
/** 菜单查询参数 */
|
||||
export interface MenuQuery {
|
||||
/** 搜索关键字 */
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/** 菜单视图对象 */
|
||||
export interface MenuVO {
|
||||
/** 子菜单 */
|
||||
children?: MenuVO[];
|
||||
/** 组件路径 */
|
||||
component?: string;
|
||||
/** ICON */
|
||||
icon?: string;
|
||||
/** 菜单ID */
|
||||
id?: number;
|
||||
/** 菜单名称 */
|
||||
name?: string;
|
||||
/** 父菜单ID */
|
||||
parentId?: number;
|
||||
/** 按钮权限标识 */
|
||||
perm?: string;
|
||||
/** 跳转路径 */
|
||||
redirect?: string;
|
||||
/** 路由名称 */
|
||||
routeName?: string;
|
||||
/** 路由相对路径 */
|
||||
routePath?: string;
|
||||
/** 菜单排序(数字越小排名越靠前) */
|
||||
sort?: number;
|
||||
/** 菜单 */
|
||||
type?: MenuTypeEnum;
|
||||
/** 菜单是否可见(1:显示;0:隐藏) */
|
||||
visible?: number;
|
||||
}
|
||||
|
||||
/** 菜单表单对象 */
|
||||
export interface MenuForm {
|
||||
/** 菜单ID */
|
||||
id?: string;
|
||||
/** 父菜单ID */
|
||||
parentId?: number;
|
||||
/** 菜单名称 */
|
||||
name?: string;
|
||||
/** 菜单是否可见(1-是 0-否) */
|
||||
visible: number;
|
||||
/** ICON */
|
||||
icon?: string;
|
||||
/** 排序 */
|
||||
sort?: number;
|
||||
/** 路由名称 */
|
||||
routeName?: string;
|
||||
/** 路由路径 */
|
||||
routePath?: string;
|
||||
/** 组件路径 */
|
||||
component?: string;
|
||||
/** 跳转路由路径 */
|
||||
redirect?: string;
|
||||
/** 菜单 */
|
||||
type?: MenuTypeEnum;
|
||||
/** 权限标识 */
|
||||
perm?: string;
|
||||
/** 【菜单】是否开启页面缓存 */
|
||||
keepAlive?: number;
|
||||
/** 【目录】只有一个子路由是否始终显示 */
|
||||
alwaysShow?: number;
|
||||
/** 参数 */
|
||||
params?: KeyValue[];
|
||||
}
|
||||
|
||||
interface KeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/** RouteVO,路由对象 */
|
||||
export interface RouteVO {
|
||||
/** 子路由列表 */
|
||||
children: RouteVO[];
|
||||
/** 组件路径 */
|
||||
component?: string;
|
||||
/** 路由属性 */
|
||||
meta?: Meta;
|
||||
/** 路由名称 */
|
||||
name?: string;
|
||||
/** 路由路径 */
|
||||
path?: string;
|
||||
/** 跳转链接 */
|
||||
redirect?: string;
|
||||
}
|
||||
|
||||
/** Meta,路由属性 */
|
||||
export interface Meta {
|
||||
/** 【目录】只有一个子路由是否始终显示 */
|
||||
alwaysShow?: boolean;
|
||||
/** 是否隐藏(true-是 false-否) */
|
||||
hidden?: boolean;
|
||||
/** ICON */
|
||||
icon?: string;
|
||||
/** 【菜单】是否开启页面缓存 */
|
||||
keepAlive?: boolean;
|
||||
/** 拥有路由权限的角色编码 */
|
||||
roles?: string[];
|
||||
/** 路由title */
|
||||
title?: string;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import request from "@/utils/request";
|
||||
import { MenuQuery, MenuVO, MenuForm, RouteVO } from "./model";
|
||||
|
||||
const MENU_BASE_URL = "/api/v1/menus";
|
||||
|
||||
class MenuAPI {
|
||||
/**
|
||||
* 获取路由列表
|
||||
*
|
||||
* @returns 路由列表
|
||||
*/
|
||||
static getRoutes() {
|
||||
return request<any, RouteVO[]>({
|
||||
url: `${MENU_BASE_URL}/routes`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单树形列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 菜单树形列表
|
||||
*/
|
||||
static getList(queryParams: MenuQuery) {
|
||||
return request<any, MenuVO[]>({
|
||||
url: `${MENU_BASE_URL}`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单下拉数据源
|
||||
*
|
||||
* @returns 菜单下拉数据源
|
||||
*/
|
||||
static getOptions() {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${MENU_BASE_URL}/options`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单表单数据
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @returns 菜单表单数据
|
||||
*/
|
||||
static getFormData(id: number) {
|
||||
return request<any, MenuForm>({
|
||||
url: `${MENU_BASE_URL}/${id}/form`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加菜单
|
||||
*
|
||||
* @param data 菜单表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static add(data: MenuForm) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}`,
|
||||
method: "post",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改菜单
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @param data 菜单表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static update(id: string, data: MenuForm) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}/${id}`,
|
||||
method: "put",
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除菜单
|
||||
*
|
||||
* @param id 菜单ID
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteById(id: number) {
|
||||
return request({
|
||||
url: `${MENU_BASE_URL}/${id}`,
|
||||
method: "delete",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default MenuAPI;
|
||||
@@ -1,188 +0,0 @@
|
||||
import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
|
||||
|
||||
/**
|
||||
* 菜单查询参数类型
|
||||
*/
|
||||
export interface MenuQuery {
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单视图对象类型
|
||||
*/
|
||||
export interface MenuVO {
|
||||
/**
|
||||
* 子菜单
|
||||
*/
|
||||
children?: MenuVO[];
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
component?: string;
|
||||
/**
|
||||
* ICON
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
parentId?: number;
|
||||
/**
|
||||
* 按钮权限标识
|
||||
*/
|
||||
perm?: string;
|
||||
/**
|
||||
* 跳转路径
|
||||
*/
|
||||
redirect?: string;
|
||||
/**
|
||||
* 路由名称
|
||||
*/
|
||||
routeName?: string;
|
||||
/**
|
||||
* 路由相对路径
|
||||
*/
|
||||
routePath?: string;
|
||||
/**
|
||||
* 菜单排序(数字越小排名越靠前)
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 菜单类型
|
||||
*/
|
||||
type?: MenuTypeEnum;
|
||||
/**
|
||||
* 菜单是否可见(1:显示;0:隐藏)
|
||||
*/
|
||||
visible?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单表单对象类型
|
||||
*/
|
||||
export interface MenuForm {
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
parentId?: number;
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 菜单是否可见(1:是;0:否;)
|
||||
*/
|
||||
visible: number;
|
||||
icon?: string;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
component?: string;
|
||||
/**
|
||||
* 路由路径
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* 跳转路由路径
|
||||
*/
|
||||
redirect?: string;
|
||||
|
||||
/**
|
||||
* 菜单类型
|
||||
*/
|
||||
type?: MenuTypeEnum;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
perm?: string;
|
||||
/**
|
||||
* 【菜单】是否开启页面缓存
|
||||
*/
|
||||
keepAlive?: number;
|
||||
|
||||
/**
|
||||
* 【目录】只有一个子路由是否始终显示
|
||||
*/
|
||||
alwaysShow?: number;
|
||||
|
||||
params?: KeyValue[];
|
||||
}
|
||||
|
||||
interface KeyValue {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* RouteVO,路由对象
|
||||
*/
|
||||
export interface RouteVO {
|
||||
/**
|
||||
* 子路由列表
|
||||
*/
|
||||
children: RouteVO[];
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
component?: string;
|
||||
meta?: Meta;
|
||||
/**
|
||||
* 路由名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 路由路径
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* 跳转链接
|
||||
*/
|
||||
redirect?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Meta,路由属性类型
|
||||
*/
|
||||
export interface Meta {
|
||||
/**
|
||||
* 【目录】只有一个子路由是否始终显示
|
||||
*/
|
||||
alwaysShow?: boolean;
|
||||
/**
|
||||
* 是否隐藏(true-是 false-否)
|
||||
*/
|
||||
hidden?: boolean;
|
||||
/**
|
||||
* ICON
|
||||
*/
|
||||
icon?: string;
|
||||
/**
|
||||
* 【菜单】是否开启页面缓存
|
||||
*/
|
||||
keepAlive?: boolean;
|
||||
/**
|
||||
* 拥有路由权限的角色编码
|
||||
*/
|
||||
roles?: string[];
|
||||
/**
|
||||
* 路由title
|
||||
*/
|
||||
title?: string;
|
||||
}
|
||||
@@ -1,34 +1,22 @@
|
||||
import request from "@/utils/request";
|
||||
import { RoleQuery, RolePageResult, RoleForm } from "./model";
|
||||
|
||||
const ROLE_BASE_URL = "/api/v1/roles";
|
||||
|
||||
class RoleAPI {
|
||||
/**
|
||||
* 获取角色分页数据
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 角色分页数据
|
||||
*/
|
||||
static getPage(queryParams?: RoleQuery) {
|
||||
return request<any, RolePageResult>({
|
||||
/** 获取角色分页数据 */
|
||||
static getPage(queryParams?: RolePageQuery) {
|
||||
return request<any, PageResult<RolePageVO[]>>({
|
||||
url: `${ROLE_BASE_URL}/page`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色下拉数据源
|
||||
*
|
||||
* @param queryParams 查询参数(可选)
|
||||
* @returns 角色下拉数据源
|
||||
*/
|
||||
static getOptions(queryParams?: RoleQuery) {
|
||||
/** 获取角色下拉数据源 */
|
||||
static getOptions() {
|
||||
return request<any, OptionType[]>({
|
||||
url: `${ROLE_BASE_URL}/options`,
|
||||
method: "get",
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,7 +34,7 @@ class RoleAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分配菜单权限给角色
|
||||
* 分配菜单权限
|
||||
*
|
||||
* @param roleId 角色ID
|
||||
* @param data 菜单ID集合
|
||||
@@ -73,12 +61,7 @@ class RoleAPI {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加角色
|
||||
*
|
||||
* @param data 角色表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
/** 添加角色 */
|
||||
static add(data: RoleForm) {
|
||||
return request({
|
||||
url: `${ROLE_BASE_URL}`,
|
||||
@@ -92,7 +75,6 @@ class RoleAPI {
|
||||
*
|
||||
* @param id 角色ID
|
||||
* @param data 角色表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static update(id: number, data: RoleForm) {
|
||||
return request({
|
||||
@@ -106,7 +88,6 @@ class RoleAPI {
|
||||
* 批量删除角色,多个以英文逗号(,)分割
|
||||
*
|
||||
* @param ids 角色ID字符串,多个以英文逗号(,)分割
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteByIds(ids: string) {
|
||||
return request({
|
||||
@@ -117,3 +98,43 @@ class RoleAPI {
|
||||
}
|
||||
|
||||
export default RoleAPI;
|
||||
|
||||
/** 角色分页查询参数 */
|
||||
export interface RolePageQuery extends PageQuery {
|
||||
/** 搜索关键字 */
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/** 角色分页对象 */
|
||||
export interface RolePageVO {
|
||||
/** 角色编码 */
|
||||
code?: string;
|
||||
/** 角色ID */
|
||||
id?: number;
|
||||
/** 角色名称 */
|
||||
name?: string;
|
||||
/** 排序 */
|
||||
sort?: number;
|
||||
/** 角色状态 */
|
||||
status?: number;
|
||||
/** 创建时间 */
|
||||
createTime?: Date;
|
||||
/** 修改时间 */
|
||||
updateTime?: Date;
|
||||
}
|
||||
|
||||
/** 角色表单对象 */
|
||||
export interface RoleForm {
|
||||
/** 角色ID */
|
||||
id?: number;
|
||||
/** 角色编码 */
|
||||
code: string;
|
||||
/** 数据权限 */
|
||||
dataScope?: number;
|
||||
/** 角色名称 */
|
||||
name: string;
|
||||
/** 排序 */
|
||||
sort?: number;
|
||||
/** 角色状态(1-正常;0-停用) */
|
||||
status?: number;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* 角色查询参数
|
||||
*/
|
||||
export interface RoleQuery extends PageQuery {
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色分页对象
|
||||
*/
|
||||
export interface RolePageVO {
|
||||
/**
|
||||
* 角色编码
|
||||
*/
|
||||
code?: string;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 角色状态
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: Date;
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
updateTime?: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 角色分页
|
||||
*/
|
||||
export type RolePageResult = PageResult<RolePageVO[]>;
|
||||
|
||||
/**
|
||||
* 角色表单对象
|
||||
*/
|
||||
export interface RoleForm {
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
id?: number;
|
||||
|
||||
/**
|
||||
* 角色编码
|
||||
*/
|
||||
code: string;
|
||||
/**
|
||||
* 数据权限
|
||||
*/
|
||||
dataScope?: number;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
sort?: number;
|
||||
/**
|
||||
* 角色状态(1-正常;0-停用)
|
||||
*/
|
||||
status?: number;
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import request from "@/utils/request";
|
||||
import { UserForm, UserInfo, UserPageVO, UserQuery } from "./model";
|
||||
|
||||
const USER_BASE_URL = "/api/v1/users";
|
||||
|
||||
class UserAPI {
|
||||
/**
|
||||
* 登录成功后获取用户信息(昵称、头像、权限集合和角色集合)
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @returns 用户信息
|
||||
* @returns 登录用户昵称、头像信息,包括角色和权限
|
||||
*/
|
||||
static getInfo() {
|
||||
return request<any, UserInfo>({
|
||||
@@ -20,9 +19,8 @@ class UserAPI {
|
||||
* 获取用户分页列表
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 用户分页列表
|
||||
*/
|
||||
static getPage(queryParams: UserQuery) {
|
||||
static getPage(queryParams: UserPageQuery) {
|
||||
return request<any, PageResult<UserPageVO[]>>({
|
||||
url: `${USER_BASE_URL}/page`,
|
||||
method: "get",
|
||||
@@ -47,7 +45,6 @@ class UserAPI {
|
||||
* 添加用户
|
||||
*
|
||||
* @param data 用户表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static add(data: UserForm) {
|
||||
return request({
|
||||
@@ -62,7 +59,6 @@ class UserAPI {
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @param data 用户表单数据
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static update(id: number, data: UserForm) {
|
||||
return request({
|
||||
@@ -77,7 +73,6 @@ class UserAPI {
|
||||
*
|
||||
* @param id 用户ID
|
||||
* @param password 新密码
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static updatePassword(id: number, password: string) {
|
||||
return request({
|
||||
@@ -91,7 +86,6 @@ class UserAPI {
|
||||
* 批量删除用户,多个以英文逗号(,)分割
|
||||
*
|
||||
* @param ids 用户ID字符串,多个以英文逗号(,)分割
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static deleteByIds(ids: string) {
|
||||
return request({
|
||||
@@ -100,11 +94,7 @@ class UserAPI {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载用户导入模板
|
||||
*
|
||||
* @returns 用户导入模板文件
|
||||
*/
|
||||
/** 下载用户导入模板 */
|
||||
static downloadTemplate() {
|
||||
return request({
|
||||
url: `${USER_BASE_URL}/template`,
|
||||
@@ -117,9 +107,8 @@ class UserAPI {
|
||||
* 导出用户
|
||||
*
|
||||
* @param queryParams 查询参数
|
||||
* @returns 导出文件
|
||||
*/
|
||||
static export(queryParams: UserQuery) {
|
||||
static export(queryParams: UserPageQuery) {
|
||||
return request({
|
||||
url: `${USER_BASE_URL}/export`,
|
||||
method: "get",
|
||||
@@ -133,7 +122,6 @@ class UserAPI {
|
||||
*
|
||||
* @param deptId 部门ID
|
||||
* @param file 导入文件
|
||||
* @returns 请求结果
|
||||
*/
|
||||
static import(deptId: number, file: File) {
|
||||
const formData = new FormData();
|
||||
@@ -151,3 +139,94 @@ class UserAPI {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/** 开始时间 */
|
||||
startTime?: string;
|
||||
|
||||
/** 结束时间 */
|
||||
endTime?: string;
|
||||
}
|
||||
|
||||
/** 用户分页对象 */
|
||||
export interface UserPageVO {
|
||||
/** 用户头像URL */
|
||||
avatar?: string;
|
||||
/** 创建时间 */
|
||||
createTime?: Date;
|
||||
/** 部门名称 */
|
||||
deptName?: string;
|
||||
/** 用户邮箱 */
|
||||
email?: string;
|
||||
/** 性别 */
|
||||
genderLabel?: string;
|
||||
/** 用户ID */
|
||||
id?: number;
|
||||
/** 手机号 */
|
||||
mobile?: string;
|
||||
/** 用户昵称 */
|
||||
nickname?: string;
|
||||
/** 角色名称,多个使用英文逗号(,)分割 */
|
||||
roleNames?: string;
|
||||
/** 用户状态(1:启用;0:禁用) */
|
||||
status?: number;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
}
|
||||
|
||||
/** 用户表单类型 */
|
||||
export interface UserForm {
|
||||
/** 用户头像 */
|
||||
avatar?: string;
|
||||
/** 部门ID */
|
||||
deptId?: number;
|
||||
/** 邮箱 */
|
||||
email?: string;
|
||||
/** 性别 */
|
||||
gender?: number;
|
||||
/** 用户ID */
|
||||
id?: number;
|
||||
/** 手机号 */
|
||||
mobile?: string;
|
||||
/** 昵称 */
|
||||
nickname?: string;
|
||||
/** 角色ID集合 */
|
||||
roleIds?: number[];
|
||||
/** 用户状态(1:正常;0:禁用) */
|
||||
status?: number;
|
||||
/** 用户名 */
|
||||
username?: string;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/**
|
||||
* 登录用户信息
|
||||
*/
|
||||
export interface UserInfo {
|
||||
userId?: number;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
avatar?: string;
|
||||
roles: string[];
|
||||
perms: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户查询对象类型
|
||||
*/
|
||||
export interface UserQuery extends PageQuery {
|
||||
keywords?: string;
|
||||
status?: number;
|
||||
deptId?: number;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户分页对象
|
||||
*/
|
||||
export interface UserPageVO {
|
||||
/**
|
||||
* 用户头像地址
|
||||
*/
|
||||
avatar?: string;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
createTime?: Date;
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
deptName?: string;
|
||||
/**
|
||||
* 用户邮箱
|
||||
*/
|
||||
email?: string;
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
genderLabel?: string;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
id?: number;
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
mobile?: string;
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
nickname?: string;
|
||||
/**
|
||||
* 角色名称,多个使用英文逗号(,)分割
|
||||
*/
|
||||
roleNames?: string;
|
||||
/**
|
||||
* 用户状态(1:启用;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户表单类型
|
||||
*/
|
||||
export interface UserForm {
|
||||
/**
|
||||
* 用户头像
|
||||
*/
|
||||
avatar?: string;
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
deptId?: number;
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
email?: string;
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
gender?: number;
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
id?: number;
|
||||
mobile?: string;
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
nickname?: string;
|
||||
/**
|
||||
* 角色ID集合
|
||||
*/
|
||||
roleIds?: number[];
|
||||
/**
|
||||
* 用户状态(1:正常;0:禁用)
|
||||
*/
|
||||
status?: number;
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username?: string;
|
||||
}
|
||||
@@ -20,9 +20,9 @@ import DictAPI from "@/api/dict";
|
||||
|
||||
const props = defineProps({
|
||||
/**
|
||||
* 字典类型编码(eg: 性别-gender)
|
||||
* 字典编码(eg: 性别-gender)
|
||||
*/
|
||||
typeCode: {
|
||||
code: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
@@ -39,14 +39,17 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]); // 父组件监听事件,同步子组件值的变化给父组件
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
|
||||
const options: Ref<OptionType[]> = ref([]); // 字典下拉数据源
|
||||
const options: Ref<OptionType[]> = ref([]);
|
||||
|
||||
const selectedValue = ref<string | number | undefined>();
|
||||
|
||||
watch([options, () => props.modelValue], ([newOptions, newModelValue]) => {
|
||||
if (newOptions.length === 0) return; // 下拉数据源加载未完成不回显
|
||||
if (newOptions.length === 0) {
|
||||
// 下拉数据源加载未完成不回显
|
||||
return;
|
||||
}
|
||||
if (newModelValue == undefined) {
|
||||
selectedValue.value = undefined;
|
||||
return;
|
||||
@@ -65,8 +68,8 @@ function handleChange(val?: string | number | undefined) {
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
// 根据字典类型编码(typeCode)获取字典选项
|
||||
DictAPI.getDictOptions(props.typeCode).then((data) => {
|
||||
// 根据字典编码获取字典项
|
||||
DictAPI.getOptions(props.code).then((data) => {
|
||||
options.value = data;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { RouteRecordRaw } from "vue-router";
|
||||
import { constantRoutes } from "@/router";
|
||||
import { store } from "@/store";
|
||||
import MenuAPI from "@/api/menu";
|
||||
import { RouteVO } from "@/api/menu/model";
|
||||
import { RouteVO } from "@/api/menu/types";
|
||||
|
||||
const modules = import.meta.glob("../../views/**/**.vue");
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
|
||||
@@ -3,8 +3,8 @@ import UserAPI from "@/api/user";
|
||||
import { resetRouter } from "@/router";
|
||||
import { store } from "@/store";
|
||||
|
||||
import { LoginData } from "@/api/auth/model";
|
||||
import { UserInfo } from "@/api/user/model";
|
||||
import { LoginData } from "@/api/auth";
|
||||
import { UserInfo } from "@/api/user";
|
||||
import { TOKEN_KEY } from "@/enums/CacheEnum";
|
||||
|
||||
export const useUserStore = defineStore("user", () => {
|
||||
|
||||
@@ -13,6 +13,7 @@ declare module "vue" {
|
||||
Breadcrumb: (typeof import("./../components/Breadcrumb/index.vue"))["default"];
|
||||
CURD: (typeof import("./../components/CURD/index.vue"))["default"];
|
||||
DeptTree: (typeof import("./../views/system/user/components/dept-tree.vue"))["default"];
|
||||
UserImport: (typeof import("./../views/system/user/components/user-import.vue"))["default"];
|
||||
Dictionary: (typeof import("./../components/Dictionary/index.vue"))["default"];
|
||||
DictItem: (typeof import("./../views/system/dict/components/dict-item.vue"))["default"];
|
||||
ElBacktop: (typeof import("element-plus/es"))["ElBacktop"];
|
||||
@@ -1,7 +1,6 @@
|
||||
import DeptAPI from "@/api/dept";
|
||||
import RoleAPI from "@/api/role";
|
||||
import UserAPI from "@/api/user";
|
||||
import type { UserForm } from "@/api/user/model";
|
||||
import UserAPI, { UserForm } from "@/api/user";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
|
||||
const modalConfig: IModalConfig<UserForm> = {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import UserAPI from "@/api/user";
|
||||
import RoleAPI from "@/api/role";
|
||||
import type { UserQuery } from "@/api/user/model";
|
||||
import type { UserPageQuery } from "@/api/user";
|
||||
import type { IContentConfig } from "@/components/CURD/types";
|
||||
|
||||
const contentConfig: IContentConfig<UserQuery> = {
|
||||
const contentConfig: IContentConfig<UserPageQuery> = {
|
||||
pageName: "sys:user",
|
||||
table: {
|
||||
border: true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import DeptAPI from "@/api/dept";
|
||||
import RoleAPI from "@/api/role";
|
||||
import UserAPI from "@/api/user";
|
||||
import type { UserForm } from "@/api/user/model";
|
||||
import type { UserForm } from "@/api/user";
|
||||
import type { IModalConfig } from "@/components/CURD/types";
|
||||
import { DeviceEnum } from "@/enums/DeviceEnum";
|
||||
import { useAppStore } from "@/store";
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
@submit-click="handleSubmitClick"
|
||||
>
|
||||
<template #gender="scope">
|
||||
<dictionary v-model="scope.formData[scope.prop]" type-code="gender" />
|
||||
<dictionary v-model="scope.formData[scope.prop]" code="gender" />
|
||||
</template>
|
||||
</page-modal>
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
@submit-click="handleSubmitClick"
|
||||
>
|
||||
<template #gender="scope">
|
||||
<dictionary v-model="scope.formData[scope.prop]" type-code="gender" />
|
||||
<dictionary v-model="scope.formData[scope.prop]" code="gender" />
|
||||
</template>
|
||||
</page-modal>
|
||||
</template>
|
||||
|
||||
@@ -15,14 +15,14 @@ const numberValue = ref(1); // 性别(值为Number)
|
||||
>
|
||||
<el-form>
|
||||
<el-form-item label="性别">
|
||||
<dictionary v-model="stringValue" type-code="gender" />
|
||||
<dictionary v-model="stringValue" code="gender" />
|
||||
<el-link :underline="false" type="primary" class="ml-5"
|
||||
>值为String: const value = ref("1");
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="性别">
|
||||
<dictionary v-model="numberValue" type-code="gender" />
|
||||
<dictionary v-model="numberValue" code="gender" />
|
||||
<el-link :underline="false" type="success" class="ml-5"
|
||||
>值为Number: const value = ref(1);
|
||||
</el-link>
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<script setup lang="ts">
|
||||
import { useSettingsStore, useUserStore } from "@/store";
|
||||
import AuthAPI from "@/api/auth";
|
||||
import { LoginData } from "@/api/auth/model";
|
||||
import { LoginData } from "@/api/auth/types";
|
||||
import type { FormInstance } from "element-plus";
|
||||
import { LocationQuery, useRoute } from "vue-router";
|
||||
import router from "@/router";
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<el-button
|
||||
v-hasPerm="['sys:dept:add']"
|
||||
type="success"
|
||||
@click="openDialog(0, undefined)"
|
||||
@click="handleOpenDialog(0, undefined)"
|
||||
><i-ep-plus />新增</el-button
|
||||
>
|
||||
<el-button
|
||||
@@ -60,6 +60,7 @@
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column prop="name" label="部门名称" min-width="200" />
|
||||
<el-table-column prop="code" label="部门编号" width="200" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status == 1" type="success">正常</el-tag>
|
||||
@@ -76,7 +77,7 @@
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="openDialog(scope.row.id, undefined)"
|
||||
@click.stop="handleOpenDialog(scope.row.id, undefined)"
|
||||
><i-ep-plus />新增
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -84,7 +85,7 @@
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="openDialog(scope.row.parentId, scope.row.id)"
|
||||
@click.stop="handleOpenDialog(scope.row.parentId, scope.row.id)"
|
||||
><i-ep-edit />编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
@@ -105,7 +106,7 @@
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
width="600px"
|
||||
@closed="closeDialog"
|
||||
@closed="handleCloseDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="deptFormRef"
|
||||
@@ -126,6 +127,9 @@
|
||||
<el-form-item label="部门名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入部门名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部门编号" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入部门编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="显示排序" prop="sort">
|
||||
<el-input-number
|
||||
v-model="formData.sort"
|
||||
@@ -145,7 +149,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit"> 确 定 </el-button>
|
||||
<el-button @click="closeDialog"> 取 消 </el-button>
|
||||
<el-button @click="handleCloseDialog"> 取 消 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -158,8 +162,7 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import DeptAPI from "@/api/dept";
|
||||
import { DeptVO, DeptForm, DeptQuery } from "@/api/dept/model";
|
||||
import DeptAPI, { DeptVO, DeptForm, DeptQuery } from "@/api/dept";
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const deptFormRef = ref(ElForm);
|
||||
@@ -183,12 +186,15 @@ const formData = reactive<DeptForm>({
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
parentId: [{ required: true, message: "上级部门不能为空", trigger: "blur" }],
|
||||
parentId: [
|
||||
{ required: true, message: "上级部门不能为空", trigger: "change" },
|
||||
],
|
||||
name: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
|
||||
code: [{ required: true, message: "部门编号不能为空", trigger: "blur" }],
|
||||
sort: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
|
||||
});
|
||||
|
||||
/** 查询 */
|
||||
/** 查询部门 */
|
||||
function handleQuery() {
|
||||
loading.value = true;
|
||||
DeptAPI.getList(queryParams).then((data) => {
|
||||
@@ -197,7 +203,7 @@ function handleQuery() {
|
||||
});
|
||||
}
|
||||
|
||||
/**重置查询 */
|
||||
/** 重置查询 */
|
||||
function handleResetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
handleQuery();
|
||||
@@ -208,9 +214,15 @@ function handleSelectionChange(selection: any) {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
}
|
||||
|
||||
/** 获取部门下拉数据 */
|
||||
async function loadDeptOptions() {
|
||||
DeptAPI.getOptions().then((data) => {
|
||||
/**
|
||||
* 打开部门弹窗
|
||||
*
|
||||
* @param parentId 父部门ID
|
||||
* @param deptId 部门ID
|
||||
*/
|
||||
async function handleOpenDialog(parentId?: number, deptId?: number) {
|
||||
// 加载部门下拉数据
|
||||
const data = await DeptAPI.getOptions();
|
||||
deptOptions.value = [
|
||||
{
|
||||
value: 0,
|
||||
@@ -218,17 +230,7 @@ async function loadDeptOptions() {
|
||||
children: data,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*
|
||||
* @param parentId 父部门ID
|
||||
* @param deptId 部门ID
|
||||
*/
|
||||
async function openDialog(parentId?: number, deptId?: number) {
|
||||
await loadDeptOptions();
|
||||
dialog.visible = true;
|
||||
if (deptId) {
|
||||
dialog.title = "修改部门";
|
||||
@@ -241,17 +243,17 @@ async function openDialog(parentId?: number, deptId?: number) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 表单提交 */
|
||||
/** 提交部门表单 */
|
||||
function handleSubmit() {
|
||||
deptFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
const deptId = formData.id;
|
||||
loading.value = true;
|
||||
const deptId = formData.id;
|
||||
if (deptId) {
|
||||
DeptAPI.update(deptId, formData)
|
||||
.then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
@@ -259,7 +261,7 @@ function handleSubmit() {
|
||||
DeptAPI.add(formData)
|
||||
.then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
@@ -290,13 +292,9 @@ function handleDelete(deptId?: number) {
|
||||
}
|
||||
|
||||
/** 关闭弹窗 */
|
||||
function closeDialog() {
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
deptFormRef.value.resetFields();
|
||||
deptFormRef.value.clearValidate();
|
||||
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
<!-- 字典数据 -->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="search-container">
|
||||
<!-- 搜索表单 -->
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
<el-form-item label="关键字" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="字典名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery"
|
||||
><i-ep-search />搜索</el-button
|
||||
>
|
||||
<el-button @click="handleResetQuery"> <i-ep-refresh />重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict:add']"
|
||||
type="success"
|
||||
@click="openDialog()"
|
||||
><i-ep-plus />新增</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict:delete']"
|
||||
type="danger"
|
||||
:disabled="ids.length === 0"
|
||||
@click="handleDelete()"
|
||||
><i-ep-delete />删除</el-button
|
||||
>
|
||||
</template>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="dictList"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="50" />
|
||||
<el-table-column label="字典名称" prop="name" />
|
||||
<el-table-column label="字典值" prop="value" />
|
||||
<el-table-column label="状态" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status === 1" type="success">启用</el-tag>
|
||||
<el-tag v-else type="info">禁用</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" label="操作" align="center">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict:edit']"
|
||||
type="primary"
|
||||
link
|
||||
@click="openDialog(scope.row.id)"
|
||||
><i-ep-edit />编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict:delete']"
|
||||
type="primary"
|
||||
link
|
||||
@click.stop="handleDelete(scope.row.id)"
|
||||
><i-ep-delete />删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-if="total > 0"
|
||||
v-model:total="total"
|
||||
v-model:page="queryParams.pageNum"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="handleQuery"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 表单弹窗 -->
|
||||
<el-dialog
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
width="500px"
|
||||
@close="closeDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="字典名称">{{ typeName }}</el-form-item>
|
||||
<el-form-item label="字典名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入字典名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典值" prop="value">
|
||||
<el-input v-model="formData.value" placeholder="字典值" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sort">
|
||||
<el-input-number
|
||||
v-model="formData.sort"
|
||||
controls-position="right"
|
||||
:min="0"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">正常</el-radio>
|
||||
<el-radio :label="0">停用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="formData.remark" type="textarea" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "DictData",
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import DictAPI from "@/api/dict";
|
||||
import { DictPageVO, DictForm, DictQuery } from "@/api/dict/model";
|
||||
|
||||
const props = defineProps({
|
||||
typeCode: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
typeName: {
|
||||
type: String,
|
||||
default: () => {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.typeCode,
|
||||
(newVal: string) => {
|
||||
queryParams.typeCode = newVal;
|
||||
formData.typeCode = newVal;
|
||||
handleResetQuery();
|
||||
}
|
||||
);
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref(ElForm);
|
||||
|
||||
const loading = ref(false);
|
||||
const ids = ref<number[]>([]);
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<DictQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
typeCode: props.typeCode,
|
||||
});
|
||||
|
||||
const dictList = ref<DictPageVO[]>();
|
||||
|
||||
const dialog = reactive({
|
||||
title: "",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const formData = reactive<DictForm>({
|
||||
status: 1,
|
||||
typeCode: props.typeCode,
|
||||
sort: 1,
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: "请输入字典名称", trigger: "blur" }],
|
||||
value: [{ required: true, message: "请输入字典值", trigger: "blur" }],
|
||||
});
|
||||
|
||||
/** 查询 */
|
||||
function handleQuery() {
|
||||
if (queryParams.typeCode) {
|
||||
loading.value = true;
|
||||
DictAPI.getDictPage(queryParams)
|
||||
.then((data) => {
|
||||
dictList.value = data.list;
|
||||
total.value = data.total;
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置查询 */
|
||||
function handleResetQuery() {
|
||||
queryFormRef.value.resetFields();
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* 行checkbox change事件
|
||||
*
|
||||
* @param selection
|
||||
*/
|
||||
function handleSelectionChange(selection: any) {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开字典表单弹窗
|
||||
*
|
||||
* @param dictId 字典ID
|
||||
*/
|
||||
function openDialog(dictId?: number) {
|
||||
dialog.visible = true;
|
||||
if (dictId) {
|
||||
dialog.title = "修改字典";
|
||||
DictAPI.getDictFormData(dictId).then((data) => {
|
||||
Object.assign(formData, data);
|
||||
});
|
||||
} else {
|
||||
dialog.title = "新增字典";
|
||||
}
|
||||
}
|
||||
|
||||
/** 字典表单提交 */
|
||||
function handleSubmit() {
|
||||
dataFormRef.value.validate((isValid: boolean) => {
|
||||
if (isValid) {
|
||||
loading.value = false;
|
||||
const dictId = formData.id;
|
||||
if (dictId) {
|
||||
DictAPI.updateDict(dictId, formData)
|
||||
.then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
closeDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
} else {
|
||||
DictAPI.addDict(formData)
|
||||
.then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
closeDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭弹窗 */
|
||||
function closeDialog() {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
/** 重置表单 */
|
||||
function resetForm() {
|
||||
dataFormRef.value.resetFields();
|
||||
dataFormRef.value.clearValidate();
|
||||
|
||||
formData.id = undefined;
|
||||
formData.status = 1;
|
||||
formData.sort = 1;
|
||||
formData.typeCode = props.typeCode;
|
||||
}
|
||||
|
||||
/** 删除字典 */
|
||||
function handleDelete(dictId?: number) {
|
||||
const dictIds = [dictId || ids.value].join(",");
|
||||
if (!dictIds) {
|
||||
ElMessage.warning("请勾选删除项");
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
DictAPI.deleteDictByIds(dictIds).then(() => {
|
||||
ElMessage.success("删除成功");
|
||||
handleResetQuery();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
@@ -1,5 +1,4 @@
|
||||
<!--字典类型-->
|
||||
|
||||
<!-- 分类字典 -->
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div class="search-container">
|
||||
@@ -7,7 +6,7 @@
|
||||
<el-form-item label="关键字" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.keywords"
|
||||
placeholder="字典类型名称/编码"
|
||||
placeholder="字典名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
/>
|
||||
@@ -16,68 +15,67 @@
|
||||
<el-button type="primary" @click="handleQuery()"
|
||||
><i-ep-search />搜索</el-button
|
||||
>
|
||||
<el-button @click="handleResetQuery()"
|
||||
<el-button @click="handleResetClick()"
|
||||
><i-ep-refresh />重置</el-button
|
||||
>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never" class="table-container">
|
||||
<template #header>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict_type:add']"
|
||||
type="success"
|
||||
@click="openDialog()"
|
||||
<el-card shadow="never">
|
||||
<div class="mb-[10px]">
|
||||
<el-button type="success" @click="handleAddClick()"
|
||||
><i-ep-plus />新增</el-button
|
||||
>
|
||||
<el-button
|
||||
type="danger"
|
||||
:disabled="ids.length === 0"
|
||||
@click="handleDelete()"
|
||||
@click="handleDeleteClick()"
|
||||
><i-ep-delete />删除</el-button
|
||||
>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
:data="dictTypeList"
|
||||
:data="tableData"
|
||||
border
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="字典类型名称" prop="name" width="200" />
|
||||
<el-table-column label="字典类型编码" prop="code" width="200" />
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status === 1" type="success">启用</el-tag>
|
||||
<el-tag v-else type="info">禁用</el-tag>
|
||||
|
||||
<el-table-column type="expand" label="字典项列表" width="100">
|
||||
<template #default="props">
|
||||
<el-table :data="props.row.dictItems">
|
||||
<el-table-column label="字典项键" prop="name" width="200" />
|
||||
<el-table-column label="字典项值" prop="value" align="center" />
|
||||
<el-table-column label="排序" prop="sort" align="center" />
|
||||
</el-table>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字典名称" prop="name" />
|
||||
<el-table-column label="字典编码" prop="code" />
|
||||
<el-table-column label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'">
|
||||
{{ scope.row.status === 1 ? "启用" : "禁用" }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" prop="remark" align="center" />
|
||||
<el-table-column fixed="right" label="操作" align="center" width="220">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="openDictDialog(scope.row)"
|
||||
><i-ep-Collection />字典数据</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict_type:edit']"
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="openDialog(scope.row.id)"
|
||||
@click.stop="handleEditClick(scope.row.id, scope.row.name)"
|
||||
><i-ep-edit />编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPerm="['sys:dict_type:delete']"
|
||||
type="primary"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleDelete(scope.row.id)"
|
||||
@click.stop="handleDeleteClick(scope.row.id)"
|
||||
><i-ep-delete />删除</el-button
|
||||
>
|
||||
</template>
|
||||
@@ -93,71 +91,128 @@
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog
|
||||
<!--字典弹窗-->
|
||||
<el-drawer
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
width="500px"
|
||||
@close="closeDialog"
|
||||
size="70%"
|
||||
@close="handleCloseDialog"
|
||||
>
|
||||
<el-form
|
||||
ref="dataFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="80px"
|
||||
:rules="computedRules"
|
||||
label-width="100px"
|
||||
:inline="true"
|
||||
>
|
||||
<el-card shadow="never">
|
||||
<el-form-item label="字典名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入字典名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典编码" prop="code">
|
||||
<el-input v-model="formData.code" placeholder="请输入字典编码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
|
||||
<el-form-item label="状态">
|
||||
<el-radio-group v-model="formData.status">
|
||||
<el-radio :label="1">正常</el-radio>
|
||||
<el-radio :label="0">停用</el-radio>
|
||||
<el-radio :value="1">启用</el-radio>
|
||||
<el-radio :value="0">禁用</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
type="textarea"
|
||||
placeholder="字典类型备注"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||
/>
|
||||
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="formData.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt-5">
|
||||
<template #header>
|
||||
<div class="flex-x-between">
|
||||
<span>字典项</span>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="handleAddAttrClick"
|
||||
><i-ep-plus />新增字典</el-button
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!--字典数据弹窗-->
|
||||
<el-dialog
|
||||
v-model="dictDataDialog.visible"
|
||||
:title="dictDataDialog.title"
|
||||
width="1000px"
|
||||
@close="closeDictDialog"
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
highlight--currentrow
|
||||
:data="formData.dictItems"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<dict-item
|
||||
v-model:typeCode="selectedDictType.typeCode"
|
||||
v-model:typeName="selectedDictType.typeName"
|
||||
<el-table-column label="字典项名称" width="200">
|
||||
<template #default="scope">
|
||||
<el-form-item :prop="'dictItems.' + scope.$index + '.name'">
|
||||
<el-input v-model="scope.row.name" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="字典项值" width="200">
|
||||
<template #default="scope">
|
||||
<el-form-item :prop="'dictItems.' + scope.$index + '.value'">
|
||||
<el-input v-model="scope.row.value" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="排序">
|
||||
<template #default="scope">
|
||||
<el-form-item :prop="'dictItems.' + scope.$index + '.sort'">
|
||||
<el-input v-model="scope.row.sort" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" prop="status">
|
||||
<template #default="scope">
|
||||
<el-form-item :prop="'dictItems.' + scope.$index + '.status'">
|
||||
<el-switch
|
||||
v-model="scope.row.status"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
/>
|
||||
</el-dialog>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
fixed="right"
|
||||
label="操作"
|
||||
align="center"
|
||||
width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleDeleteAttrClick(scope.$index)"
|
||||
><i-ep-delete />删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmitClick">确 定</el-button>
|
||||
<el-button @click="handleCloseDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({
|
||||
name: "DictType",
|
||||
inheritAttrs: false,
|
||||
name: "Dict",
|
||||
inherititems: false,
|
||||
});
|
||||
|
||||
import DictAPI from "@/api/dict";
|
||||
|
||||
import { DictTypePageVO, DictTypeQuery, DictTypeForm } from "@/api/dict/model";
|
||||
import DictAPI, { DictPageQuery, DictPageVO, DictForm } from "@/api/dict";
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const dataFormRef = ref(ElForm);
|
||||
@@ -166,33 +221,42 @@ const loading = ref(false);
|
||||
const ids = ref<number[]>([]);
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<DictTypeQuery>({
|
||||
const queryParams = reactive<DictPageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const dictTypeList = ref<DictTypePageVO[]>();
|
||||
const tableData = ref<DictPageVO[]>();
|
||||
|
||||
// 字典弹窗
|
||||
const dialog = reactive({
|
||||
title: "",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const formData = reactive<DictTypeForm>({
|
||||
status: 1,
|
||||
const formData = reactive<DictForm>({});
|
||||
|
||||
const computedRules = computed(() => {
|
||||
const rules: Partial<Record<string, any>> = {
|
||||
name: [{ required: true, message: "请输入字典名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入字典编码", trigger: "blur" }],
|
||||
};
|
||||
if (formData.dictItems) {
|
||||
formData.dictItems.forEach((attr, index) => {
|
||||
rules[`dictItems.${index}.name`] = [
|
||||
{ required: true, message: "请输入字典项名称", trigger: "blur" },
|
||||
];
|
||||
});
|
||||
}
|
||||
return rules;
|
||||
});
|
||||
|
||||
const rules = reactive({
|
||||
name: [{ required: true, message: "请输入字典类型名称", trigger: "blur" }],
|
||||
code: [{ required: true, message: "请输入字典类型编码", trigger: "blur" }],
|
||||
});
|
||||
|
||||
/** 查询 */
|
||||
// 查询
|
||||
function handleQuery() {
|
||||
loading.value = true;
|
||||
DictAPI.getDictTypePage(queryParams)
|
||||
DictAPI.getPage(queryParams)
|
||||
.then((data) => {
|
||||
dictTypeList.value = data.list;
|
||||
tableData.value = data.list;
|
||||
total.value = data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -200,56 +264,57 @@ function handleQuery() {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置查询
|
||||
*/
|
||||
function handleResetQuery() {
|
||||
// 重置查询
|
||||
function handleResetClick() {
|
||||
queryFormRef.value.resetFields();
|
||||
queryParams.pageNum = 1;
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 行复选框选中 */
|
||||
// 行选择
|
||||
function handleSelectionChange(selection: any) {
|
||||
ids.value = selection.map((item: any) => item.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开字典类型表单弹窗
|
||||
*
|
||||
* @param dicTypeId 字典类型ID
|
||||
*/
|
||||
function openDialog(dicTypeId?: number) {
|
||||
// 新增字典
|
||||
function handleAddClick() {
|
||||
dialog.visible = true;
|
||||
if (dicTypeId) {
|
||||
dialog.title = "修改字典类型";
|
||||
DictAPI.getDictTypeForm(dicTypeId).then((data) => {
|
||||
dialog.title = "新增字典";
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑字典
|
||||
*
|
||||
* @param id 字典ID
|
||||
*/
|
||||
function handleEditClick(id: number, name: string) {
|
||||
dialog.visible = true;
|
||||
dialog.title = "【" + name + "】字典修改";
|
||||
DictAPI.getFormData(id).then((data) => {
|
||||
Object.assign(formData, data);
|
||||
});
|
||||
} else {
|
||||
dialog.title = "新增字典类型";
|
||||
}
|
||||
}
|
||||
|
||||
/** 字典类型表单提交 */
|
||||
function handleSubmit() {
|
||||
// 提交字典表单
|
||||
function handleSubmitClick() {
|
||||
dataFormRef.value.validate((isValid: boolean) => {
|
||||
console.log("isValid", isValid);
|
||||
if (isValid) {
|
||||
loading.value = false;
|
||||
const dictTypeId = formData.id;
|
||||
if (dictTypeId) {
|
||||
DictAPI.updateDictType(dictTypeId, formData)
|
||||
loading.value = true;
|
||||
const id = formData.id;
|
||||
if (id) {
|
||||
DictAPI.update(id, formData)
|
||||
.then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
} else {
|
||||
DictAPI.addDictType(formData)
|
||||
DictAPI.add(formData)
|
||||
.then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
@@ -258,63 +323,57 @@ function handleSubmit() {
|
||||
});
|
||||
}
|
||||
|
||||
/** 关闭字典类型弹窗 */
|
||||
function closeDialog() {
|
||||
/** 关闭字典弹窗 */
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
/** 重置字典类型表单 */
|
||||
function resetForm() {
|
||||
dataFormRef.value.resetFields();
|
||||
dataFormRef.value.clearValidate();
|
||||
|
||||
formData.id = undefined;
|
||||
formData.status = 1;
|
||||
}
|
||||
|
||||
/** 删除字典类型 */
|
||||
function handleDelete(dictTypeId?: number) {
|
||||
const dictTypeIds = [dictTypeId || ids.value].join(",");
|
||||
if (!dictTypeIds) {
|
||||
/**
|
||||
* 删除字典
|
||||
*
|
||||
* @param id 字典ID
|
||||
*/
|
||||
function handleDeleteClick(id?: number) {
|
||||
const attrGroupIds = [id || ids.value].join(",");
|
||||
if (!attrGroupIds) {
|
||||
ElMessage.warning("请勾选删除项");
|
||||
return;
|
||||
}
|
||||
|
||||
ElMessageBox.confirm("确认删除已选中的数据项?", "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(() => {
|
||||
DictAPI.deleteDictTypes(dictTypeIds).then(() => {
|
||||
DictAPI.deleteByIds(attrGroupIds).then(() => {
|
||||
ElMessage.success("删除成功");
|
||||
handleResetQuery();
|
||||
handleResetClick();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const dictDataDialog = reactive({
|
||||
title: "",
|
||||
visible: false,
|
||||
});
|
||||
|
||||
const selectedDictType = reactive({ typeCode: "", typeName: "" }); // 当前选中的字典类型
|
||||
|
||||
/** 打开字典数据弹窗 */
|
||||
function openDictDialog(row: DictTypePageVO) {
|
||||
dictDataDialog.visible = true;
|
||||
dictDataDialog.title = "【" + row.name + "】字典数据";
|
||||
|
||||
selectedDictType.typeCode = row.code;
|
||||
selectedDictType.typeName = row.name;
|
||||
// 新增字典
|
||||
function handleAddAttrClick() {
|
||||
formData.dictItems = formData.dictItems ?? [];
|
||||
formData.dictItems.push({ sort: 1, status: 1 });
|
||||
}
|
||||
|
||||
/** 关闭字典数据弹窗 */
|
||||
function closeDictDialog() {
|
||||
dictDataDialog.visible = false;
|
||||
// 删除字典
|
||||
function handleDeleteAttrClick(index: number) {
|
||||
if (formData.dictItems && formData.dictItems.length > 0) {
|
||||
formData.dictItems.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.el-form--inline .el-form-item {
|
||||
margin-top: 18px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<el-button
|
||||
v-hasPerm="['sys:menu:add']"
|
||||
type="success"
|
||||
@click="handleDialogOpen(0)"
|
||||
@click="handleOpenDialog(0)"
|
||||
>
|
||||
<template #icon><i-ep-plus /></template>
|
||||
新增</el-button
|
||||
@@ -84,11 +84,18 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="路由名称"
|
||||
align="left"
|
||||
width="150"
|
||||
prop="routeName"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
label="路由路径"
|
||||
align="left"
|
||||
width="150"
|
||||
prop="path"
|
||||
prop="routePath"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
@@ -122,7 +129,7 @@
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleDialogOpen(scope.row.id)"
|
||||
@click.stop="handleOpenDialog(scope.row.id)"
|
||||
>
|
||||
<i-ep-plus />新增
|
||||
</el-button>
|
||||
@@ -132,7 +139,7 @@
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click.stop="handleDialogOpen(undefined, scope.row.id)"
|
||||
@click.stop="handleOpenDialog(undefined, scope.row.id)"
|
||||
>
|
||||
<i-ep-edit />编辑
|
||||
</el-button>
|
||||
@@ -150,19 +157,17 @@
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog
|
||||
<el-drawer
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
width="1000px"
|
||||
@close="closeDialog"
|
||||
@close="handleCloseDialog"
|
||||
size="50%"
|
||||
>
|
||||
<el-form
|
||||
ref="menuFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="160px"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="父级菜单" prop="parentId">
|
||||
<el-tree-select
|
||||
@@ -196,7 +201,10 @@
|
||||
label="外链地址"
|
||||
prop="path"
|
||||
>
|
||||
<el-input v-model="formData.path" placeholder="请输入外链完整路径" />
|
||||
<el-input
|
||||
v-model="formData.routePath"
|
||||
placeholder="请输入外链完整路径"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
@@ -204,8 +212,29 @@
|
||||
formData.type == MenuTypeEnum.CATALOG ||
|
||||
formData.type == MenuTypeEnum.MENU
|
||||
"
|
||||
label=""
|
||||
prop="path"
|
||||
prop="routeName"
|
||||
>
|
||||
<template #label>
|
||||
<div>
|
||||
路由名称
|
||||
<el-tooltip placement="bottom" effect="light">
|
||||
<template #content>
|
||||
如果需要开启缓存,需保证页面 defineOptions 中的 name
|
||||
与此处一致,建议使用驼峰。
|
||||
</template>
|
||||
<i-ep-QuestionFilled class="inline-block" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="formData.routeName" placeholder="User" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
v-if="
|
||||
formData.type == MenuTypeEnum.CATALOG ||
|
||||
formData.type == MenuTypeEnum.MENU
|
||||
"
|
||||
prop="routePath"
|
||||
>
|
||||
<template #label>
|
||||
<div>
|
||||
@@ -222,10 +251,10 @@
|
||||
</template>
|
||||
<el-input
|
||||
v-if="formData.type == MenuTypeEnum.CATALOG"
|
||||
v-model="formData.path"
|
||||
v-model="formData.routePath"
|
||||
placeholder="system"
|
||||
/>
|
||||
<el-input v-else v-model="formData.path" placeholder="user" />
|
||||
<el-input v-else v-model="formData.routePath" placeholder="user" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item
|
||||
@@ -405,10 +434,10 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
<el-button @click="handleCloseDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -418,8 +447,7 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import MenuAPI from "@/api/menu";
|
||||
import { MenuQuery, MenuForm, MenuVO } from "@/api/menu/model";
|
||||
import MenuAPI, { MenuQuery, MenuForm, MenuVO } from "@/api/menu";
|
||||
import { MenuTypeEnum } from "@/enums/MenuTypeEnum";
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
@@ -458,7 +486,7 @@ const rules = reactive({
|
||||
parentId: [{ required: true, message: "请选择顶级菜单", trigger: "blur" }],
|
||||
name: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
|
||||
type: [{ required: true, message: "请选择菜单类型", trigger: "blur" }],
|
||||
path: [{ required: true, message: "请输入路由路径", trigger: "blur" }],
|
||||
routePath: [{ required: true, message: "请输入路由路径", trigger: "blur" }],
|
||||
component: [{ required: true, message: "请输入组件路径", trigger: "blur" }],
|
||||
visible: [{ required: true, message: "请输入路由路径", trigger: "blur" }],
|
||||
});
|
||||
@@ -496,7 +524,7 @@ function handleRowClick(row: MenuVO) {
|
||||
* @param parentId 父菜单ID
|
||||
* @param menuId 菜单ID
|
||||
*/
|
||||
function handleDialogOpen(parentId?: number, menuId?: number) {
|
||||
function handleOpenDialog(parentId?: number, menuId?: number) {
|
||||
MenuAPI.getOptions()
|
||||
.then((data) => {
|
||||
menuOptions.value = [{ value: 0, label: "顶级菜单", children: data }];
|
||||
@@ -541,13 +569,13 @@ function submitForm() {
|
||||
if (menuId) {
|
||||
MenuAPI.update(menuId, formData.value).then(() => {
|
||||
ElMessage.success("修改成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
} else {
|
||||
MenuAPI.add(formData.value).then(() => {
|
||||
ElMessage.success("新增成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleQuery();
|
||||
});
|
||||
}
|
||||
@@ -577,7 +605,7 @@ function handleDelete(menuId: number) {
|
||||
}
|
||||
|
||||
// 关闭弹窗
|
||||
function closeDialog() {
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
menuFormRef.value.resetFields();
|
||||
menuFormRef.value.clearValidate();
|
||||
|
||||
@@ -195,7 +195,6 @@
|
||||
:data="menuPermOptions"
|
||||
:filter-node-method="handlePermFilter"
|
||||
:default-expand-all="true"
|
||||
:check-on-click-node="true"
|
||||
:check-strictly="!parentChildLinked"
|
||||
class="mt-5"
|
||||
>
|
||||
@@ -222,11 +221,9 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import RoleAPI from "@/api/role";
|
||||
import RoleAPI, { RolePageVO, RoleForm, RolePageQuery } from "@/api/role";
|
||||
import MenuAPI from "@/api/menu";
|
||||
|
||||
import { RolePageVO, RoleForm, RoleQuery } from "@/api/role/model";
|
||||
|
||||
const queryFormRef = ref(ElForm);
|
||||
const roleFormRef = ref(ElForm);
|
||||
const permTreeRef = ref<InstanceType<typeof ElTree>>();
|
||||
@@ -235,7 +232,7 @@ const loading = ref(false);
|
||||
const ids = ref<number[]>([]);
|
||||
const total = ref(0);
|
||||
|
||||
const queryParams = reactive<RoleQuery>({
|
||||
const queryParams = reactive<RolePageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
@@ -315,7 +312,7 @@ function handleOpenDialog(roleId?: number) {
|
||||
}
|
||||
}
|
||||
|
||||
// 角色保存提交
|
||||
/** 提交角色表单 */
|
||||
function handleSubmit() {
|
||||
roleFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
@@ -342,7 +339,7 @@ function handleSubmit() {
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭表单弹窗
|
||||
/** 关闭表单弹窗 */
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
|
||||
@@ -354,7 +351,7 @@ function handleCloseDialog() {
|
||||
formData.status = 1;
|
||||
}
|
||||
|
||||
// 删除角色
|
||||
/** 删除角色 */
|
||||
function handleDelete(roleId?: number) {
|
||||
const roleIds = [roleId || ids.value].join(",");
|
||||
if (!roleIds) {
|
||||
@@ -377,7 +374,7 @@ function handleDelete(roleId?: number) {
|
||||
});
|
||||
}
|
||||
|
||||
// 打开分配权限
|
||||
/** 打开分配菜单权限弹窗 */
|
||||
async function handleOpenAssignPermDialog(row: RolePageVO) {
|
||||
const roleId = row.id;
|
||||
if (roleId) {
|
||||
@@ -404,7 +401,7 @@ async function handleOpenAssignPermDialog(row: RolePageVO) {
|
||||
}
|
||||
}
|
||||
|
||||
// 分配权限提交
|
||||
/** 分配菜单权限提交 */
|
||||
function handleAssignPermSubmit() {
|
||||
const roleId = checkedRole.value.id;
|
||||
if (roleId) {
|
||||
@@ -425,7 +422,7 @@ function handleAssignPermSubmit() {
|
||||
}
|
||||
}
|
||||
|
||||
// 切换菜单树展开状态
|
||||
/** 展开/收缩 菜单权限树 */
|
||||
function togglePermTree() {
|
||||
isExpanded.value = !isExpanded.value;
|
||||
if (permTreeRef.value) {
|
||||
@@ -438,11 +435,12 @@ function togglePermTree() {
|
||||
});
|
||||
}
|
||||
}
|
||||
// 菜单权限筛选
|
||||
watch(permKeywords, (val) => {
|
||||
permTreeRef.value!.filter(val);
|
||||
});
|
||||
|
||||
// 权限筛选
|
||||
/** 权限筛选 */
|
||||
function handlePermFilter(
|
||||
value: string,
|
||||
data: {
|
||||
@@ -453,6 +451,7 @@ function handlePermFilter(
|
||||
return data.label.includes(value);
|
||||
}
|
||||
|
||||
/** 父子菜单节点是否联动 change*/
|
||||
function handleparentChildLinkedChange(val: any) {
|
||||
parentChildLinked.value = val;
|
||||
}
|
||||
|
||||
145
src/views/system/user/components/user-import.vue
Normal file
145
src/views/system/user/components/user-import.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
:align-center="true"
|
||||
title="导入数据"
|
||||
width="600px"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-scrollbar max-height="60vh">
|
||||
<el-form
|
||||
ref="importFormRef"
|
||||
label-width="auto"
|
||||
style="padding-right: var(--el-dialog-padding-primary)"
|
||||
:model="importFormData"
|
||||
:rules="importFormRules"
|
||||
>
|
||||
<el-form-item label="文件名" prop="files">
|
||||
<el-upload
|
||||
class="w-full"
|
||||
ref="uploadRef"
|
||||
v-model:file-list="importFormData.files"
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:drag="true"
|
||||
:limit="1"
|
||||
:auto-upload="false"
|
||||
:on-exceed="handleFileExceed"
|
||||
>
|
||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div class="el-upload__tip">
|
||||
*.xlsx / *.xls
|
||||
<el-link
|
||||
type="primary"
|
||||
icon="download"
|
||||
:underline="false"
|
||||
@click="handleDownloadTemplate"
|
||||
>
|
||||
下载模板
|
||||
</el-link>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-scrollbar>
|
||||
<template #footer>
|
||||
<div style="padding-right: var(--el-dialog-padding-primary)">
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="importFormData.files.length === 0"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
确 定
|
||||
</el-button>
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { type UploadUserFile } from "element-plus";
|
||||
|
||||
import UserAPI from "@/api/user";
|
||||
|
||||
const props = defineProps({
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:visible", "import-success"]);
|
||||
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (val) => {
|
||||
emit("update:visible", val);
|
||||
},
|
||||
});
|
||||
|
||||
const importFormRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
|
||||
const importFormData = reactive<{
|
||||
files: UploadUserFile[];
|
||||
}>({
|
||||
files: [],
|
||||
});
|
||||
|
||||
const importFormRules = {
|
||||
files: [{ required: true, message: "文件不能为空", trigger: "blur" }],
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
dialogVisible.value = false;
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!importFormData.files.length) {
|
||||
ElMessage.warning("请选择文件");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await UserAPI.import(1, importFormData.files[0].raw as File);
|
||||
ElMessage.success("上传成功");
|
||||
emit("import-success");
|
||||
handleClose();
|
||||
} catch (error) {
|
||||
ElMessage.error("上传失败");
|
||||
}
|
||||
};
|
||||
|
||||
const handleFileExceed = () => {
|
||||
ElMessage.warning("只能上传一个文件");
|
||||
};
|
||||
|
||||
const handleDownloadTemplate = () => {
|
||||
UserAPI.downloadTemplate().then((response: any) => {
|
||||
const fileData = response.data;
|
||||
const fileName = decodeURI(
|
||||
response.headers["content-disposition"].split(";")[1].split("=")[1]
|
||||
);
|
||||
const fileType =
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
|
||||
|
||||
const blob = new Blob([fileData], { type: fileType });
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = downloadUrl;
|
||||
downloadLink.download = fileName;
|
||||
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
|
||||
document.body.removeChild(downloadLink);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -59,12 +59,12 @@
|
||||
|
||||
<el-card shadow="never" class="table-container">
|
||||
<template #header>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex-x-between">
|
||||
<div>
|
||||
<el-button
|
||||
v-hasPerm="['sys:user:add']"
|
||||
type="success"
|
||||
@click="openDialog('user-form')"
|
||||
@click="handleOpenDialog()"
|
||||
><i-ep-plus />新增</el-button
|
||||
>
|
||||
<el-button
|
||||
@@ -76,19 +76,10 @@
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<el-dropdown split-button>
|
||||
导入
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="downloadTemplate">
|
||||
<i-ep-download />下载模板</el-dropdown-item
|
||||
<el-button class="ml-3" @click="handleOpenImportDialog"
|
||||
><template #icon><i-ep-upload /></template>导入</el-button
|
||||
>
|
||||
<el-dropdown-item @click="openDialog('user-import')">
|
||||
<i-ep-top />导入数据</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
|
||||
<el-button class="ml-3" @click="handleExport"
|
||||
><template #icon><i-ep-download /></template>导出</el-button
|
||||
>
|
||||
@@ -162,7 +153,7 @@
|
||||
type="primary"
|
||||
size="small"
|
||||
link
|
||||
@click="resetPassword(scope.row)"
|
||||
@click="hancleResetPassword(scope.row)"
|
||||
><i-ep-refresh-left />重置密码</el-button
|
||||
>
|
||||
<el-button
|
||||
@@ -170,12 +161,12 @@
|
||||
type="primary"
|
||||
link
|
||||
size="small"
|
||||
@click="openDialog('user-form', scope.row.id)"
|
||||
@click="handleOpenDialog(scope.row.id)"
|
||||
><i-ep-edit />编辑</el-button
|
||||
>
|
||||
<el-button
|
||||
v-hasPerm="['sys:user:delete']"
|
||||
type="primary"
|
||||
type="danger"
|
||||
link
|
||||
size="small"
|
||||
@click="handleDelete(scope.row.id)"
|
||||
@@ -196,17 +187,15 @@
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 弹窗 -->
|
||||
<el-dialog
|
||||
<!-- 用户表单弹窗 -->
|
||||
<el-drawer
|
||||
v-model="dialog.visible"
|
||||
:title="dialog.title"
|
||||
:width="dialog.width"
|
||||
append-to-body
|
||||
@close="closeDialog"
|
||||
@close="handleCloseDialog"
|
||||
>
|
||||
<!-- 用户新增/编辑表单 -->
|
||||
<el-form
|
||||
v-if="dialog.type === 'user-form'"
|
||||
ref="userFormRef"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
@@ -228,7 +217,7 @@
|
||||
<el-tree-select
|
||||
v-model="formData.deptId"
|
||||
placeholder="请选择所属部门"
|
||||
:data="deptList"
|
||||
:data="deptOptions"
|
||||
filterable
|
||||
check-strictly
|
||||
:render-after-expand="false"
|
||||
@@ -236,13 +225,13 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="性别" prop="gender">
|
||||
<dictionary v-model="formData.gender" type-code="gender" />
|
||||
<dictionary v-model="formData.gender" code="gender" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="角色" prop="roleIds">
|
||||
<el-select v-model="formData.roleIds" multiple placeholder="请选择">
|
||||
<el-option
|
||||
v-for="item in roleList"
|
||||
v-for="item in roleOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
@@ -274,55 +263,19 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 用户导入表单 -->
|
||||
<el-form
|
||||
v-else-if="dialog.type === 'user-import'"
|
||||
:model="importData"
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item label="部门">
|
||||
<el-tree-select
|
||||
v-model="importData.deptId"
|
||||
placeholder="请选择部门"
|
||||
:data="deptList"
|
||||
filterable
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="Excel文件">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
action=""
|
||||
drag
|
||||
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
|
||||
:limit="1"
|
||||
:auto-upload="false"
|
||||
:file-list="importData.fileList"
|
||||
:on-change="handleFileChange"
|
||||
:on-exceed="handleFileExceed"
|
||||
>
|
||||
<el-icon class="el-icon--upload">
|
||||
<i-ep-upload-filled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<div>xls/xlsx files</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 弹窗底部操作按钮 -->
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button type="primary" @click="handleSubmit">确 定</el-button>
|
||||
<el-button @click="closeDialog">取 消</el-button>
|
||||
<el-button @click="handleCloseDialog">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-drawer>
|
||||
|
||||
<!-- 用户导入弹窗 -->
|
||||
<user-import
|
||||
v-model:visible="importDialogVisible"
|
||||
@import-success="handleOpenImportDialogSuccess"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -332,30 +285,28 @@ defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
import UserAPI from "@/api/user";
|
||||
import UserAPI, { UserForm, UserPageQuery, UserPageVO } from "@/api/user";
|
||||
import DeptAPI from "@/api/dept";
|
||||
import RoleAPI from "@/api/role";
|
||||
|
||||
import { UserForm, UserQuery, UserPageVO } from "@/api/user/model";
|
||||
import type { UploadInstance } from "element-plus";
|
||||
import { genFileId } from "element-plus";
|
||||
const queryFormRef = ref(ElForm);
|
||||
const userFormRef = ref(ElForm);
|
||||
|
||||
const queryFormRef = ref(ElForm); // 查询表单
|
||||
const userFormRef = ref(ElForm); // 用户表单
|
||||
const uploadRef = ref<UploadInstance>(); // 上传组件
|
||||
|
||||
const loading = ref(false); // 加载状态
|
||||
const removeIds = ref([]); // 删除用户ID集合 用于批量删除
|
||||
const queryParams = reactive<UserQuery>({
|
||||
const loading = ref(false);
|
||||
const removeIds = ref([]);
|
||||
const total = ref(0);
|
||||
const pageData = ref<UserPageVO[]>();
|
||||
/** 部门下拉选项 */
|
||||
const deptOptions = ref<OptionType[]>();
|
||||
/** 角色下拉选项 */
|
||||
const roleOptions = ref<OptionType[]>();
|
||||
/** 用户查询参数 */
|
||||
const queryParams = reactive<UserPageQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
const dateTimeRange = ref("");
|
||||
const total = ref(0); // 数据总数
|
||||
const pageData = ref<UserPageVO[]>(); // 用户分页数据
|
||||
const deptList = ref<OptionType[]>(); // 部门下拉数据源
|
||||
const roleList = ref<OptionType[]>(); // 角色下拉数据源
|
||||
|
||||
const dateTimeRange = ref("");
|
||||
watch(dateTimeRange, (newVal) => {
|
||||
if (newVal) {
|
||||
queryParams.startTime = newVal[0];
|
||||
@@ -363,27 +314,21 @@ watch(dateTimeRange, (newVal) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 弹窗对象
|
||||
/** 用户弹窗对象 */
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
type: "user-form",
|
||||
width: 800,
|
||||
title: "",
|
||||
});
|
||||
|
||||
/** 导入弹窗显示状态 */
|
||||
const importDialogVisible = ref(false);
|
||||
|
||||
// 用户表单数据
|
||||
const formData = reactive<UserForm>({
|
||||
status: 1,
|
||||
});
|
||||
|
||||
// 用户导入数据
|
||||
const importData = reactive({
|
||||
deptId: undefined,
|
||||
file: undefined,
|
||||
fileList: [],
|
||||
});
|
||||
|
||||
// 校验规则
|
||||
/** 用户表单校验规则 */
|
||||
const rules = reactive({
|
||||
username: [{ required: true, message: "用户名不能为空", trigger: "blur" }],
|
||||
nickname: [{ required: true, message: "用户昵称不能为空", trigger: "blur" }],
|
||||
@@ -436,7 +381,7 @@ function handleSelectionChange(selection: any) {
|
||||
}
|
||||
|
||||
/** 重置密码 */
|
||||
function resetPassword(row: { [key: string]: any }) {
|
||||
function hancleResetPassword(row: { [key: string]: any }) {
|
||||
ElMessageBox.prompt(
|
||||
"请输入用户「" + row.username + "」的新密码",
|
||||
"重置密码",
|
||||
@@ -456,34 +401,18 @@ function resetPassword(row: { [key: string]: any }) {
|
||||
});
|
||||
}
|
||||
|
||||
/** 加载角色下拉数据源 */
|
||||
async function loadRoleOptions() {
|
||||
RoleAPI.getOptions().then((data) => {
|
||||
roleList.value = data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 加载部门下拉数据源 */
|
||||
async function loadDeptOptions() {
|
||||
DeptAPI.getOptions().then((data) => {
|
||||
deptList.value = data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*
|
||||
* @param type 弹窗类型 用户表单:user-form | 用户导入:user-import
|
||||
* @param id 用户ID
|
||||
*/
|
||||
async function openDialog(type: string, id?: number) {
|
||||
async function handleOpenDialog(id?: number) {
|
||||
dialog.visible = true;
|
||||
dialog.type = type;
|
||||
// 加载角色下拉数据源
|
||||
roleOptions.value = await RoleAPI.getOptions();
|
||||
// 加载部门下拉数据源
|
||||
deptOptions.value = await DeptAPI.getOptions();
|
||||
|
||||
if (dialog.type === "user-form") {
|
||||
// 用户表单弹窗
|
||||
await loadDeptOptions();
|
||||
await loadRoleOptions();
|
||||
if (id) {
|
||||
dialog.title = "修改用户";
|
||||
UserAPI.getFormData(id).then((data) => {
|
||||
@@ -492,36 +421,20 @@ async function openDialog(type: string, id?: number) {
|
||||
} else {
|
||||
dialog.title = "新增用户";
|
||||
}
|
||||
} else if (dialog.type === "user-import") {
|
||||
// 用户导入弹窗
|
||||
dialog.title = "导入用户";
|
||||
dialog.width = 600;
|
||||
loadDeptOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭弹窗
|
||||
*
|
||||
* @param type 弹窗类型 用户表单:user-form | 用户导入:user-import
|
||||
*/
|
||||
function closeDialog() {
|
||||
/** 关闭弹窗 */
|
||||
function handleCloseDialog() {
|
||||
dialog.visible = false;
|
||||
if (dialog.type === "user-form") {
|
||||
userFormRef.value.resetFields();
|
||||
userFormRef.value.clearValidate();
|
||||
|
||||
formData.id = undefined;
|
||||
formData.status = 1;
|
||||
} else if (dialog.type === "user-import") {
|
||||
importData.file = undefined;
|
||||
importData.fileList = [];
|
||||
}
|
||||
}
|
||||
|
||||
/** 表单提交 */
|
||||
const handleSubmit = useThrottleFn(() => {
|
||||
if (dialog.type === "user-form") {
|
||||
userFormRef.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
const userId = formData.id;
|
||||
@@ -530,7 +443,7 @@ const handleSubmit = useThrottleFn(() => {
|
||||
UserAPI.update(userId, formData)
|
||||
.then(() => {
|
||||
ElMessage.success("修改用户成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
@@ -538,28 +451,13 @@ const handleSubmit = useThrottleFn(() => {
|
||||
UserAPI.add(formData)
|
||||
.then(() => {
|
||||
ElMessage.success("新增用户成功");
|
||||
closeDialog();
|
||||
handleCloseDialog();
|
||||
handleResetQuery();
|
||||
})
|
||||
.finally(() => (loading.value = false));
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (dialog.type === "user-import") {
|
||||
if (!importData?.deptId) {
|
||||
ElMessage.warning("请选择部门");
|
||||
return false;
|
||||
}
|
||||
if (!importData?.file) {
|
||||
ElMessage.warning("上传Excel文件不能为空");
|
||||
return false;
|
||||
}
|
||||
UserAPI.import(importData?.deptId, importData?.file).then((data) => {
|
||||
ElMessage.success("导入用户成功");
|
||||
closeDialog();
|
||||
handleResetQuery();
|
||||
});
|
||||
}
|
||||
}, 3000);
|
||||
|
||||
/** 删除用户 */
|
||||
@@ -581,44 +479,14 @@ function handleDelete(id?: number) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** 下载导入模板 */
|
||||
function downloadTemplate() {
|
||||
UserAPI.downloadTemplate().then((response: any) => {
|
||||
const fileData = response.data;
|
||||
const fileName = decodeURI(
|
||||
response.headers["content-disposition"].split(";")[1].split("=")[1]
|
||||
);
|
||||
const fileType =
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8";
|
||||
|
||||
const blob = new Blob([fileData], { type: fileType });
|
||||
const downloadUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
const downloadLink = document.createElement("a");
|
||||
downloadLink.href = downloadUrl;
|
||||
downloadLink.download = fileName;
|
||||
|
||||
document.body.appendChild(downloadLink);
|
||||
downloadLink.click();
|
||||
|
||||
document.body.removeChild(downloadLink);
|
||||
window.URL.revokeObjectURL(downloadUrl);
|
||||
});
|
||||
/** 打开导入弹窗 */
|
||||
function handleOpenImportDialog() {
|
||||
importDialogVisible.value = true;
|
||||
}
|
||||
|
||||
/** Excel文件 Change */
|
||||
function handleFileChange(file: any) {
|
||||
importData.file = file.raw;
|
||||
}
|
||||
|
||||
/** Excel文件 Exceed */
|
||||
function handleFileExceed(files: any) {
|
||||
uploadRef.value!.clearFiles();
|
||||
const file = files[0];
|
||||
file.uid = genFileId();
|
||||
uploadRef.value!.handleStart(file);
|
||||
importData.file = file;
|
||||
/** 导入用户成功 */
|
||||
function handleOpenImportDialogSuccess() {
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 导出用户 */
|
||||
|
||||
@@ -25,9 +25,8 @@
|
||||
"jsxFragmentFactory": "Fragment"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.vue",
|
||||
"src/typings/**/*.d.ts",
|
||||
"src/types/**/*.d.ts",
|
||||
"mock/**/*.ts",
|
||||
"vite.config.ts"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user