重构角色和权限相关DTO,替换RoleDto为RoleRespDto,并更新相关服务和控制器逻辑

This commit is contained in:
Chuck1sn
2025-06-16 10:57:35 +08:00
parent 7b8ef54e7b
commit ea10b156e3
34 changed files with 543 additions and 405 deletions

View File

@@ -15,7 +15,6 @@ import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.IdentityAccessService; import com.zl.mjga.service.IdentityAccessService;
import io.minio.MinioClient; import io.minio.MinioClient;
import io.minio.PutObjectArgs; import io.minio.PutObjectArgs;
import io.minio.errors.*;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.security.Principal; import java.security.Principal;
@@ -118,7 +117,7 @@ public class IdentityAccessController {
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)") @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).WRITE_USER_ROLE_PERMISSION)")
@GetMapping("/role") @GetMapping("/role")
RoleDto queryRoleWithPermission(@RequestParam Long roleId) { RoleRespDto queryRoleWithPermission(@RequestParam Long roleId) {
return identityAccessService.queryUniqueRoleWithPermission(roleId); return identityAccessService.queryUniqueRoleWithPermission(roleId);
} }
@@ -145,7 +144,7 @@ public class IdentityAccessController {
@PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)") @PreAuthorize("hasAuthority(T(com.zl.mjga.model.urp.EPermission).READ_USER_ROLE_PERMISSION)")
@GetMapping("/roles") @GetMapping("/roles")
@ResponseStatus(HttpStatus.OK) @ResponseStatus(HttpStatus.OK)
PageResponseDto<List<RoleDto>> queryRoles( PageResponseDto<List<RoleRespDto>> queryRoles(
@ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) { @ModelAttribute PageRequestDto pageRequestDto, @ModelAttribute RoleQueryDto roleQueryDto) {
return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto); return identityAccessService.pageQueryRole(pageRequestDto, roleQueryDto);
} }

View File

@@ -1,5 +1,6 @@
package com.zl.mjga.dto.urp; package com.zl.mjga.dto.urp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
@AllArgsConstructor @AllArgsConstructor
@@ -7,8 +8,16 @@ import lombok.*;
@Data @Data
@Builder @Builder
public class PermissionRespDto { public class PermissionRespDto {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Long id; private Long id;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String code; private String code;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String name; private String name;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean isBound; private Boolean isBound;
} }

View File

@@ -1,5 +1,6 @@
package com.zl.mjga.dto.urp; package com.zl.mjga.dto.urp;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import lombok.*; import lombok.*;
@@ -8,10 +9,18 @@ import lombok.*;
@NoArgsConstructor @NoArgsConstructor
@Data @Data
@Builder @Builder
public class RoleDto { public class RoleRespDto {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Long id; private Long id;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String code; private String code;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String name; private String name;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean isBound; private Boolean isBound;
@Builder.Default List<PermissionRespDto> permissions = new LinkedList<>(); @Builder.Default List<PermissionRespDto> permissions = new LinkedList<>();
} }

View File

@@ -1,6 +1,7 @@
package com.zl.mjga.dto.urp; package com.zl.mjga.dto.urp;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -13,7 +14,11 @@ import lombok.*;
@Data @Data
@Builder @Builder
public class UserRolePermissionDto { public class UserRolePermissionDto {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Long id; private Long id;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private String username; private String username;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@@ -21,9 +26,12 @@ public class UserRolePermissionDto {
private String avatar; private String avatar;
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Boolean enable; private Boolean enable;
@Builder.Default private List<RoleDto> roles = new LinkedList<>();
@Builder.Default private List<RoleRespDto> roles = new LinkedList<>();
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private OffsetDateTime createTime; private OffsetDateTime createTime;
public Set<PermissionRespDto> getPermissions() { public Set<PermissionRespDto> getPermissions() {

View File

@@ -5,7 +5,7 @@ import static org.jooq.impl.DSL.*;
import com.zl.mjga.dto.PageRequestDto; import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.urp.PermissionRespDto; import com.zl.mjga.dto.urp.PermissionRespDto;
import com.zl.mjga.dto.urp.RoleDto; import com.zl.mjga.dto.urp.RoleRespDto;
import com.zl.mjga.dto.urp.UserQueryDto; import com.zl.mjga.dto.urp.UserQueryDto;
import com.zl.mjga.dto.urp.UserRolePermissionDto; import com.zl.mjga.dto.urp.UserRolePermissionDto;
import java.util.List; import java.util.List;
@@ -102,7 +102,7 @@ public class UserRepository extends UserDao {
r -> r.map((record) -> record.into(PermissionRespDto.class))) r -> r.map((record) -> record.into(PermissionRespDto.class)))
.as("permissions")) .as("permissions"))
.from(USER.role())) .from(USER.role()))
.convertFrom(r -> r.map((record) -> record.into(RoleDto.class))) .convertFrom(r -> r.map((record) -> record.into(RoleRespDto.class)))
.as("roles")) .as("roles"))
.from(USER) .from(USER)
.where(USER.ID.eq(userId)) .where(USER.ID.eq(userId))

View File

