fix(monitor): 修复定时任务权限标识错误

refactor(base_crud): 优化数据权限过滤逻辑

fix(user): 修正用户详情部门查询错误

feat(menu): 添加菜单标题字段并优化路由更新

style(auth): 优化登录页面背景样式

fix(profile): 修复表单样式问题

perf(redis): 优化缓存清除逻辑

fix(role): 移除默认角色操作限制

chore: 清理无用导入和注释
This commit is contained in:
zhangtao
2025-08-10 02:46:59 +08:00
parent 51f678bc42
commit 603bbdb3e9
22 changed files with 152 additions and 85 deletions
@@ -25,7 +25,7 @@ router = APIRouter(route_class=OperationLogRoute)
@router.get("/detail/{id}", summary="获取定时任务详情", description="获取定时任务详情")
async def get_obj_detail_controller(
id: int = Path(..., description="定时任务ID"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:query"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:query"]))
) -> JSONResponse:
result_dict = await JobService.get_job_detail_service(id=id, auth=auth)
logger.info(f"获取定时任务详情成功 {id}")
@@ -35,7 +35,7 @@ async def get_obj_detail_controller(
async def get_obj_list_controller(
page: PaginationQueryParams = Depends(),
search: JobQueryParams = Depends(),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:query"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:query"]))
) -> JSONResponse:
result_dict_list = await JobService.get_job_list_service(auth=auth, search=search, order_by=page.order_by)
result_dict = await PaginationService.get_page_obj(data_list= result_dict_list, page_no= page.page_no, page_size = page.page_size)
@@ -45,7 +45,7 @@ async def get_obj_list_controller(
@router.post("/create", summary="创建定时任务", description="创建定时任务")
async def create_obj_controller(
data: JobCreateSchema,
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:create"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:create"]))
) -> JSONResponse:
result_dict = await JobService.create_job_service(auth=auth, data=data)
logger.info(f"创建定时任务成功: {result_dict}")
@@ -54,7 +54,7 @@ async def create_obj_controller(
@router.put("/update", summary="修改定时任务", description="修改定时任务")
async def update_obj_controller(
data: JobUpdateSchema,
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:update"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:update"]))
) -> JSONResponse:
result_dict = await JobService.update_job_service(auth=auth, data=data)
logger.info(f"修改定时任务成功: {result_dict}")
@@ -63,7 +63,7 @@ async def update_obj_controller(
@router.delete("/delete", summary="删除定时任务", description="删除定时任务")
async def delete_obj_controller(
ids: list[int] = Body(..., description="ID列表"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:delete"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:delete"]))
) -> JSONResponse:
await JobService.delete_job_service(auth=auth, ids=ids)
logger.info(f"删除定时任务成功: {id}")
@@ -72,7 +72,7 @@ async def delete_obj_controller(
@router.post('/export', summary="导出定时任务", description="导出定时任务")
async def export_obj_list_controller(
search: JobQueryParams = Depends(),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:export"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:export"]))
) -> StreamingResponse:
# 获取全量数据
result_dict_list = await JobService.get_job_list_service(search=search, auth=auth)
@@ -89,7 +89,7 @@ async def export_obj_list_controller(
@router.delete("/clear", summary="清空定时任务日志", description="清空定时任务日志")
async def clear_obj_log_controller(
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:delete"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:delete"]))
) -> JSONResponse:
await JobService.clear_job_service(auth=auth)
logger.info(f"清空定时任务成功")
@@ -99,13 +99,13 @@ async def clear_obj_log_controller(
async def option_obj_controller(
id: int = Body(..., description="定时任务ID"),
option: int = Body(..., description="操作类型 1: 暂停 2: 恢复 3: 重启"),
auth: AuthSchema = Depends(AuthPermission(permissions=["system:job:update"]))
auth: AuthSchema = Depends(AuthPermission(permissions=["monitor:job:update"]))
) -> JSONResponse:
await JobService.option_job_service(auth=auth, id=id, option=option)
logger.info(f"操作定时任务成功: {id}")
return SuccessResponse(msg="操作定时任务成功")
@router.get("/log", summary="获取定时任务日志", description="获取定时任务日志", dependencies=[Depends(AuthPermission(permissions=["system:job:query"]))])
@router.get("/log", summary="获取定时任务日志", description="获取定时任务日志", dependencies=[Depends(AuthPermission(permissions=["monitor:job:query"]))])
async def get_job_log_controller():
data = [
{
@@ -35,7 +35,7 @@ class ConfigModel(ModelBase):
creator = relationship(
"UserModel",
foreign_keys=creator_id,
lazy="joined",
lazy="selectin",
post_update=True,
uselist=False
)
@@ -3,7 +3,6 @@
from datetime import datetime
from sqlalchemy import Boolean, Column, String, Integer, DateTime, ForeignKey, Text
from sqlalchemy.orm import relationship
from typing import Optional, List
from app.core.base_model import ModelBase
@@ -4,7 +4,7 @@ from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
from app.core.base_schema import BaseSchema
from app.core.validator import DateTimeStr
class PositionCreateSchema(BaseModel):
"""岗位创建模型"""
@@ -22,3 +22,11 @@ class PositionUpdateSchema(PositionCreateSchema):
class PositionOutSchema(PositionCreateSchema, BaseSchema):
"""岗位信息响应模型"""
model_config = ConfigDict(from_attributes=True)
class PositionOptionsOut(PositionCreateSchema):
model_config = ConfigDict(from_attributes=True)
id: int = Field(description="主键ID")
created_at: DateTimeStr = Field(description="创建时间")
updated_at: DateTimeStr = Field(description="更新时间")
@@ -7,7 +7,7 @@ from app.api.v1.schemas.system.dept_schema import DeptOutSchema
from app.api.v1.schemas.system.menu_schema import MenuOutSchema
from app.core.base_schema import BaseSchema
from app.core.validator import role_permission_request_validator
from app.core.validator import DateTimeStr
class RoleCreateSchema(BaseModel):
"""角色创建模型"""
@@ -43,3 +43,13 @@ class RoleOutSchema(RoleCreateSchema, BaseSchema):
menus: List[MenuOutSchema] = Field(default_factory=list, description='角色菜单列表')
depts: List[DeptOutSchema] = Field(default_factory=list, description='角色部门列表')
class RoleOptionsOut(RoleCreateSchema):
model_config = ConfigDict(from_attributes=True)
id: int = Field(description="主键ID")
created_at: DateTimeStr = Field(description="创建时间")
updated_at: DateTimeStr = Field(description="更新时间")
menus: List[MenuOutSchema] = Field(default_factory=list, description='角色菜单列表')
depts: List[DeptOutSchema] = Field(default_factory=list, description='角色部门列表')
@@ -3,8 +3,8 @@
from typing import Optional, List
from pydantic import BaseModel, ConfigDict, Field, EmailStr, field_validator
from app.api.v1.schemas.system.position_schema import PositionOutSchema
from app.api.v1.schemas.system.role_schema import RoleOutSchema
from app.api.v1.schemas.system.position_schema import PositionOptionsOut
from app.api.v1.schemas.system.role_schema import RoleOptionsOut
from app.api.v1.schemas.system.dept_schema import DeptOutSchema
from app.core.validator import DateTimeStr, mobile_validator
from app.core.base_schema import BaseSchema
@@ -76,6 +76,7 @@ class UserCreateSchema(CurrentUserUpdateSchema):
class UserUpdateSchema(UserCreateSchema):
"""更新"""
model_config = ConfigDict(from_attributes=True, exclude={"password"})
id: int = Field(..., description="主键ID")
@@ -86,5 +87,5 @@ class UserOutSchema(UserCreateSchema, BaseSchema):
last_login: Optional[DateTimeStr] = Field(default=None, description="最后登录时间")
dept_name: Optional[str] = Field(default=None, description='部门名称')
dept: Optional[DeptOutSchema] = Field(default=None, description='部门')
roles: List[RoleOutSchema] = Field(default=[], description='角色')
positions: List[PositionOutSchema] = Field(default=[], description='岗位')
roles: Optional[List[RoleOptionsOut]] = Field(default=[], description='角色')
positions: Optional[List[PositionOptionsOut]] = Field(default=[], description='岗位')
@@ -116,8 +116,11 @@ class CacheService:
:param redis: Redis对象
:return: 操作缓存响应信息
"""
cache_keys = await RedisCURD(redis).get_keys
cache_keys = await RedisCURD(redis).get_keys()
if cache_keys:
await RedisCURD(redis).delete(*cache_keys)
return True
# 避免清除所有的缓存,而采用上面的方式,只清除本系统内指定的所有缓存
# return await RedisCURD(redis).clear()
@@ -57,8 +57,8 @@ class OnlineService:
async def clear_online_service(cls, redis: Redis) -> bool:
"""强制下线在线用户"""
# 删除 token
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:*")
await RedisCURD(redis).delete(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:*")
await RedisCURD(redis).clear(f"{RedisInitKeyConfig.ACCESS_TOKEN.key}:*")
await RedisCURD(redis).clear(f"{RedisInitKeyConfig.REFRESH_TOKEN.key}:*")
logger.info(f"清除所有在线用户会话成功")
return True
@@ -176,7 +176,7 @@ class UserService:
raise CustomException(msg="用户不存在")
# 获取部门名称
if user.dept_id:
dept = await DeptCRUD(auth).get_by_id_crud(id=user.dept_id)
dept = await DeptCRUD(auth).get_by_id_crud(id=auth.user.dept_id)
user.dept_name = dept.name if dept else None
user_dict = UserOutSchema.model_validate(user).model_dump()
@@ -189,7 +189,7 @@ class UserService:
MenuOutSchema.model_validate(menu).model_dump()
for role in auth.user.roles
for menu in role.menus
if menu.status and menu.type in [1, 2]
if menu.status and menu.type in [1, 2, 4]
]
user_dict["menus"] = menus
return user_dict
@@ -259,7 +259,7 @@ class UserService:
# 更新密码
new_password_hash = PwdUtil.set_password_hash(password=data.password)
new_user = await UserCRUD(auth).change_password_crud(id=user.id, password_hash=new_password_hash)
new_user = await UserCRUD(auth).change_password_crud(id=data.id, password_hash=new_password_hash)
return UserOutSchema.model_validate(new_user).model_dump()
@classmethod
+1 -1
View File
@@ -192,7 +192,7 @@ class Settings(BaseSettings):
UPLOAD_MACHINE: str = 'A' # 上传机器标识
ALLOWED_EXTENSIONS: list[str] = [ # 允许的文件类型
# 图片
'.bmp', '.gif', '.jpg', '.jpeg', '.png', '.ico',
'.bmp', '.gif', '.jpg', '.jpeg', '.png', '.ico', '.svg',
# 文档
'.csv', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.html', '.htm', '.txt', '.pdf',
# 压缩包
+26 -21
View File
@@ -55,8 +55,13 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
if hasattr(self.model, "creator"):
sql = sql.options(selectinload(self.model.creator))
# sql = await self.__filter_permissions(sql)
result: Result = await self.db.execute(sql)
obj = result.scalars().unique().first()
# if not obj:
# raise CustomException(msg="该信息不存在")
return obj
except Exception as e:
raise CustomException(msg=f"获取查询失败: {str(e)}")
@@ -82,6 +87,9 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
.where(*conditions)
.order_by(*self.__order_by(order))
.distinct())
# 预加载creator关系
if hasattr(self.model, "creator"):
sql = sql.options(selectinload(self.model.creator))
sql = await self.__filter_permissions(sql)
result: Result = await self.db.execute(sql)
return result.scalars().unique().all()
@@ -219,14 +227,18 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
async def __filter_permissions(self, sql: Select[Any]) -> Select[Any]:
"""过滤数据权限"""
# 1. 如果模型没有creator字段,则不需要过滤
# 如果不需要检查数据权限,则直接返回
if not self.current_user or not self.auth.check_data_scope:
return sql
# 1. 如果模型没有创建人creator字段,则不需要权限判断
if not hasattr(self.model, "creator"):
return sql
sql = sql.options(selectinload(self.model.creator))
# 2. 超级管理员可以查看所有数据
if not self.current_user or self.current_user.is_superuser:
if self.current_user.is_superuser:
return sql
# 3. 如果用户没有部门或角色,则只能查看自己的数据
@@ -243,23 +255,21 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
# 3: 本部门及以下数据权限
# 4: 全部数据权限
# 5: 自定义数据权限
# 5. 处理各种数据权限范围
# 获取当前用户所绑定角色的数据权限范围
for role in self.current_user.roles:
# 如果有全部数据权限,直接返回所有数据
if role.data_scope == 4:
return sql
for dept in role.depts:
dept_ids.add(dept.id)
data_scopes.add(role.data_scope)
# 如果是自定义权限,添加自定义部门
if role.data_scope == 5:
dept_ids.update({dept.id for dept in role.depts})
conditions = []
if 4 in data_scopes:
# 4、全部数据权限
return sql
# 5. 处理各种数据权限范围
if 1 in data_scopes:
# 1、仅本人数据
conditions.append(self.model.creator_id == self.current_user.id)
return sql.where(self.model.creator_id == self.current_user.id)
if 2 in data_scopes:
# 2、本部门数据
@@ -270,16 +280,11 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
dept_objs = await CRUDBase(DeptModel, self.auth).list()
id_map = get_child_id_map(dept_objs)
dept_child_ids = get_child_recursion(id=self.current_user.dept_id, id_map=id_map)
dept_ids.update(dept_child_ids)
for child_id in dept_child_ids:
dept_ids.add(child_id)
if dept_ids:
conditions.append(self.model.creator.has(UserModel.dept_id.in_(list(dept_ids))))
# 6. 组合所有条件
if conditions:
return sql.where(and_(*conditions))
return sql.where(self.model.creator_id == self.current_user.id)
# 5、自定义权限
return sql.where(self.model.creator.has(UserModel.dept_id.in_(list(dept_ids))))
def __order_by(self, order_by: List[Dict[str, str]]) -> List[ColumnElement]:
"""
+6 -1
View File
@@ -103,8 +103,13 @@ export interface MenuForm {
hidden?: boolean;
always_show?: boolean;
title?: string;
params?: { key: string; value: string; }[];
params?: KeyValue[];
affix?: boolean;
status?: boolean;
description?: string;
}
export interface KeyValue {
key: string;
value: string;
}
+3 -3
View File
@@ -67,7 +67,7 @@ export const UserAPI = {
},
getUserDetail(query: number) {
return request<ApiResponse>({
return request<ApiResponse<UserInfo>>({
url: `/system/user/detail/${query}`,
method: "get",
});
@@ -246,9 +246,9 @@ export interface UserForm {
dept_id?: number;
dept_name?: string;
role_ids?: number[];
roleNames?: string;
roleNames?: string[];
position_ids?: number[];
positionNames?: string;
positionNames?: string[];
password?: string;
gender?: number;
email?: string;
+3 -2
View File
@@ -26,7 +26,7 @@ export const useUserStore = defineStore("user", {
// 获取用户信息
async getUserInfo() {
const response = await UserAPI.getCurrentUserInfo();
const routers = response.data.data.menus;
const routers: MenuTable[] = response.data.data.menus || [];
delete response.data.data.menus;
this.setRoute(routers);
this.basicInfo = { ...this.basicInfo, ...response.data.data };
@@ -37,7 +37,8 @@ export const useUserStore = defineStore("user", {
this.basicInfo = info;
},
setRoute(routers: any) {
// 设置路由
setRoute(routers: MenuTable[]) {
this.routeList = routers;
this.hasGetRoute = true;
},
+17 -8
View File
@@ -122,18 +122,18 @@
<span>基本设置</span>
</template>
<div>
<el-form ref="ruleFormRef" :model="infoFormState" :rules="rules" :inline="true" label-suffix=":">
<el-form ref="ruleFormRef" :model="infoFormState" :rules="rules" :inline="true" label-width="80px" label-suffix=":">
<el-form-item label="姓名" name="name">
<el-input v-model="infoFormState.name" placeholder="请输入姓名" prefix-icon="User" clearable />
<el-input v-model="infoFormState.name" placeholder="请输入姓名" prefix-icon="User" clearable style="width: 240px;" />
</el-form-item>
<el-form-item label="手机号" name="mobile">
<el-input v-model="infoFormState.mobile" placeholder="请输入手机号码" prefix-icon="Phone" clearable />
<el-input v-model="infoFormState.mobile" placeholder="请输入手机号码" prefix-icon="Phone" clearable style="width: 240px;" />
</el-form-item>
<el-form-item label="邮箱" name="email">
<el-input v-model="infoFormState.email" placeholder="请输入邮箱" prefix-icon="Message" clearable />
<el-input v-model="infoFormState.email" placeholder="请输入邮箱" prefix-icon="Message" clearable style="width: 240px;" />
</el-form-item>
<el-form-item label="性别" name="gender">
@@ -159,9 +159,9 @@
<span>安全设置</span>
</template>
<div>
<el-form ref="ruleFormRef" :model="passwordFormState" :rules="resetPasswordRules" label-suffix=":">
<el-form ref="ruleFormRef" :model="passwordFormState" :rules="resetPasswordRules" label-width="80px" label-suffix=":">
<el-form-item label="当前密码" name="old_password">
<el-input v-model.trim="passwordFormState.old_password" :placeholder="t('login.password')" type="password" show-password clearable>
<el-input v-model.trim="passwordFormState.old_password" :placeholder="t('login.password')" type="password" show-password clearable style="width: 240px;">
<template #prefix>
<Lock />
</template>
@@ -169,7 +169,7 @@
</el-form-item>
<el-form-item label="新密码" name="new_password">
<el-input v-model.trim="passwordFormState.new_password" type="password" :placeholder="t('login.newPassword')" show-password clearable>
<el-input v-model.trim="passwordFormState.new_password" type="password" :placeholder="t('login.newPassword')" show-password clearable style="width: 240px;">
<template #prefix>
<Key />
</template>
@@ -177,7 +177,7 @@
</el-form-item>
<el-form-item label="确认新密码" name="confirm_password">
<el-input v-model.trim="passwordFormState.confirm_password" type="password" :placeholder="t('login.message.password.confirm')" show-password clearable>
<el-input v-model.trim="passwordFormState.confirm_password" type="password" :placeholder="t('login.message.password.confirm')" show-password clearable style="width: 240px;">
<template #prefix>
<Check />
</template>
@@ -507,4 +507,13 @@ onMounted(async () => {
}
}
}
/* 修复表单输入框清除按钮导致的宽度变化问题 */
.el-input {
transition: none !important;
}
.el-input__wrapper {
transition: none !important;
}
</style>
-1
View File
@@ -879,7 +879,6 @@ const handleClear = () => {
try {
loading.value = true;
await JobAPI.clearJob();
ElMessage.success("清空成功");
handleResetQuery();
} catch (error: any) {
console.error(error);
@@ -101,10 +101,10 @@
</template>
<script setup lang="ts">
import type { FormInstance } from "element-plus";
import { LocationQuery, RouteLocationRaw, useRoute } from "vue-router";
import { LocationQuery, RouteLocationRaw, useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n";
import { onActivated, onMounted, watch } from "vue";
import AuthAPI, {type LoginFormData, type CaptchaInfo } from "@/api/system/auth";
import router from "@/router";
import { useAppStore, useUserStore } from "@/store";
import CommonWrapper from "@/components/CommonWrapper/index.vue";
@@ -113,9 +113,27 @@ const userStore = useUserStore();
const appStore = useAppStore();
const route = useRoute();
const router = useRouter();
// 组件挂载时获取验证码
onMounted(() => getCaptcha());
// 组件激活时获取验证码(适用于KeepAlive缓存的情况)
onActivated(() => {
getCaptcha();
// 重置登录表单
loginForm.captcha = '';
});
// 监听路由变化,确保每次进入登录页面都有最新验证码
watch(
() => route.fullPath,
() => {
getCaptcha();
loginForm.captcha = '';
}
);
const loginFormRef = ref<FormInstance>();
const loading = ref(false);
// 是否大写锁定
+3 -10
View File
@@ -1,5 +1,5 @@
<template>
<div class="login-container">
<div class="login-container" :style="{ 'background-image': configStore.configData?.sys_login_background?.config_value ? `url(${configStore.configData.sys_login_background.config_value})` : '/background.svg' }">
<!-- 右侧切换主题语言按钮 -->
<div class="action-bar">
<el-tooltip :content="t('login.themeToggle')" placement="bottom">
@@ -93,17 +93,10 @@ onMounted(() => {
}
//
.login-container::before {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 100%;
height: 100%;
content: "";
background: url("/background.svg");
.login-container {
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
}
.action-bar {
+11 -2
View File
@@ -242,6 +242,10 @@
<el-input v-model="formData.name" placeholder="请输入菜单名称" />
</el-form-item>
<el-form-item label="菜单标题" prop="title">
<el-input v-model="formData.title" placeholder="请输入菜单标题" />
</el-form-item>
<el-form-item label="菜单类型" prop="type">
<el-radio-group v-model="formData.type" @change="handleMenuTypeChange">
<el-radio :value="MenuTypeEnum.CATALOG">目录</el-radio>
@@ -255,7 +259,7 @@
<el-input v-model="formData.route_path" placeholder="请输入外链完整路径" />
</el-form-item>
<el-form-item v-if="formData.type == MenuTypeEnum.MENU" prop="routeName">
<el-form-item prop="routeName">
<template #label>
<div class="flex-y-center">
路由名称
@@ -464,6 +468,7 @@ defineOptions({
});
import { useAppStore } from "@/store/modules/app.store";
import { useUserStore } from "@/store/modules/user.store";
import { DeviceEnum } from "@/enums/settings/device.enum";
import MenuAPI, { MenuPageQuery, MenuForm, MenuTable } from "@/api/system/menu";
@@ -471,6 +476,7 @@ import { MenuTypeEnum } from "@/enums/system/menu.enum";
import { formatTree, listToTree } from "@/utils/common";
const appStore = useAppStore();
const userStore = useUserStore();
const queryFormRef = ref();
const dataFormRef = ref();
@@ -514,7 +520,7 @@ const formData = reactive<MenuForm>({
hidden: false,
always_show: false,
title: '',
params: [] as { key: string; value: string }[],
params: undefined,
affix: false,
status: true,
description: undefined,
@@ -716,6 +722,7 @@ async function handleSubmit() {
if (id) {
try {
await MenuAPI.updateMenu(formData)
await userStore.getUserInfo();
dialogVisible.visible = false;
resetForm();
handleResetQuery();
@@ -727,6 +734,7 @@ async function handleSubmit() {
} else {
try {
await MenuAPI.createMenu(formData)
await userStore.getUserInfo();
dialogVisible.visible = false;
resetForm();
handleResetQuery();
@@ -750,6 +758,7 @@ async function handleDelete(ids: number[]) {
try {
loading.value = true;
await MenuAPI.deleteMenu(ids);
await userStore.getUserInfo();
handleResetQuery();
} catch (error: any) {
console.error(error);
+1 -2
View File
@@ -146,8 +146,7 @@
size="small"
link
icon="document"
@click="scope.row.id === 1 ? ElMessage.warning('系统默认角色,不可操作') : handleOpenDialog('detail', scope.row.id)"
:disabled="scope.row.id === 1"
@click="handleOpenDialog('detail', scope.row.id)"
>详情</el-button>
<el-button
type="primary"
+12 -4
View File
@@ -257,7 +257,7 @@
</el-select>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-form-item label="手机号" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
</el-form-item>
@@ -281,7 +281,7 @@
</el-select>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-form-item label="密码" prop="password" v-if="dialogVisible.type === 'create'">
<el-input v-model="formData.password" placeholder="请输入密码" type="password" show-password clearable />
</el-form-item>
@@ -548,6 +548,8 @@ async function handleCloseDialog() {
//
async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: number) {
dialogVisible.type = type;
//
rules.password[0].required = type === 'create';
if (id) {
const response = await UserAPI.getUserDetail(id);
if (type === 'detail') {
@@ -556,6 +558,9 @@ async function handleOpenDialog(type: 'create' | 'update' | 'detail', id?: numbe
} else if (type === 'update') {
dialogVisible.title = "修改用户";
Object.assign(formData, response.data.data);
// ID
formData.role_ids = (response.data.data.roles || []).map(item => item.id as number);
formData.position_ids = (response.data.data.positions || []).map(item => item.id as number);
}
} else {
dialogVisible.title = "新增用户";
@@ -596,8 +601,11 @@ async function handleSubmit() {
// (deatil\create\update)
const id = formData.id;
if (id) {
try {
await UserAPI.updateUser({ id, ...formData })
try {
//
const updateData = { id, ...formData };
delete updateData.password;
await UserAPI.updateUser(updateData)
dialogVisible.visible = false;
resetForm();
handleCloseDialog();
+1 -1
View File
@@ -47,7 +47,7 @@ export default defineConfig(({ mode }: ConfigEnv) => {
target: env.VITE_API_BASE_URL, // 代理目标地址:https://后端地址
secure: false, // 请求是否https
changeOrigin: true, // 是否跨域
// rewrite: (path) => path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
rewrite: (path) => path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
},
},
},