@@ -80,17 +80,17 @@ public class IdentityAccessService {
return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId); return userRepository.fetchUniqueUserDtoWithNestedRolePermissionBy(userId);
} }
public PageResponseDto<List<RoleDto>> pageQueryRole( public PageResponseDto<List<RoleRespDto>> pageQueryRole(
PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) { PageRequestDto pageRequestDto, RoleQueryDto roleQueryDto) {
Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto); Result<Record> roleRecords = roleRepository.pageFetchBy(pageRequestDto, roleQueryDto);
if (roleRecords.isEmpty()) { if (roleRecords.isEmpty()) {
return PageResponseDto.empty(); return PageResponseDto.empty();
} }
List<RoleDto> roleDtoList = List<RoleRespDto> roleRespDtoList =
roleRecords.stream() roleRecords.stream()
.map( .map(
record -> { record -> {
return RoleDto.builder() return RoleRespDto.builder()
.id(record.getValue("id", Long.class)) .id(record.getValue("id", Long.class))
.code(record.getValue("code", String.class)) .code(record.getValue("code", String.class))
.name(record.getValue("name", String.class)) .name(record.getValue("name", String.class))
@@ -103,17 +103,17 @@ public class IdentityAccessService {
}) })
.toList(); .toList();
return new PageResponseDto<>( return new PageResponseDto<>(
roleRecords.get(0).getValue("total_role", Integer.class), roleDtoList); roleRecords.get(0).getValue("total_role", Integer.class), roleRespDtoList);
} }
public @Nullable RoleDto queryUniqueRoleWithPermission(Long roleId) { public @Nullable RoleRespDto queryUniqueRoleWithPermission(Long roleId) {
Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId); Result<Record> roleWithPermissionRecords = roleRepository.fetchUniqueRoleWithPermission(roleId);
if (roleWithPermissionRecords.isEmpty()) { if (roleWithPermissionRecords.isEmpty()) {
return null; return null;
} }
RoleDto roleDto = createRbacDtoRolePart(roleWithPermissionRecords); RoleRespDto roleRespDto = createRbacDtoRolePart(roleWithPermissionRecords);
setCurrentRolePermission(roleDto, roleWithPermissionRecords); setCurrentRolePermission(roleRespDto, roleWithPermissionRecords);
return roleDto; return roleRespDto;
} }
public PageResponseDto<List<PermissionRespDto>> pageQueryPermission( public PageResponseDto<List<PermissionRespDto>> pageQueryPermission(
@@ -199,12 +199,12 @@ public class IdentityAccessService {
.toList()); .toList());
} }
private void setCurrentRolePermission(RoleDto roleDto, List<Record> roleResult) { private void setCurrentRolePermission(RoleRespDto roleRespDto, List<Record> roleResult) {
if (roleResult.get(0).getValue(PERMISSION.ID) != null) { if (roleResult.get(0).getValue(PERMISSION.ID) != null) {
roleResult.forEach( roleResult.forEach(
(record) -> { (record) -> {
PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record); PermissionRespDto permissionRespDto = createRbacDtoPermissionPart(record);
roleDto.getPermissions().add(permissionRespDto); roleRespDto.getPermissions().add(permissionRespDto);
}); });
} }
} }
@@ -217,12 +217,12 @@ public class IdentityAccessService {
return permissionRespDto; return permissionRespDto;
} }
private RoleDto createRbacDtoRolePart(List<Record> roleResult) { private RoleRespDto createRbacDtoRolePart(List<Record> roleResult) {
RoleDto roleDto = new RoleDto(); RoleRespDto roleRespDto = new RoleRespDto();
roleDto.setId(roleResult.get(0).getValue(ROLE.ID)); roleRespDto.setId(roleResult.get(0).getValue(ROLE.ID));
roleDto.setCode(roleResult.get(0).getValue(ROLE.CODE)); roleRespDto.setCode(roleResult.get(0).getValue(ROLE.CODE));
roleDto.setName(roleResult.get(0).getValue(ROLE.NAME)); roleRespDto.setName(roleResult.get(0).getValue(ROLE.NAME));
return roleDto; return roleRespDto;
} }
public boolean isRoleDuplicate(String roleCode, String name) { public boolean isRoleDuplicate(String roleCode, String name) {

View File

@@ -178,14 +178,14 @@ class UserRolePermissionMvcTest {
stubRoleQueryDto.setRoleId(stubRoleId); stubRoleQueryDto.setRoleId(stubRoleId);
stubRoleQueryDto.setRoleCode(stubRoleCode); stubRoleQueryDto.setRoleCode(stubRoleCode);
stubRoleQueryDto.setRoleName(stubRoleName); stubRoleQueryDto.setRoleName(stubRoleName);
RoleDto stubRoleDto = new RoleDto(); RoleRespDto stubRoleRespDto = new RoleRespDto();
stubRoleDto.setId(1L); stubRoleRespDto.setId(1L);
stubRoleDto.setName(stubRoleName); stubRoleRespDto.setName(stubRoleName);
stubRoleDto.setCode(stubRoleCode); stubRoleRespDto.setCode(stubRoleCode);
stubRoleDto.setPermissions( stubRoleRespDto.setPermissions(
List.of(new PermissionRespDto(1L, "9VWU1nmU89zEVH", "9VWU1nmU89zEVH", false))); List.of(new PermissionRespDto(1L, "9VWU1nmU89zEVH", "9VWU1nmU89zEVH", false)));
when(identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), stubRoleQueryDto)) when(identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), stubRoleQueryDto))
.thenReturn(new PageResponseDto<>(1, List.of(stubRoleDto))); .thenReturn(new PageResponseDto<>(1, List.of(stubRoleRespDto)));
mockMvc mockMvc
.perform( .perform(

View File

@@ -112,19 +112,19 @@ class UserRolePermissionUnitTest {
DSL.field("total_user", Integer.class)) DSL.field("total_user", Integer.class))
.values(stubUserId2, stubUserName2, stubUserPassword2, true, null, 2)); .values(stubUserId2, stubUserName2, stubUserPassword2, true, null, 2));
UserRolePermissionDto mockUserRolePermissionDto1 = new UserRolePermissionDto(); UserRolePermissionDto mockUserRolePermissionDto1 = new UserRolePermissionDto();
RoleDto mockRoleDto = new RoleDto(); RoleRespDto mockRoleRespDto = new RoleRespDto();
mockRoleDto.setId(stubRoleId); mockRoleRespDto.setId(stubRoleId);
mockRoleDto.setCode(stubRoleCode); mockRoleRespDto.setCode(stubRoleCode);
mockRoleDto.setName(stubRoleName); mockRoleRespDto.setName(stubRoleName);
PermissionRespDto permissionRespDto = new PermissionRespDto(); PermissionRespDto permissionRespDto = new PermissionRespDto();
permissionRespDto.setId(stubPermissionId); permissionRespDto.setId(stubPermissionId);
permissionRespDto.setCode(stubPermissionCode); permissionRespDto.setCode(stubPermissionCode);
permissionRespDto.setName(stubPermissionName); permissionRespDto.setName(stubPermissionName);
mockRoleDto.getPermissions().add(permissionRespDto); mockRoleRespDto.getPermissions().add(permissionRespDto);
mockUserRolePermissionDto1.setId(stubUserId1); mockUserRolePermissionDto1.setId(stubUserId1);
mockUserRolePermissionDto1.setUsername(stubUserName1); mockUserRolePermissionDto1.setUsername(stubUserName1);
mockUserRolePermissionDto1.setPassword(stubUserPassword1); mockUserRolePermissionDto1.setPassword(stubUserPassword1);
mockUserRolePermissionDto1.getRoles().add(mockRoleDto); mockUserRolePermissionDto1.getRoles().add(mockRoleRespDto);
UserRolePermissionDto mockUserRolePermissionDto2 = new UserRolePermissionDto(); UserRolePermissionDto mockUserRolePermissionDto2 = new UserRolePermissionDto();
mockUserRolePermissionDto2.setId(stubUserId2); mockUserRolePermissionDto2.setId(stubUserId2);
@@ -202,7 +202,7 @@ class UserRolePermissionUnitTest {
mockResult.setId(stubRoleId); mockResult.setId(stubRoleId);
mockResult.setRoles( mockResult.setRoles(
List.of( List.of(
new RoleDto( new RoleRespDto(
stubRoleId, stubRoleId,
stubRoleName, stubRoleName,
stubRoleCode, stubRoleCode,
@@ -245,12 +245,12 @@ class UserRolePermissionUnitTest {
when(roleRepository.pageFetchBy(any(PageRequestDto.class), any(RoleQueryDto.class))) when(roleRepository.pageFetchBy(any(PageRequestDto.class), any(RoleQueryDto.class)))
.thenReturn(mockRoleResult); .thenReturn(mockRoleResult);
RoleQueryDto roleQueryDto = new RoleQueryDto(); RoleQueryDto roleQueryDto = new RoleQueryDto();
PageResponseDto<List<RoleDto>> pageResult = PageResponseDto<List<RoleRespDto>> pageResult =
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto); identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
assertThat(pageResult.getTotal()).isEqualTo(0L); assertThat(pageResult.getTotal()).isEqualTo(0L);
roleQueryDto.setUserId(1L); roleQueryDto.setUserId(1L);
PageResponseDto<List<RoleDto>> pageResult2 = PageResponseDto<List<RoleRespDto>> pageResult2 =
identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto); identityAccessService.pageQueryRole(PageRequestDto.of(1, 5), roleQueryDto);
assertThat(pageResult2.getTotal()).isEqualTo(0L); assertThat(pageResult2.getTotal()).isEqualTo(0L);
} }

View File

@@ -289,7 +289,7 @@
"content": { "content": {
"*/*": { "*/*": {
"schema": { "schema": {
"$ref": "#/components/schemas/RoleDto" "$ref": "#/components/schemas/RoleRespDto"
} }
} }
} }
@@ -1031,7 +1031,7 @@
"content": { "content": {
"*/*": { "*/*": {
"schema": { "schema": {
"$ref": "#/components/schemas/PageResponseDtoListRoleDto" "$ref": "#/components/schemas/PageResponseDtoListRoleRespDto"
} }
} }
} }
@@ -1718,6 +1718,12 @@
} }
}, },
"PermissionRespDto": { "PermissionRespDto": {
"required": [
"code",
"id",
"isBound",
"name"
],
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
@@ -1735,7 +1741,13 @@
} }
} }
}, },
"RoleDto": { "RoleRespDto": {
"required": [
"code",
"id",
"isBound",
"name"
],
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
@@ -1760,6 +1772,12 @@
} }
}, },
"UserRolePermissionDto": { "UserRolePermissionDto": {
"required": [
"createTime",
"enable",
"id",
"username"
],
"type": "object", "type": "object",
"properties": { "properties": {
"id": { "id": {
@@ -1782,7 +1800,7 @@
"roles": { "roles": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/components/schemas/RoleDto" "$ref": "#/components/schemas/RoleRespDto"
} }
}, },
"createTime": { "createTime": {
@@ -1832,7 +1850,7 @@
} }
} }
}, },
"PageResponseDtoListRoleDto": { "PageResponseDtoListRoleRespDto": {
"type": "object", "type": "object",
"properties": { "properties": {
"total": { "total": {
@@ -1842,7 +1860,7 @@
"data": { "data": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/components/schemas/RoleDto" "$ref": "#/components/schemas/RoleRespDto"
} }
} }
} }

View File

@@ -779,29 +779,29 @@ export interface components {
}; };
PermissionRespDto: { PermissionRespDto: {
/** Format: int64 */ /** Format: int64 */
id?: number; id: number;
code?: string; code: string;
name?: string; name: string;
isBound?: boolean; isBound: boolean;
}; };
RoleDto: { RoleRespDto: {
/** Format: int64 */ /** Format: int64 */
id?: number; id: number;
code?: string; code: string;
name?: string; name: string;
isBound?: boolean; isBound: boolean;
permissions?: components["schemas"]["PermissionRespDto"][]; permissions?: components["schemas"]["PermissionRespDto"][];
}; };
UserRolePermissionDto: { UserRolePermissionDto: {
/** Format: int64 */ /** Format: int64 */
id?: number; id: number;
username?: string; username: string;
password?: string; password?: string;
avatar?: string; avatar?: string;
enable?: boolean; enable: boolean;
roles?: components["schemas"]["RoleDto"][]; roles?: components["schemas"]["RoleRespDto"][];
/** Format: date-time */ /** Format: date-time */
createTime?: string; createTime: string;
permissions?: components["schemas"]["PermissionRespDto"][]; permissions?: components["schemas"]["PermissionRespDto"][];
}; };
RoleQueryDto: { RoleQueryDto: {
@@ -815,10 +815,10 @@ export interface components {
/** @enum {string} */ /** @enum {string} */
bindState?: "BIND" | "UNBIND" | "ALL"; bindState?: "BIND" | "UNBIND" | "ALL";
}; };
PageResponseDtoListRoleDto: { PageResponseDtoListRoleRespDto: {
/** Format: int64 */ /** Format: int64 */
total?: number; total?: number;
data?: components["schemas"]["RoleDto"][]; data?: components["schemas"]["RoleRespDto"][];
}; };
PermissionQueryDto: { PermissionQueryDto: {
/** Format: int64 */ /** Format: int64 */
@@ -1113,7 +1113,7 @@ export interface operations {
[name: string]: unknown; [name: string]: unknown;
}; };
content: { content: {
"*/*": components["schemas"]["RoleDto"]; "*/*": components["schemas"]["RoleRespDto"];
}; };
}; };
}; };
@@ -1750,7 +1750,7 @@ export interface operations {
[name: string]: unknown; [name: string]: unknown;
}; };
content: { content: {
"*/*": components["schemas"]["PageResponseDtoListRoleDto"]; "*/*": components["schemas"]["PageResponseDtoListRoleRespDto"];
}; };
}; };
}; };

View File

@@ -10,10 +10,10 @@
import { getUserAvatarUrl } from "@/utils/avatarUtil"; import { getUserAvatarUrl } from "@/utils/avatarUtil";
import { computed } from "vue"; import { computed } from "vue";
const { const {
src = "", src = "",
alt = "用户头像", alt = "用户头像",
size = "md" size = "md",
} = defineProps<{ } = defineProps<{
src?: string; src?: string;
alt?: string; alt?: string;
@@ -37,7 +37,7 @@ const processedSrc = computed(() => {
} }
if (src === "/trump.jpg") { if (src === "/trump.jpg") {
return src; return src;
} }
return getUserAvatarUrl(src); return getUserAvatarUrl(src);
}); });
</script> </script>

View File

@@ -2,7 +2,7 @@
<nav class="flex mb-4" aria-label="Breadcrumb"> <nav class="flex mb-4" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 sm:space-x-2 text-sm"> <ol class="inline-flex items-center space-x-1 sm:space-x-2 text-sm">
<li class="inline-flex items-center"> <li class="inline-flex items-center">
<RouterLink :to="{ name: RouteName.HOME }" <RouterLink :to="Routes.HOME.fullPath()"
class="inline-flex items-center font-medium text-gray-500 hover:text-blue-600"> class="inline-flex items-center font-medium text-gray-500 hover:text-blue-600">
<svg class="w-3.5 h-3.5 mr-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" <svg class="w-3.5 h-3.5 mr-1.5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor"
viewBox="0 0 20 20"> viewBox="0 0 20 20">
@@ -30,7 +30,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import { computed } from "vue"; import { computed } from "vue";
import type { RouteLocationRaw } from "vue-router"; import type { RouteLocationRaw } from "vue-router";

View File

@@ -53,14 +53,14 @@
<li> <li>
<button @click="() => { <button @click="() => {
userDropDownMenu?.toggle() userDropDownMenu?.toggle()
router.push(`${RoutePath.DASHBOARD}/${RoutePath.SETTINGS}`) router.push(Routes.SETTINGS.fullPath())
}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 " }" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 "
role="menuitem">Settings</button> role="menuitem">Settings</button>
</li> </li>
<li> <li>
<button @click="() => { <button @click="() => {
userDropDownMenu?.toggle() userDropDownMenu?.toggle()
router.push(RouteName.USERVIEW) router.push(Routes.USERVIEW.withParams({}))
}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 " }" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 "
role="menuitem">Dashboard</button> role="menuitem">Dashboard</button>
</li> </li>
@@ -93,7 +93,7 @@ import { Dropdown, type DropdownInterface, initFlowbite } from "flowbite";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import useUserAuth from "../composables/auth/useUserAuth"; import useUserAuth from "../composables/auth/useUserAuth";
import { RouteName, RoutePath } from "../router/constants"; import { Routes } from "../router/constants";
import Avatar from "./Avatar.vue"; import Avatar from "./Avatar.vue";
import AiChatIcon from "./icons/AiChatIcon.vue"; import AiChatIcon from "./icons/AiChatIcon.vue";
@@ -113,7 +113,7 @@ const { signOut } = useUserAuth();
const router = useRouter(); const router = useRouter();
const handleLogoutClick = () => { const handleLogoutClick = () => {
signOut(); signOut();
router.push(RoutePath.LOGIN); router.push(Routes.LOGIN.path);
}; };
onMounted(() => { onMounted(() => {

View File

@@ -52,7 +52,7 @@ import type { components } from "../api/types/schema";
const alertStore = useAlertStore(); const alertStore = useAlertStore();
const { role, onSubmit } = defineProps<{ const { role, onSubmit } = defineProps<{
role?: components["schemas"]["RoleDto"]; role?: components["schemas"]["RoleRespDto"];
closeModal: () => void; closeModal: () => void;
onSubmit: (data: RoleUpsertModel) => Promise<void>; onSubmit: (data: RoleUpsertModel) => Promise<void>;
}>(); }>();

View File

@@ -28,7 +28,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { RoutePath } from "@/router/constants"; import { Routes } from "@/router/constants";
import { initFlowbite } from "flowbite"; import { initFlowbite } from "flowbite";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { RouterLink, useRoute } from "vue-router"; import { RouterLink, useRoute } from "vue-router";
@@ -73,42 +73,42 @@ defineExpose({
const menuItems = [ const menuItems = [
{ {
title: "用户管理", title: "用户管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}`, path: Routes.USERVIEW.fullPath(),
icon: UsersIcon, icon: UsersIcon,
}, },
{ {
title: "角色管理", title: "角色管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.ROLEVIEW}`, path: Routes.ROLEVIEW.fullPath(),
icon: RoleIcon, icon: RoleIcon,
}, },
{ {
title: "权限管理", title: "权限管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.PERMISSIONVIEW}`, path: Routes.PERMISSIONVIEW.fullPath(),
icon: PermissionIcon, icon: PermissionIcon,
}, },
{ {
title: "部门管理", title: "部门管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.DEPARTMENTVIEW}`, path: Routes.DEPARTMENTVIEW.fullPath(),
icon: DepartmentIcon, icon: DepartmentIcon,
}, },
{ {
title: "岗位管理", title: "岗位管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.POSITIONVIEW}`, path: Routes.POSITIONVIEW.fullPath(),
icon: PositionIcon, icon: PositionIcon,
}, },
{ {
title: "个人中心", title: "个人中心",
path: `${RoutePath.DASHBOARD}/${RoutePath.SETTINGS}`, path: Routes.SETTINGS.fullPath(),
icon: SettingsIcon, icon: SettingsIcon,
}, },
{ {
title: "定时任务", title: "定时任务",
path: `${RoutePath.DASHBOARD}/${RoutePath.SCHEDULERVIEW}`, path: Routes.SCHEDULERVIEW.fullPath(),
icon: SchedulerIcon, icon: SchedulerIcon,
}, },
{ {
title: "大模型管理", title: "大模型管理",
path: `${RoutePath.DASHBOARD}/${RoutePath.LLMCONFIGVIEW}`, path: Routes.LLMCONFIGVIEW.fullPath(),
icon: LlmConfigIcon, icon: LlmConfigIcon,
}, },
]; ];

View File

@@ -4,8 +4,8 @@ import type { components } from "../../api/types/schema";
export const useRolesQuery = () => { export const useRolesQuery = () => {
const total = ref<number>(0); const total = ref<number>(0);
const roles = ref<components["schemas"]["RoleDto"][]>(); const roles = ref<components["schemas"]["RoleRespDto"][]>();
const roleWithDetail = ref<components["schemas"]["RoleDto"]>(); const roleWithDetail = ref<components["schemas"]["RoleRespDto"]>();
const getRoleWithDetail = async (roleId: number) => { const getRoleWithDetail = async (roleId: number) => {
const { data } = await client.GET("/iam/role", { const { data } = await client.GET("/iam/role", {

View File

@@ -1,56 +1,156 @@
export enum RoutePath { import type { RouteLocationRaw } from "vue-router";
HOME = "/",
LOGIN = "/login",
DASHBOARD = "/dashboard",
GLOBAL_NOTFOUND = "/:pathMatch(.*)*",
NOTFOUND = ":pathMatch(.*)*",
OVERVIEW = "overview",
USERVIEW = "users",
ROLEVIEW = "roles",
BINDROLEVIEW = "bind-roles/:userId",
BINDPERMISSIONVIEW = "bind-permissions/:roleId",
BINDDEPARTMENTVIEW = "bind-departments/:userId",
BINDPOSITIONVIEW = "bind-positions/:userId",
PERMISSIONVIEW = "permissions",
DEPARTMENTVIEW = "departments",
POSITIONVIEW = "positions",
CREATEUSERVIEW = "create-user",
LLMCONFIGVIEW = "llm/config",
SCHEDULERVIEW = "scheduler",
UPSERTUSERVIEW = "upsert-user",
UPSERTROLEVIEW = "upsert-role",
UPSERTPERMISSIONVIEW = "upsert-permission",
UPSERTDEPARTMENTVIEW = "upsert-department",
UPSERTPOSITIONVIEW = "upsert-position",
SETTINGS = "settings",
}
export enum RouteName { export type RouteConfig = {
HOME = "home", path: string;
LOGIN = "login", name: string;
DASHBOARD = "dashboard", fullPath: () => string;
OVERVIEW = "overview", withParams: <T extends Record<string, string | number>>(
USERVIEW = "users", params: T,
ROLEVIEW = "roles", ) => RouteLocationRaw;
BINDROLEVIEW = "bind-roles", };
BINDPERMISSIONVIEW = "bind-permissions",
BINDDEPARTMENTVIEW = "bind-departments", // 基础路由
BINDPOSITIONVIEW = "bind-positions", export const BaseRoutes = {
PERMISSIONVIEW = "permissions", HOME: {
DEPARTMENTVIEW = "departments", path: "/",
POSITIONVIEW = "positions", name: "home",
CREATEUSERVIEW = "create-user", fullPath: () => "/",
LLMCONFIGVIEW = "llm/config", withParams: () => ({ name: "home" }),
SCHEDULERVIEW = "scheduler", },
UPSERTUSERVIEW = "upsert-user", LOGIN: {
UPSERTROLEVIEW = "upsert-role", path: "/login",
UPSERTPERMISSIONVIEW = "upsert-permission", name: "login",
UPSERTDEPARTMENTVIEW = "upsert-department", fullPath: () => "/login",
UPSERTPOSITIONVIEW = "upsert-position", withParams: () => ({ name: "login" }),
SETTINGS = "settings", },
NOTFOUND = "notfound", DASHBOARD: {
GLOBAL_NOTFOUND = "global-notfound", path: "/dashboard",
} name: "dashboard",
fullPath: () => "/dashboard",
withParams: () => ({ name: "dashboard" }),
},
NOTFOUND: {
path: ":pathMatch(.*)*",
name: "notfound",
fullPath: () => "/dashboard/:pathMatch(.*)*",
withParams: () => ({ name: "notfound" }),
},
GLOBAL_NOTFOUND: {
path: "/:pathMatch(.*)*",
name: "global-notfound",
fullPath: () => "/:pathMatch(.*)*",
withParams: () => ({ name: "global-notfound" }),
},
} as const;
// 仪表盘子路由
export const DashboardRoutes = {
OVERVIEW: {
path: "overview",
name: "overview",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/overview`,
withParams: () => ({ name: "overview" }),
},
SETTINGS: {
path: "settings",
name: "settings",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/settings`,
withParams: () => ({ name: "settings" }),
},
} as const;
// 用户管理相关路由
export const UserRoutes = {
USERVIEW: {
path: "users",
name: "users",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/users`,
withParams: () => ({ name: "users" }),
},
ROLEVIEW: {
path: "roles",
name: "roles",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/roles`,
withParams: () => ({ name: "roles" }),
},
BINDROLEVIEW: {
path: "bind-roles/:userId",
name: "bind-roles",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/bind-roles/:userId`,
withParams: <T extends { userId: string | number }>(params: T) => ({
name: "bind-roles",
params: { userId: params.userId.toString() },
}),
},
BINDPERMISSIONVIEW: {
path: "bind-permissions/:roleId",
name: "bind-permissions",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/bind-permissions/:roleId`,
withParams: <T extends { roleId: string | number }>(params: T) => ({
name: "bind-permissions",
params: { roleId: params.roleId.toString() },
}),
},
BINDDEPARTMENTVIEW: {
path: "bind-departments/:userId",
name: "bind-departments",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/bind-departments/:userId`,
withParams: <T extends { userId: string | number }>(params: T) => ({
name: "bind-departments",
params: { userId: params.userId.toString() },
}),
},
BINDPOSITIONVIEW: {
path: "bind-positions/:userId",
name: "bind-positions",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/bind-positions/:userId`,
withParams: <T extends { userId: string | number }>(params: T) => ({
name: "bind-positions",
params: { userId: params.userId.toString() },
}),
},
PERMISSIONVIEW: {
path: "permissions",
name: "permissions",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/permissions`,
withParams: () => ({ name: "permissions" }),
},
DEPARTMENTVIEW: {
path: "departments",
name: "departments",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/departments`,
withParams: () => ({ name: "departments" }),
},
POSITIONVIEW: {
path: "positions",
name: "positions",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/positions`,
withParams: () => ({ name: "positions" }),
},
} as const;
// AI相关路由
export const AiRoutes = {
LLMCONFIGVIEW: {
path: "llm/config",
name: "llm/config",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/llm/config`,
withParams: () => ({ name: "llm/config" }),
},
SCHEDULERVIEW: {
path: "scheduler",
name: "scheduler",
fullPath: () => `${BaseRoutes.DASHBOARD.path}/scheduler`,
withParams: () => ({ name: "scheduler" }),
},
} as const;
export const Routes = {
...BaseRoutes,
...DashboardRoutes,
...UserRoutes,
...AiRoutes,
} as const;
export enum ERole { export enum ERole {
ADMIN = "ADMIN", ADMIN = "ADMIN",

View File

@@ -1,19 +1,19 @@
import useAlertStore from "@/composables/store/useAlertStore";
import useUserStore from "@/composables/store/useUserStore"; import useUserStore from "@/composables/store/useUserStore";
import type { NavigationGuard, Router } from "vue-router"; import type { NavigationGuard, Router } from "vue-router";
import type { RouteMeta } from "../types/router"; import type { RouteMeta } from "../types/router";
import { RoutePath } from "./constants"; import { Routes } from "./constants";
import useAlertStore from "@/composables/store/useAlertStore";
export const authGuard: NavigationGuard = (to) => { export const authGuard: NavigationGuard = (to) => {
const userStore = useUserStore(); const userStore = useUserStore();
if (to.meta.requiresAuth && !userStore.user) { if (to.meta.requiresAuth && !userStore.user) {
return { return {
path: RoutePath.LOGIN, path: Routes.LOGIN.path,
query: { redirect: to.fullPath }, query: { redirect: to.fullPath },
}; };
} }
if (to.path === RoutePath.LOGIN && userStore.user) { if (to.path === Routes.LOGIN.path && userStore.user) {
return { path: `${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}` }; return { path: `${Routes.DASHBOARD.path}/${Routes.USERVIEW.path}` };
} }
}; };

View File

@@ -2,20 +2,20 @@ import { createRouter, createWebHistory } from "vue-router";
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { setupGuards } from "./guards"; import { setupGuards } from "./guards";
import { Routes } from "./constants";
import authRoutes from "./modules/auth"; import authRoutes from "./modules/auth";
import dashboardRoutes from "./modules/dashboard"; import dashboardRoutes from "./modules/dashboard";
import errorRoutes from "./modules/error"; import errorRoutes from "./modules/error";
import { RouteName, RoutePath } from "./constants";
const routes: RouteRecordRaw[] = [ const routes: RouteRecordRaw[] = [
dashboardRoutes, dashboardRoutes,
...authRoutes, ...authRoutes,
...errorRoutes, ...errorRoutes,
{ {
path: RoutePath.HOME, path: Routes.HOME.path,
name: RouteName.HOME, name: Routes.HOME.name,
redirect: { redirect: {
path: `${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}`, path: `${Routes.DASHBOARD.path}/${Routes.USERVIEW.path}`,
}, },
}, },
]; ];
@@ -27,7 +27,7 @@ const router = createRouter({
router.onError((err) => { router.onError((err) => {
console.error("router err:", err); console.error("router err:", err);
router.push(RouteName.USERVIEW); router.push(Routes.USERVIEW.name);
return false; return false;
}); });

View File

@@ -1,10 +1,10 @@
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { EPermission, RouteName, RoutePath } from "../constants"; import { EPermission, Routes } from "../constants";
const aiRoutes: RouteRecordRaw[] = [ const aiRoutes: RouteRecordRaw[] = [
{ {
path: RoutePath.LLMCONFIGVIEW, path: Routes.LLMCONFIGVIEW.path,
name: RouteName.LLMCONFIGVIEW, name: Routes.LLMCONFIGVIEW.name,
component: () => import("@/views/LlmConfigView.vue"), component: () => import("@/views/LlmConfigView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,

View File

@@ -1,17 +1,17 @@
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { RouteName, RoutePath } from "../constants"; import { Routes } from "../constants";
const authRoutes: RouteRecordRaw[] = [ const authRoutes: RouteRecordRaw[] = [
{ {
path: RoutePath.HOME, path: Routes.HOME.path,
name: RouteName.HOME, name: Routes.HOME.name,
redirect: { redirect: {
name: RouteName.LOGIN, name: Routes.LOGIN.name,
}, },
}, },
{ {
path: RoutePath.LOGIN, path: Routes.LOGIN.path,
name: RouteName.LOGIN, name: Routes.LOGIN.name,
component: () => import("../../views/LoginView.vue"), component: () => import("../../views/LoginView.vue"),
}, },
]; ];

View File

@@ -1,28 +1,28 @@
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import Dashboard from "../../components/Dashboard.vue"; import Dashboard from "../../components/Dashboard.vue";
import { EPermission, ERole, RouteName, RoutePath } from "../constants"; import { EPermission, ERole, Routes } from "../constants";
import userManagementRoutes from "./user";
import aiRoutes from "./ai"; import aiRoutes from "./ai";
import userManagementRoutes from "./user";
const dashboardRoutes: RouteRecordRaw = { const dashboardRoutes: RouteRecordRaw = {
path: RoutePath.DASHBOARD, path: Routes.DASHBOARD.path,
name: RouteName.DASHBOARD, name: Routes.DASHBOARD.name,
component: Dashboard, component: Dashboard,
meta: { meta: {
requiresAuth: true, requiresAuth: true,
}, },
children: [ children: [
{ {
path: RoutePath.OVERVIEW, path: Routes.OVERVIEW.path,
name: RouteName.OVERVIEW, name: Routes.OVERVIEW.name,
component: () => import("@/views/OverView.vue"), component: () => import("@/views/OverView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
}, },
}, },
{ {
path: RoutePath.SETTINGS, path: Routes.SETTINGS.path,
name: RouteName.SETTINGS, name: Routes.SETTINGS.name,
component: () => import("@/views/SettingsView.vue"), component: () => import("@/views/SettingsView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -31,13 +31,13 @@ const dashboardRoutes: RouteRecordRaw = {
...userManagementRoutes, ...userManagementRoutes,
...aiRoutes, ...aiRoutes,
{ {
path: RoutePath.NOTFOUND, path: Routes.NOTFOUND.path,
name: RouteName.NOTFOUND, name: Routes.NOTFOUND.name,
component: () => import("@/views/NotFound.vue"), component: () => import("@/views/NotFound.vue"),
}, },
{ {
path: RoutePath.SCHEDULERVIEW, path: Routes.SCHEDULERVIEW.path,
name: RouteName.SCHEDULERVIEW, name: Routes.SCHEDULERVIEW.name,
component: () => import("@/views/SchedulerView.vue"), component: () => import("@/views/SchedulerView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -45,8 +45,8 @@ const dashboardRoutes: RouteRecordRaw = {
}, },
}, },
{ {
path: RoutePath.DEPARTMENTVIEW, path: Routes.DEPARTMENTVIEW.path,
name: RouteName.DEPARTMENTVIEW, name: Routes.DEPARTMENTVIEW.name,
component: () => import("@/views/DepartmentView.vue"), component: () => import("@/views/DepartmentView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -54,8 +54,8 @@ const dashboardRoutes: RouteRecordRaw = {
}, },
}, },
{ {
path: RoutePath.POSITIONVIEW, path: Routes.POSITIONVIEW.path,
name: RouteName.POSITIONVIEW, name: Routes.POSITIONVIEW.name,
component: () => import("@/views/PositionView.vue"), component: () => import("@/views/PositionView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,

View File

@@ -1,10 +1,10 @@
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { RouteName, RoutePath } from "../constants"; import { Routes } from "../constants";
const errorRoutes: RouteRecordRaw[] = [ const errorRoutes: RouteRecordRaw[] = [
{ {
path: RoutePath.GLOBAL_NOTFOUND, path: Routes.GLOBAL_NOTFOUND.path,
name: RouteName.GLOBAL_NOTFOUND, name: Routes.GLOBAL_NOTFOUND.name,
component: () => import("../../views/NotFound.vue"), component: () => import("../../views/NotFound.vue"),
}, },
]; ];

View File

@@ -1,10 +1,10 @@
import type { RouteRecordRaw } from "vue-router"; import type { RouteRecordRaw } from "vue-router";
import { EPermission, RouteName, RoutePath } from "../constants"; import { EPermission, Routes } from "../constants";
const userManagementRoutes: RouteRecordRaw[] = [ const userManagementRoutes: RouteRecordRaw[] = [
{ {
path: RoutePath.USERVIEW, path: Routes.USERVIEW.path,
name: RouteName.USERVIEW, name: Routes.USERVIEW.name,
component: () => import("@/views/UserView.vue"), component: () => import("@/views/UserView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -12,8 +12,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.ROLEVIEW, path: Routes.ROLEVIEW.path,
name: RouteName.ROLEVIEW, name: Routes.ROLEVIEW.name,
component: () => import("@/views/RoleView.vue"), component: () => import("@/views/RoleView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -21,8 +21,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.BINDROLEVIEW, path: Routes.BINDROLEVIEW.path,
name: RouteName.BINDROLEVIEW, name: Routes.BINDROLEVIEW.name,
component: () => import("@/views/BindRoleView.vue"), component: () => import("@/views/BindRoleView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -30,8 +30,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.BINDDEPARTMENTVIEW, path: Routes.BINDDEPARTMENTVIEW.path,
name: RouteName.BINDDEPARTMENTVIEW, name: Routes.BINDDEPARTMENTVIEW.name,
component: () => import("@/views/BindDepartmentView.vue"), component: () => import("@/views/BindDepartmentView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -39,8 +39,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.BINDPERMISSIONVIEW, path: Routes.BINDPERMISSIONVIEW.path,
name: RouteName.BINDPERMISSIONVIEW, name: Routes.BINDPERMISSIONVIEW.name,
component: () => import("@/views/BindPermissionView.vue"), component: () => import("@/views/BindPermissionView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -48,8 +48,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.PERMISSIONVIEW, path: Routes.PERMISSIONVIEW.path,
name: RouteName.PERMISSIONVIEW, name: Routes.PERMISSIONVIEW.name,
component: () => import("@/views/PermissionView.vue"), component: () => import("@/views/PermissionView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,
@@ -57,8 +57,8 @@ const userManagementRoutes: RouteRecordRaw[] = [
}, },
}, },
{ {
path: RoutePath.BINDPOSITIONVIEW, path: Routes.BINDPOSITIONVIEW.path,
name: RouteName.BINDPOSITIONVIEW, name: Routes.BINDPOSITIONVIEW.name,
component: () => import("@/views/BindPositionView.vue"), component: () => import("@/views/BindPositionView.vue"),
meta: { meta: {
requiresAuth: true, requiresAuth: true,

View File

@@ -1,6 +1,5 @@
import type { ComponentPublicInstance } from "vue"; import type { ComponentPublicInstance } from "vue";
import type { Router } from "vue-router"; import type { Router } from "vue-router";
import { RoutePath } from "../router/constants";
import { import {
ForbiddenError, ForbiddenError,
InternalServerError, InternalServerError,
@@ -9,6 +8,7 @@ import {
UnAuthError, UnAuthError,
} from "../types/error"; } from "../types/error";
import { z } from "zod"; import { z } from "zod";
import { Routes } from "../router/constants";
const makeErrorHandler = const makeErrorHandler =
( (
@@ -31,7 +31,7 @@ const makeErrorHandler =
}); });
} else if (err instanceof UnAuthError) { } else if (err instanceof UnAuthError) {
signOut(); signOut();
router.push(RoutePath.LOGIN); router.push(Routes.LOGIN.path);
showAlert({ showAlert({
level: "error", level: "error",
content: err.message, content: err.message,

View File

@@ -1,15 +1,15 @@
<template> <template>
<div class="px-2 sm:px-4 pt-6 sm:rounded-lg"> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 sm:mb-6 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['用户管理', '绑定部门']" :routes="[{ name: RouteName.USERVIEW }]" /> <Breadcrumbs :names="['用户管理', '绑定部门']" :routes="[Routes.USERVIEW.fullPath()]" />
<h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定部门</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定部门</h1>
</div> </div>
<TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch" <TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch"
@update:values="updateFilterValues"> @update:values="updateFilterValues">
<template #actions> <template #actions>
<div class="flex gap-x-2"> <div class="flex gap-x-2">
<TableButton variant="primary" @click="() => { <TableButton variant="primary" @click="() => {
if (checkedDepartmentIds.length === 0) { if (checkedDepartmentIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择部门', content: '没有选择部门',
@@ -19,9 +19,9 @@
departmentBindModal?.show(); departmentBindModal?.show();
} }
}"> }">
绑定 绑定
</TableButton> </TableButton>
<TableButton variant="danger" @click="() => { <TableButton variant="danger" @click="() => {
if (checkedDepartmentIds.length === 0) { if (checkedDepartmentIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择部门', content: '没有选择部门',
@@ -31,59 +31,59 @@
departmentUnbindModal?.show(); departmentUnbindModal?.show();
} }
}"> }">
解绑 解绑
</TableButton> </TableButton>
</div> </div>
</template> </template>
</TableFilterForm> </TableFilterForm>
<!-- 移动端卡片布局 --> <!-- 移动端卡片布局 -->
<div class="md:hidden space-y-4"> <div class="md:hidden space-y-4">
<MobileCardListWithCheckbox :items="departments || []" v-model="checkedDepartmentIds"> <MobileCardListWithCheckbox :items="departments || []" v-model="checkedDepartmentIds">
<template #title="{ item }"> <template #title="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #status="{ item }"> <template #status="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
<span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span> <span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span>
</div> </div>
</template> </template>
<template #content="{ item }"> <template #content="{ item }">
<div> <div>
<p class="text-xs font-medium text-gray-600">上级部门</p> <p class="text-xs font-medium text-gray-600">上级部门</p>
<p class="text-sm text-gray-900 mt-0.5">{{ !item.parentName ? '无' : item.parentName }}</p> <p class="text-sm text-gray-900 mt-0.5">{{ !item.parentName ? '无' : item.parentName }}</p>
</div> </div>
</template> </template>
</MobileCardListWithCheckbox> </MobileCardListWithCheckbox>
</div> </div>
<!-- PC端表格布局 --> <!-- PC端表格布局 -->
<div class="hidden md:block"> <div class="hidden md:block">
<TableFormLayout :items="departments || []" :columns="columns" :hasCheckbox="true" v-model="checkedDepartmentIds" <TableFormLayout :items="departments || []" :columns="columns" :hasCheckbox="true" v-model="checkedDepartmentIds"
@all-checked-change="allChecked = $event"> @all-checked-change="allChecked = $event">
<template #parentName="{ item }"> <template #parentName="{ item }">
{{ !item.parentName ? '无' : item.parentName }} {{ !item.parentName ? '无' : item.parentName }}
</template> </template>
<template #name="{ item }"> <template #name="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #bindState="{ item }"> <template #bindState="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
{{ item.isBound === true ? "已绑定" : "未绑定" }} {{ item.isBound === true ? "已绑定" : "未绑定" }}
</div> </div>
</template> </template>
</TableFormLayout> </TableFormLayout>
</div> </div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
<BindModal :id="'department-bind-modal'" :closeModal="() => { <BindModal :id="'department-bind-modal'" :closeModal="() => {
departmentBindModal!.hide(); departmentBindModal!.hide();
}" :onSubmit="handleBindDepartmentSubmit" title="绑定选中的部门吗"></BindModal> }" :onSubmit="handleBindDepartmentSubmit" title="绑定选中的部门吗"></BindModal>
<UnModal :id="'department-unbind-modal'" :closeModal="() => { <UnModal :id="'department-unbind-modal'" :closeModal="() => {
departmentUnbindModal!.hide(); departmentUnbindModal!.hide();
}" :onSubmit="handleUnbindDepartmentSubmit" title="解绑选中的部门吗"></UnModal> }" :onSubmit="handleUnbindDepartmentSubmit" title="解绑选中的部门吗"></UnModal>
</div> </div>
</template> </template>
@@ -99,7 +99,7 @@ import TableFormLayout from "@/components/TableFormLayout.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";
import { useDepartmentQuery } from "@/composables/department/useDepartmentQuery"; import { useDepartmentQuery } from "@/composables/department/useDepartmentQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref, watch } from "vue"; import { onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";

View File

@@ -1,15 +1,15 @@
<template> <template>
<div class="px-2 sm:px-4 pt-6 sm:rounded-lg"> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 sm:mb-6 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['角色管理', '绑定权限']" :routes="[{ name: RouteName.ROLEVIEW }]" /> <Breadcrumbs :names="['角色管理', '绑定权限']" :routes="[Routes.ROLEVIEW.fullPath()]" />
<h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定权限</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定权限</h1>
</div> </div>
<TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch" <TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch"
@update:values="updateFilterValues"> @update:values="updateFilterValues">
<template #actions> <template #actions>
<div class="flex gap-x-2"> <div class="flex gap-x-2">
<TableButton variant="primary" @click="() => { <TableButton variant="primary" @click="() => {
if (checkedPermissionIds.length === 0) { if (checkedPermissionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择权限', content: '没有选择权限',
@@ -19,9 +19,9 @@
permissionBindModal?.show(); permissionBindModal?.show();
} }
}"> }">
绑定 绑定
</TableButton> </TableButton>
<TableButton variant="danger" @click="() => { <TableButton variant="danger" @click="() => {
if (checkedPermissionIds.length === 0) { if (checkedPermissionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择权限', content: '没有选择权限',
@@ -31,59 +31,59 @@
permissionUnbindModal?.show(); permissionUnbindModal?.show();
} }
}"> }">
解绑 解绑
</TableButton> </TableButton>
</div> </div>
</template> </template>
</TableFilterForm> </TableFilterForm>
<!-- 移动端卡片布局 --> <!-- 移动端卡片布局 -->
<div class="md:hidden space-y-4"> <div class="md:hidden space-y-4">
<MobileCardListWithCheckbox :items="permissions || []" v-model="checkedPermissionIds"> <MobileCardListWithCheckbox :items="permissions || []" v-model="checkedPermissionIds">
<template #title="{ item }"> <template #title="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #status="{ item }"> <template #status="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
<span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span> <span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span>
</div> </div>
</template> </template>
<template #content="{ item }"> <template #content="{ item }">
<div> <div>
<p class="text-xs font-medium text-gray-600">权限编码</p> <p class="text-xs font-medium text-gray-600">权限编码</p>
<p class="text-sm text-gray-900 mt-0.5">{{ item.code }}</p> <p class="text-sm text-gray-900 mt-0.5">{{ item.code }}</p>
</div> </div>
</template> </template>
</MobileCardListWithCheckbox> </MobileCardListWithCheckbox>
</div> </div>
<!-- PC端表格布局 --> <!-- PC端表格布局 -->
<div class="hidden md:block"> <div class="hidden md:block">
<TableFormLayout :items="permissions || []" :columns="columns" :hasCheckbox="true" v-model="checkedPermissionIds" <TableFormLayout :items="permissions || []" :columns="columns" :hasCheckbox="true" v-model="checkedPermissionIds"
@all-checked-change="allChecked = $event"> @all-checked-change="allChecked = $event">
<template #code="{ item }"> <template #code="{ item }">
{{ item.code }} {{ item.code }}
</template> </template>
<template #name="{ item }"> <template #name="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #bindState="{ item }"> <template #bindState="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
{{ item.isBound === true ? "已绑定" : "未绑定" }} {{ item.isBound === true ? "已绑定" : "未绑定" }}
</div> </div>
</template> </template>
</TableFormLayout> </TableFormLayout>
</div> </div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>
<BindModal :id="'permission-bind-modal'" :closeModal="() => { <BindModal :id="'permission-bind-modal'" :closeModal="() => {
permissionBindModal!.hide(); permissionBindModal!.hide();
}" :onSubmit="handleBindPermissionSubmit" title="确定绑定选中的权限吗"></BindModal> }" :onSubmit="handleBindPermissionSubmit" title="确定绑定选中的权限吗"></BindModal>
<UnModal :id="'permission-unbind-modal'" :closeModal="() => { <UnModal :id="'permission-unbind-modal'" :closeModal="() => {
permissionUnbindModal!.hide(); permissionUnbindModal!.hide();
}" :onSubmit="handleUnbindPermissionSubmit" title="确定解绑选中的权限吗"></UnModal> }" :onSubmit="handleUnbindPermissionSubmit" title="确定解绑选中的权限吗"></UnModal>
</template> </template>
@@ -99,7 +99,7 @@ import type { FilterItem } from "@/components/TableFilterForm.vue";
import TableFormLayout from "@/components/TableFormLayout.vue"; import TableFormLayout from "@/components/TableFormLayout.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref, watch } from "vue"; import { onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";

View File

@@ -1,15 +1,15 @@
<template> <template>
<div class="px-2 sm:px-4 pt-6 sm:rounded-lg"> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 sm:mb-6 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['用户管理', '绑定岗位']" :routes="[{ name: RouteName.USERVIEW }]" /> <Breadcrumbs :names="['用户管理', '绑定岗位']" :routes="[Routes.USERVIEW.fullPath()]" />
<h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定岗位</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">绑定岗位</h1>
</div> </div>
<TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch" <TableFilterForm :filters="filterConfig" :initialValues="filterValues" @search="handleSearch"
@update:values="updateFilterValues"> @update:values="updateFilterValues">
<template #actions> <template #actions>
<div class="flex gap-x-2"> <div class="flex gap-x-2">
<TableButton variant="primary" @click="() => { <TableButton variant="primary" @click="() => {
if (checkedPositionIds.length === 0) { if (checkedPositionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择岗位', content: '没有选择岗位',
@@ -19,9 +19,9 @@
positionBindModal?.show(); positionBindModal?.show();
} }
}"> }">
绑定 绑定
</TableButton> </TableButton>
<TableButton variant="danger" @click="() => { <TableButton variant="danger" @click="() => {
if (checkedPositionIds.length === 0) { if (checkedPositionIds.length === 0) {
alertStore.showAlert({ alertStore.showAlert({
content: '没有选择岗位', content: '没有选择岗位',
@@ -31,50 +31,50 @@
positionUnbindModal?.show(); positionUnbindModal?.show();
} }
}"> }">
解绑 解绑
</TableButton> </TableButton>
</div> </div>
</template> </template>
</TableFilterForm> </TableFilterForm>
<!-- 移动端卡片布局 --> <!-- 移动端卡片布局 -->
<div class="md:hidden space-y-4"> <div class="md:hidden space-y-4">
<MobileCardListWithCheckbox :items="positions || []" v-model="checkedPositionIds"> <MobileCardListWithCheckbox :items="positions || []" v-model="checkedPositionIds">
<template #title="{ item }"> <template #title="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #status="{ item }"> <template #status="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
<span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span> <span class="text-sm">{{ item.isBound === true ? "已绑定" : "未绑定" }}</span>
</div> </div>
</template> </template>
</MobileCardListWithCheckbox> </MobileCardListWithCheckbox>
</div> </div>
<!-- PC端表格布局 --> <!-- PC端表格布局 -->
<div class="hidden md:block"> <div class="hidden md:block">
<TableFormLayout :items="positions || []" :columns="columns" :hasCheckbox="true" v-model="checkedPositionIds" <TableFormLayout :items="positions || []" :columns="columns" :hasCheckbox="true" v-model="checkedPositionIds"
@all-checked-change="allChecked = $event"> @all-checked-change="allChecked = $event">
<template #name="{ item }"> <template #name="{ item }">
{{ item.name }} {{ item.name }}
</template> </template>
<template #bindState="{ item }"> <template #bindState="{ item }">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div> <div class="h-2.5 w-2.5 rounded-full me-2" :class="item.isBound ? 'bg-green-500' : 'bg-red-500'"></div>
{{ item.isBound === true ? "已绑定" : "未绑定" }} {{ item.isBound === true ? "已绑定" : "未绑定" }}
</div> </div>
</template> </template>
</TableFormLayout> </TableFormLayout>
</div> </div>
<TablePagination :pageChange="handlePageChange" :total="total" /> <TablePagination :pageChange="handlePageChange" :total="total" />
</div> </div>
<BindModal :id="'position-bind-modal'" :closeModal="() => { <BindModal :id="'position-bind-modal'" :closeModal="() => {
positionBindModal!.hide(); positionBindModal!.hide();
}" :onSubmit="handleBindPositionSubmit" title="绑定选中的岗位吗"></BindModal> }" :onSubmit="handleBindPositionSubmit" title="绑定选中的岗位吗"></BindModal>
<UnModal :id="'position-unbind-modal'" :closeModal="() => { <UnModal :id="'position-unbind-modal'" :closeModal="() => {
positionUnbindModal!.hide(); positionUnbindModal!.hide();
}" :onSubmit="handleUnbindPositionSubmit" title="解绑选中的岗位吗"></UnModal> }" :onSubmit="handleUnbindPositionSubmit" title="解绑选中的岗位吗"></UnModal>
</template> </template>
@@ -93,7 +93,7 @@ import { usePositionBind } from "@/composables/position/usePositionBind";
import { usePositionQuery } from "@/composables/position/usePositionQuery"; import { usePositionQuery } from "@/composables/position/usePositionQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import { useMobileStyles } from "@/composables/useMobileStyles"; import { useMobileStyles } from "@/composables/useMobileStyles";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref, watch } from "vue"; import { onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class="px-2 sm:px-4 pt-6 sm:rounded-lg"> <div class="px-2 sm:px-4 pt-6 sm:rounded-lg">
<div class="mb-4 sm:mb-6 col-span-full"> <div class="mb-4 sm:mb-6 col-span-full">
<Breadcrumbs :names="['用户管理', '角色分配']" :routes="[{ name: RouteName.USERVIEW }]" /> <Breadcrumbs :names="['用户管理', '角色分配']" :routes="[Routes.USERVIEW.fullPath()]" />
<h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">角色分配</h1> <h1 class="text-xl sm:text-2xl mb-4 sm:mb-6 font-semibold text-gray-900">角色分配</h1>
</div> </div>
@@ -101,7 +101,7 @@ import TableFormLayout from "@/components/TableFormLayout.vue";
import TablePagination from "@/components/TablePagination.vue"; import TablePagination from "@/components/TablePagination.vue";
import { useRolesQuery } from "@/composables/role/useRolesQuery"; import { useRolesQuery } from "@/composables/role/useRolesQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref } from "vue"; import { onMounted, reactive, ref } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";

View File

@@ -33,7 +33,7 @@ import { useRoute, useRouter } from "vue-router";
import { z } from "zod"; import { z } from "zod";
import useUserAuth from "../composables/auth/useUserAuth"; import useUserAuth from "../composables/auth/useUserAuth";
import useAlertStore from "../composables/store/useAlertStore"; import useAlertStore from "../composables/store/useAlertStore";
import { RoutePath } from "../router/constants"; import { Routes } from "../router/constants";
const username = ref("admin"); const username = ref("admin");
const password = ref("admin"); const password = ref("admin");
@@ -58,8 +58,7 @@ const handleLogin = async () => {
content: "登录成功", content: "登录成功",
}); });
const redirectPath = const redirectPath =
(route.query.redirect as string) || (route.query.redirect as string) || Routes.USERVIEW.fullPath();
`${RoutePath.DASHBOARD}/${RoutePath.USERVIEW}`;
router.push(redirectPath); router.push(redirectPath);
}; };

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { RoutePath } from "../router/constants"; import { Routes } from "../router/constants";
</script> </script>
<template> <template>
@@ -10,7 +10,7 @@ import { RoutePath } from "../router/constants";
found</h1> found</h1>
<p class="mt-6 text-base sm:text-lg font-medium text-pretty text-gray-500">您访问的资源未找到请点击浏览器后退按钮返回</p> <p class="mt-6 text-base sm:text-lg font-medium text-pretty text-gray-500">您访问的资源未找到请点击浏览器后退按钮返回</p>
<div class="mt-10 flex items-center justify-center gap-x-6"> <div class="mt-10 flex items-center justify-center gap-x-6">
<RouterLink :to="`${RoutePath.DASHBOARD}/${RoutePath.OVERVIEW}`" <RouterLink :to="Routes.OVERVIEW.fullPath()"
class="rounded-md px-3.5 py-2.5 text-sm font-semibold bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 text-white shadow-xs focus-visible:outline-2 focus-visible:outline-offset-2"> class="rounded-md px-3.5 py-2.5 text-sm font-semibold bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 text-white shadow-xs focus-visible:outline-2 focus-visible:outline-offset-2">
回到主页</RouterLink> 回到主页</RouterLink>
<a href="#" class="text-sm font-semibold text-gray-900">联系我们<span aria-hidden="true">&rarr;</span></a> <a href="#" class="text-sm font-semibold text-gray-900">联系我们<span aria-hidden="true">&rarr;</span></a>

View File

@@ -135,7 +135,7 @@ import PlusIcon from "@/components/icons/PlusIcon.vue";
import useRoleDelete from "@/composables/role/useRoleDelete"; import useRoleDelete from "@/composables/role/useRoleDelete";
import { useRolesQuery } from "@/composables/role/useRolesQuery"; import { useRolesQuery } from "@/composables/role/useRolesQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import type { RoleUpsertModel } from "@/types/role"; import type { RoleUpsertModel } from "@/types/role";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, reactive, ref } from "vue"; import { nextTick, onMounted, reactive, ref } from "vue";
@@ -169,7 +169,7 @@ const updateFilterValues = (
} }
}; };
const selectedRole = ref<components["schemas"]["RoleDto"]>(); const selectedRole = ref<components["schemas"]["RoleRespDto"]>();
const roleUpsertModal = ref<ModalInterface>(); const roleUpsertModal = ref<ModalInterface>();
const roleDeleteModal = ref<ModalInterface>(); const roleDeleteModal = ref<ModalInterface>();
const actionExcStore = useActionExcStore(); const actionExcStore = useActionExcStore();
@@ -223,7 +223,7 @@ const handleUpsertModalSubmit = async (data: RoleUpsertModel) => {
}; };
const handleUpsertRoleClick = async ( const handleUpsertRoleClick = async (
role?: components["schemas"]["RoleDto"], role?: components["schemas"]["RoleRespDto"],
) => { ) => {
selectedRole.value = role; selectedRole.value = role;
await nextTick(() => { await nextTick(() => {
@@ -232,14 +232,13 @@ const handleUpsertRoleClick = async (
}; };
const handleBindPermissionClick = async ( const handleBindPermissionClick = async (
role: components["schemas"]["RoleDto"], role: components["schemas"]["RoleRespDto"],
) => { ) => {
router.push({ router.push(
name: RouteName.BINDPERMISSIONVIEW, Routes.BINDPERMISSIONVIEW.withParams({
params: { roleId: role.id!,
roleId: role.id, }),
}, );
});
}; };
const handleDeletedModalSubmit = async () => { const handleDeletedModalSubmit = async () => {
@@ -256,7 +255,7 @@ const handleDeletedModalSubmit = async () => {
}; };
const handleDeleteRoleClick = async ( const handleDeleteRoleClick = async (
role: components["schemas"]["RoleDto"], role: components["schemas"]["RoleRespDto"],
) => { ) => {
selectedRole.value = role; selectedRole.value = role;
await nextTick(() => { await nextTick(() => {

View File

@@ -52,14 +52,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Breadcrumbs from "@/components/Breadcrumbs.vue";
import useUserAuth from "@/composables/auth/useUserAuth"; import useUserAuth from "@/composables/auth/useUserAuth";
import useUserStore from "@/composables/store/useUserStore"; import useUserStore from "@/composables/store/useUserStore";
import { initFlowbite } from "flowbite"; import { initFlowbite } from "flowbite";
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import { z } from "zod"; import { z } from "zod";
import useAlertStore from "../composables/store/useAlertStore"; import useAlertStore from "../composables/store/useAlertStore";
import { RouteName } from "../router/constants"; import { Routes } from "../router/constants";
import Breadcrumbs from "@/components/Breadcrumbs.vue";
const { user } = useUserStore(); const { user } = useUserStore();
const { upsertCurrentUser } = useUserAuth(); const { upsertCurrentUser } = useUserAuth();

View File

@@ -174,7 +174,7 @@ import { useSort } from "@/composables/sort";
import { useActionExcStore } from "@/composables/store/useActionExcStore"; import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useUserDelete from "@/composables/user/useUserDelete"; import useUserDelete from "@/composables/user/useUserDelete";
import { useUserQuery } from "@/composables/user/useUserQuery"; import { useUserQuery } from "@/composables/user/useUserQuery";
import { RouteName } from "@/router/constants"; import { Routes } from "@/router/constants";
import type { UserUpsertSubmitModel } from "@/types/user"; import type { UserUpsertSubmitModel } from "@/types/user";
import { dayjs, formatDate } from "@/utils/dateUtil"; import { dayjs, formatDate } from "@/utils/dateUtil";
import { Modal, type ModalInterface, initFlowbite } from "flowbite"; import { Modal, type ModalInterface, initFlowbite } from "flowbite";
@@ -289,34 +289,31 @@ const handleUpsertUserClick = async (
const handleBindRoleClick = async ( const handleBindRoleClick = async (
user: components["schemas"]["UserRolePermissionDto"], user: components["schemas"]["UserRolePermissionDto"],
) => { ) => {
router.push({ router.push(
name: RouteName.BINDROLEVIEW, Routes.BINDROLEVIEW.withParams({
params: { userId: user.id!,
userId: user.id, }),
}, );
});
}; };
const handleBindDepartmentClick = async ( const handleBindDepartmentClick = async (
user: components["schemas"]["UserRolePermissionDto"], user: components["schemas"]["UserRolePermissionDto"],
) => { ) => {
router.push({ router.push(
name: RouteName.BINDDEPARTMENTVIEW, Routes.BINDDEPARTMENTVIEW.withParams({
params: { userId: user.id!,
userId: user.id, }),
}, );
});
}; };
const handleBindPositionClick = async ( const handleBindPositionClick = async (
user: components["schemas"]["UserRolePermissionDto"], user: components["schemas"]["UserRolePermissionDto"],
) => { ) => {
router.push({ router.push(
name: RouteName.BINDPOSITIONVIEW, Routes.BINDPOSITIONVIEW.withParams({
params: { userId: user.id!,
userId: user.id, }),
}, );
});
}; };
const handleSortClick = async (field: string) => { const handleSortClick = async (field: string) => {