重构错误处理逻辑,更新组件导入路径,新增多个模态框组件以支持用户、部门、角色和权限管理功能,优化分页和排序逻辑,更新类型定义以提高代码可读性和维护性

This commit is contained in:
Chuck1sn
2025-06-16 18:00:15 +08:00
parent 772ad547bf
commit 87d288c58e
54 changed files with 308 additions and 221 deletions

View File

@@ -1,12 +1,12 @@
import createClient, { type Middleware } from "openapi-fetch";
import useAuthStore from "../composables/store/useAuthStore";
import type { paths } from "./types/schema"; // generated by openapi-typescript
import {
ForbiddenError,
RequestError,
UnAuthError,
InternalServerError,
} from "../types/error";
import type { paths } from "./types/schema"; // generated by openapi-typescript
} from "@/types/ErrorTypes";
const myMiddleware: Middleware = {
onRequest({ request, options }) {

View File

@@ -71,19 +71,19 @@
</div>
</form>
</div>
<UserUpsertModal :id="'user-upsert-modal'" :onSubmit="handleUpsertUserSubmit" :closeModal="() => {
<UserFormDialog :id="'user-upsert-modal'" :onSubmit="handleUpsertUserSubmit" :closeModal="() => {
userUpsertModal!.hide();
}">
</UserUpsertModal>
</UserFormDialog>
<UserDeleteModal :id="'user-delete-modal'" :closeModal="() => {
currentDeleteUsername = undefined
userDeleteModal!.hide();
}" :onSubmit="handleDeleteUserSubmit" title="确定删除该用户吗" content="删除用户"></UserDeleteModal>
<DepartmentUpsertModal :id="'department-upsert-modal'" :onSubmit="handleUpsertDepartmentSubmit" :closeModal="() => {
<DepartmentFormDialog :id="'department-upsert-modal'" :onSubmit="handleUpsertDepartmentSubmit" :closeModal="() => {
availableDepartments = undefined
departmentUpsertModal!.hide();
}" :availableDepartments="availableDepartments">
</DepartmentUpsertModal>
</DepartmentFormDialog>
<DepartmentDeleteModal :id="'department-delete-modal'" :closeModal="() => {
currentDeleteDepartmentName = undefined
departmentDeleteModal!.hide();
@@ -92,10 +92,9 @@
<script setup lang="ts">
import { LoadingIcon } from "@/components/icons";
import DepartmentUpsertModal from "@/components/modals/DepartmentUpsertModal.vue";
import UserDeleteModal from "@/components/modals/PopupModal.vue";
import DepartmentDeleteModal from "@/components/modals/PopupModal.vue";
import UserUpsertModal from "@/components/modals/UserUpsertModal.vue";
import UserDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import DepartmentDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import DepartmentFormDialog from "@/components/modals/DepartmentFormDialog.vue";
import TableButton from "@/components/tables/TableButton.vue";
import Avatar from "@/components/ui/Avatar.vue";
import InputButton from "@/components/ui/InputButton.vue";
@@ -107,8 +106,8 @@ import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import useUserStore from "@/composables/store/useUserStore";
import { useUserUpsert } from "@/composables/user/useUserUpsert";
import type { DepartmentUpsertModel } from "@/types/department";
import type { UserUpsertSubmitModel } from "@/types/user";
import type { DepartmentUpsertModel } from "@/types/DepartmentTypes";
import type { UserUpsertSubmitModel } from "@/types/UserTypes";
import DOMPurify from "dompurify";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { marked } from "marked";

View File

@@ -26,19 +26,19 @@
</template>
<script setup lang="ts">
import { Modal, initFlowbite } from "flowbite";
import { computed, onMounted } from "vue";
import { initFlowbite, Modal } from "flowbite";
export type ModalSize = "xs" | "sm" | "md" | "lg" | "xl";
const props = defineProps<{
/** 模态框标题 */
/** 对话框标题 */
title?: string;
/** 模态框大小 */
/** 对话框大小 */
size?: ModalSize;
/** 关闭模态框的回调函数 */
/** 关闭对话框的回调函数 */
closeModal: () => void;
/** 模态框ID用于DOM选择 */
/** 对话框ID用于DOM选择 */
id?: string;
}>();

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" :closeModal="closeModal" size="sm">
<BaseDialog :id="id" :closeModal="closeModal" size="sm">
<div class="p-5 md:p-6 text-center">
<svg class="w-14 h-14 sm:w-16 sm:h-16 mx-auto text-red-600 mb-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@@ -18,11 +18,11 @@
class="py-2.5 px-5 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 min-w-[80px]"></button>
</div>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const { title, id, closeModal, onSubmit } = defineProps<{
title: string;

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="部门管理" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="部门管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -24,17 +24,17 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import useAlertStore from "@/composables/store/useAlertStore";
import type { DepartmentUpsertModel } from "@/types/department";
import type { DepartmentUpsertModel } from "@/types/DepartmentTypes";
import { initFlowbite } from "flowbite";
import { onMounted, ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const { department, availableDepartments, onSubmit, closeModal, id } =
defineProps<{

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="大模型配置" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="大模型配置" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -53,7 +53,7 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
@@ -61,7 +61,7 @@ import type { components } from "@/api/types/schema";
import { initFlowbite } from "flowbite";
import { onMounted, ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const { llm, onSubmit, id } = defineProps<{
llm?: components["schemas"]["LlmVm"];

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="权限管理" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="权限管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -21,16 +21,16 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import useAlertStore from "@/composables/store/useAlertStore";
import type { PermissionUpsertModel } from "@/types/permission";
import type { PermissionUpsertModel } from "@/types/PermissionTypes";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const alertStore = useAlertStore();
const { permission, onSubmit, closeModal, id } = defineProps<{

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="岗位管理" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="岗位管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -15,16 +15,16 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import useAlertStore from "@/composables/store/useAlertStore";
import type { PositionUpsertModel } from "@/types/position";
import type { PositionUpsertModel } from "@/types/PositionTypes";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const alertStore = useAlertStore();
const { position, closeModal, onSubmit, id } = defineProps<{

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="角色管理" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="角色管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -21,16 +21,16 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import useAlertStore from "@/composables/store/useAlertStore";
import type { RoleUpsertModel } from "@/types/role";
import type { RoleUpsertModel } from "@/types/RoleTypes";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const alertStore = useAlertStore();
const { role, closeModal, onSubmit, id } = defineProps<{

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="定时任务配置" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="定时任务配置" size="md" :closeModal="closeModal">
<!-- Modal body -->
<div class="p-4 md:p-5">
<div class="grid gap-4 mb-4 grid-cols-1">
@@ -15,14 +15,14 @@
保存
</button>
</div>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const { job, closeModal, onSubmit, id } = defineProps<{
job?: components["schemas"]["JobTriggerDto"];

View File

@@ -1,5 +1,5 @@
<template>
<BaseModal :id="id" title="用户管理" size="md" :closeModal="closeModal">
<BaseDialog :id="id" title="用户管理" size="md" :closeModal="closeModal">
<!-- Modal body -->
<form class="p-4 md:p-5">
<div class="space-y-4">
@@ -39,19 +39,19 @@
保存
</button>
</form>
</BaseModal>
</BaseDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import useAlertStore from "@/composables/store/useAlertStore";
import { useUserUpsert } from "@/composables/user/useUserUpsert";
import { ValidationError } from "@/types/error";
import type { UserUpsertSubmitModel } from "@/types/user";
import { ValidationError } from "@/types/ErrorTypes";
import type { UserUpsertSubmitModel } from "@/types/UserTypes";
import Compressor from "compressorjs";
import { onMounted, ref, watch } from "vue";
import { ref, watch } from "vue";
import { z } from "zod";
import BaseModal from "./BaseModal.vue";
import BaseDialog from "./BaseDialog.vue";
const { user, onSubmit, id } = defineProps<{
user?: components["schemas"]["UserRolePermissionDto"];

View File

@@ -36,7 +36,7 @@
</template>
<script setup lang="ts">
import { usePagination } from "@/composables/page";
import { usePagination } from "@/composables/common/usePagination";
import { watch } from "vue";
const { pageChange, total } = defineProps<{

View File

@@ -35,8 +35,8 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import useAlertStore from "@/composables/store/useAlertStore";
import type { AlertLevel } from "@/types/alert";
import type { AlertLevel } from "@/types/AlertTypes";
import { onMounted, onUnmounted, ref } from "vue";
const alertStore = useAlertStore();
</script>

View File

@@ -7,20 +7,22 @@ import {
RequestError,
UnAuthError,
ValidationError,
} from "@/types/error";
} from "@/types/ErrorTypes";
import { useRouter } from "vue-router";
import { z } from "zod";
/**
* Composable
* Composable -
* @returns
*/
export function useErrorHandler() {
export function useErrorHandling() {
const router = useRouter();
const { signOut } = useUserAuth();
const alertStore = useAlertStore();
/**
*
* @param err
*/
const handleError = (err: unknown) => {
console.error(err);
@@ -69,4 +71,4 @@ export function useErrorHandler() {
};
}
export default useErrorHandler;
export default useErrorHandling;

View File

@@ -12,6 +12,11 @@ export interface UsePaginationOptions {
initialTotal?: number;
}
/**
* Composable -
* @param options
* @returns
*/
export function usePagination(options: UsePaginationOptions = {}) {
const { initialPage = 1, initialPageSize = 10, initialTotal = 0 } = options;

View File

@@ -1,23 +1,39 @@
import { computed, ref } from "vue";
export const useSort = () => {
const sortFields = ref<
{
field: string;
order: "asc" | "desc" | undefined;
}[]
>([]);
export interface SortField {
field: string;
order: "asc" | "desc" | undefined;
}
/**
* Composable -
* @returns
*/
export function useSorting() {
const sortFields = ref<SortField[]>([]);
/**
*
* @param field
* @returns
*/
const getSortField = (field: string) => {
return sortFields.value.find((item) => item.field === field);
};
/**
* API请求
*/
const sortBy = computed(() => {
return sortFields.value.length
? sortFields.value.map((item) => `${item.field}:${item.order}`).join(",")
: undefined;
});
/**
*
* @param field
*/
const handleSort = async (field: string) => {
if (sortFields.value?.find((item) => item.field === field)) {
sortFields.value = sortFields.value?.map((item) =>
@@ -39,4 +55,4 @@ export const useSort = () => {
handleSort,
getSortField,
};
};
}

View File

@@ -1,7 +1,8 @@
/**
* hook
* Composable -
* @returns
*/
export function useMobileStyles() {
export function useStyleSystem() {
// 移动端卡片容器样式
const cardContainerClass =
"p-4 bg-white rounded-lg shadow border border-gray-100";

View File

@@ -1,5 +1,5 @@
import client from "../../api/client";
import type { DepartmentUpsertModel } from "../../types/department";
import type { DepartmentUpsertModel } from "../../types/DepartmentTypes";
export const useDepartmentUpsert = () => {
const upsertDepartment = async (department: DepartmentUpsertModel) => {

View File

@@ -1,5 +1,5 @@
import client from "../../api/client";
import type { PermissionUpsertModel } from "../../types/permission";
import type { PermissionUpsertModel } from "../../types/PermissionTypes";
const usePermissionUpsert = () => {
const upsertPermission = async (permission: PermissionUpsertModel) => {

View File

@@ -1,5 +1,5 @@
import client from "../../api/client";
import type { UserUpsertSubmitModel } from "../../types/user";
import type { UserUpsertSubmitModel } from "../../types/UserTypes";
export const useUserUpsert = () => {
const uploadUserAvatar = async (file: File) => {

View File

@@ -5,7 +5,7 @@ import { createApp } from "vue";
import VueDatePicker from "@vuepic/vue-datepicker";
import App from "./App.vue";
import useErrorHandler from "./composables/useErrorHandler";
import useErrorHandling from "./composables/common/useErrorHandling";
import router from "./router";
import "@vuepic/vue-datepicker/dist/main.css";
import "./assets/datepicker.css";
@@ -27,7 +27,7 @@ enableMocking().then(() => {
app.use(createPinia());
app.use(router);
const { handleError } = useErrorHandler();
const { handleError } = useErrorHandling();
app.config.errorHandler = (err, instance, info) => {
handleError(err);
};

View File

@@ -5,7 +5,7 @@ const aiRoutes: RouteRecordRaw[] = [
{
path: Routes.LLMCONFIGVIEW.path,
name: Routes.LLMCONFIGVIEW.name,
component: () => import("@/views/LlmConfigView.vue"),
component: () => import("@/views/LlmConfigurationPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_LLM_CONFIG_PERMISSION,

View File

@@ -12,7 +12,7 @@ const authRoutes: RouteRecordRaw[] = [
{
path: Routes.LOGIN.path,
name: Routes.LOGIN.name,
component: () => import("../../views/LoginView.vue"),
component: () => import("../../views/LoginPage.vue"),
},
];

View File

@@ -1,8 +1,8 @@
import type { RouteRecordRaw } from "vue-router";
import Dashboard from "../../components/layout/Dashboard.vue";
import { EPermission, Routes } from "../constants";
import aiRoutes from "./ai";
import userManagementRoutes from "./user";
import Dashboard from "../../components/layout/Dashboard.vue";
const dashboardRoutes: RouteRecordRaw = {
path: Routes.DASHBOARD.path,
@@ -15,7 +15,7 @@ const dashboardRoutes: RouteRecordRaw = {
{
path: Routes.OVERVIEW.path,
name: Routes.OVERVIEW.name,
component: () => import("@/views/OverView.vue"),
component: () => import("@/views/DashboardPage.vue"),
meta: {
requiresAuth: true,
},
@@ -23,7 +23,7 @@ const dashboardRoutes: RouteRecordRaw = {
{
path: Routes.SETTINGS.path,
name: Routes.SETTINGS.name,
component: () => import("@/views/SettingsView.vue"),
component: () => import("@/views/SystemSettingsPage.vue"),
meta: {
requiresAuth: true,
},
@@ -33,12 +33,12 @@ const dashboardRoutes: RouteRecordRaw = {
{
path: Routes.NOTFOUND.path,
name: Routes.NOTFOUND.name,
component: () => import("@/views/NotFound.vue"),
component: () => import("@/views/NotFoundPage.vue"),
},
{
path: Routes.SCHEDULERVIEW.path,
name: Routes.SCHEDULERVIEW.name,
component: () => import("@/views/SchedulerView.vue"),
component: () => import("@/views/SchedulerManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_SCHEDULER_PERMISSION,
@@ -47,7 +47,7 @@ const dashboardRoutes: RouteRecordRaw = {
{
path: Routes.DEPARTMENTVIEW.path,
name: Routes.DEPARTMENTVIEW.name,
component: () => import("@/views/DepartmentView.vue"),
component: () => import("@/views/DepartmentManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_DEPARTMENT_PERMISSION,
@@ -56,7 +56,7 @@ const dashboardRoutes: RouteRecordRaw = {
{
path: Routes.POSITIONVIEW.path,
name: Routes.POSITIONVIEW.name,
component: () => import("@/views/PositionView.vue"),
component: () => import("@/views/PositionManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_POSITION_PERMISSION,

View File

@@ -5,7 +5,7 @@ const errorRoutes: RouteRecordRaw[] = [
{
path: Routes.GLOBAL_NOTFOUND.path,
name: Routes.GLOBAL_NOTFOUND.name,
component: () => import("../../views/NotFound.vue"),
component: () => import("../../views/NotFoundPage.vue"),
},
];

View File

@@ -5,7 +5,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.USERVIEW.path,
name: Routes.USERVIEW.name,
component: () => import("@/views/UserView.vue"),
component: () => import("@/views/UserManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_USER_ROLE_PERMISSION,
@@ -14,7 +14,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.ROLEVIEW.path,
name: Routes.ROLEVIEW.name,
component: () => import("@/views/RoleView.vue"),
component: () => import("@/views/RoleManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_USER_ROLE_PERMISSION,
@@ -23,7 +23,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.BINDROLEVIEW.path,
name: Routes.BINDROLEVIEW.name,
component: () => import("@/views/BindRoleView.vue"),
component: () => import("@/views/UserRoleAssignmentPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.WRITE_USER_ROLE_PERMISSION,
@@ -32,7 +32,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.BINDDEPARTMENTVIEW.path,
name: Routes.BINDDEPARTMENTVIEW.name,
component: () => import("@/views/BindDepartmentView.vue"),
component: () => import("@/views/UserDepartmentAssignmentPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.WRITE_USER_ROLE_PERMISSION,
@@ -41,7 +41,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.BINDPERMISSIONVIEW.path,
name: Routes.BINDPERMISSIONVIEW.name,
component: () => import("@/views/BindPermissionView.vue"),
component: () => import("@/views/RolePermissionAssignmentPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.WRITE_USER_ROLE_PERMISSION,
@@ -50,7 +50,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.PERMISSIONVIEW.path,
name: Routes.PERMISSIONVIEW.name,
component: () => import("@/views/PermissionView.vue"),
component: () => import("@/views/PermissionManagementPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.READ_USER_ROLE_PERMISSION,
@@ -59,7 +59,7 @@ const userManagementRoutes: RouteRecordRaw[] = [
{
path: Routes.BINDPOSITIONVIEW.path,
name: Routes.BINDPOSITIONVIEW.name,
component: () => import("@/views/BindPositionView.vue"),
component: () => import("@/views/UserPositionAssignmentPage.vue"),
meta: {
requiresAuth: true,
hasPermission: EPermission.WRITE_USER_ROLE_PERMISSION,

View File

@@ -0,0 +1 @@
export type AlertLevel = "info" | "warning" | "success" | "error";

View File

@@ -0,0 +1,15 @@
export interface DepartmentFormData {
id?: number;
name: string;
parentId?: number | null;
}
export type DepartmentUpsertModel = DepartmentFormData;
export interface DepartmentData {
id: number;
name: string;
parentId?: number;
parentName?: string;
isBound?: boolean;
}

View File

@@ -0,0 +1,46 @@
export class BaseError extends Error {
constructor(message: string) {
super(message);
this.name = this.constructor.name;
}
}
export class ValidationError extends BaseError {}
export class RequestError extends BaseError {
status: number;
constructor(status: number) {
super(`请求错误: ${status}`);
this.status = status;
}
}
export class UnAuthError extends BaseError {
status: number;
constructor(status: number) {
super(`未授权: ${status}`);
this.status = status;
}
}
export class ForbiddenError extends BaseError {
status: number;
constructor(status: number) {
super(`禁止访问: ${status}`);
this.status = status;
}
}
export class InternalServerError extends BaseError {
detail?: string;
status: number;
constructor(status: number, detail?: string) {
super(`服务器错误: ${status}`);
this.status = status;
this.detail = detail;
}
}

View File

@@ -0,0 +1,14 @@
export interface PermissionFormData {
id?: number;
name: string;
code: string;
}
export type PermissionUpsertModel = PermissionFormData;
export interface PermissionData {
id: number;
name: string;
code: string;
isBound?: boolean;
}

View File

@@ -0,0 +1,12 @@
export interface PositionFormData {
id?: number;
name: string;
}
export type PositionUpsertModel = PositionFormData;
export interface PositionData {
id: number;
name: string;
isBound?: boolean;
}

View File

@@ -0,0 +1,20 @@
export interface RoleFormData {
id?: number;
name: string;
code: string;
}
export type RoleUpsertModel = RoleFormData;
export interface RoleData {
id: number;
name: string;
code: string;
isBound?: boolean;
permissions?: Array<{
id: number;
name: string;
code: string;
isBound?: boolean;
}>;
}

View File

@@ -0,0 +1,35 @@
export interface UserFormData {
id?: number;
username: string;
password?: string;
enable: boolean;
avatar?: string;
realName?: string;
age?: number;
gender?: number;
email?: string;
telephone?: string;
}
export type UserUpsertSubmitModel = UserFormData;
// 用户类型,根据实际情况扩展
export interface UserData {
id: number;
username: string;
enable: boolean;
avatar?: string;
realName?: string;
age?: number;
gender?: number;
email?: string;
telephone?: string;
roles?: Array<{
id: number;
name: string;
code: string;
isBound?: boolean;
}>;
}
export type User = UserData | null;

View File

@@ -1,5 +0,0 @@
export interface DepartmentUpsertModel {
id?: number;
name: string;
parentId?: number | null;
}

View File

@@ -1,53 +0,0 @@
class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = "ValidationError";
}
}
class HttpError extends Error {
status: number;
detail?: string;
constructor(message: string, status: number, detail?: string) {
super(message);
this.name = "HttpError";
this.status = status;
this.detail = detail;
}
}
class UnAuthError extends HttpError {
constructor(status: number) {
super("当前用户身份认证异常", status);
this.name = "UnAuthError";
}
}
class ForbiddenError extends HttpError {
constructor(status: number) {
super("您没有对应的权限", status);
this.name = "ForbiddenError";
}
}
class RequestError extends HttpError {
constructor(status: number) {
super("请求发生异常,请检查您的输入或稍后再试", status);
this.name = "RequestError";
}
}
class InternalServerError extends HttpError {
constructor(status: number, detail: string) {
super(detail, status, detail);
this.name = "InternalServerError";
}
}
export {
UnAuthError,
ForbiddenError,
RequestError,
InternalServerError,
ValidationError,
};

View File

@@ -1,5 +0,0 @@
export interface PermissionUpsertModel {
id?: number;
name: string;
code: string;
}

View File

@@ -1,4 +0,0 @@
export interface PositionUpsertModel {
id?: number;
name: string;
}

View File

@@ -1,5 +0,0 @@
export interface RoleUpsertModel {
id?: number;
name: string;
code: string;
}

View File

@@ -1,9 +0,0 @@
export interface UserUpsertSubmitModel {
id?: number;
username: string;
password?: string;
enable: boolean;
avatar?: string;
}
export type User = UserRolePermissionModel | null;

View File

@@ -100,31 +100,31 @@
<DepartmentDeleteModal :id="'department-delete-modal'" :closeModal="() => {
departmentDeleteModal!.hide();
}" :onSubmit="handleDeleteDepartmentSubmit" title="确定删除该部门吗" content="删除部门"></DepartmentDeleteModal>
<DepartmentUpsertModal :id="'department-upsert-modal'" :onSubmit="handleUpsertDepartmentSubmit" :closeModal="() => {
<DepartmentFormDialog :id="'department-upsert-modal'" :onSubmit="handleUpsertDepartmentSubmit" :closeModal="() => {
availableDepartments = undefined
departmentUpsertModal!.hide();
departmentFormDialog!.hide();
}" :department="selectedDepartment" :availableDepartments="availableDepartments">
</DepartmentUpsertModal>
</DepartmentFormDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import DepartmentDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import DepartmentFormDialog from "@/components/modals/DepartmentFormDialog.vue";
import MobileCardList from "@/components/tables/MobileCardList.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import DepartmentUpsertModal from "@/components/modals/DepartmentUpsertModal.vue";
import DepartmentDeleteModal from "@/components/modals/PopupModal.vue";
import useDepartmentDelete from "@/composables/department/useDepartmentDelete";
import { useDepartmentQuery } from "@/composables/department/useDepartmentQuery";
import { useDepartmentUpsert } from "@/composables/department/useDepartmentUpsert";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import type { DepartmentUpsertModel } from "@/types/department";
import type { DepartmentUpsertModel } from "@/types/DepartmentTypes";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, reactive, ref } from "vue";
@@ -154,7 +154,7 @@ const updateFilterValues = (
};
const selectedDepartment = ref<components["schemas"]["Department"]>();
const departmentUpsertModal = ref<ModalInterface>();
const departmentFormDialog = ref<ModalInterface>();
const departmentDeleteModal = ref<ModalInterface>();
const {
@@ -189,7 +189,7 @@ onMounted(async () => {
"#department-delete-modal",
);
if ($upsertModalElement) {
departmentUpsertModal.value = new Modal($upsertModalElement, {});
departmentFormDialog.value = new Modal($upsertModalElement, {});
}
if ($deleteModalElement) {
departmentDeleteModal.value = new Modal($deleteModalElement, {});
@@ -205,7 +205,7 @@ const handleUpsertDepartmentSubmit = async (
department: DepartmentUpsertModel,
) => {
await upsertDepartment(department);
departmentUpsertModal.value?.hide();
departmentFormDialog.value?.hide();
alertStore.showAlert({
content: "操作成功",
level: "success",
@@ -221,7 +221,7 @@ const handleUpsertDepartmentClick = async (
selectedDepartment.value = department;
await fetchAvailableDepartments(department?.id);
await nextTick(() => {
departmentUpsertModal.value?.show();
departmentFormDialog.value?.show();
});
};

View File

@@ -109,20 +109,20 @@
<TablePagination :pageChange="handlePageChange" :total="total" />
</div>
<LlmUpdateModal :llm="selectedLlm" :id="'llm-update-modal'" :closeModal="() => {
<LlmFormDialog :llm="selectedLlm" :id="'llm-update-modal'" :closeModal="() => {
llmUpdateModal!.hide();
}" :onSubmit="handleUpdateModalSubmit"></LlmUpdateModal>
}" :onSubmit="handleUpdateModalSubmit"></LlmFormDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import LlmFormDialog from "@/components/modals/LlmFormDialog.vue";
import MobileCardList from "@/components/tables/MobileCardList.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import LlmUpdateModal from "@/components/modals/LlmUpdateModal.vue";
import { useLlmQuery } from "@/composables/ai/useLlmQuery";
import { useLlmUpdate } from "@/composables/ai/useLlmUpdate";
import useAlertStore from "@/composables/store/useAlertStore";

View File

@@ -100,32 +100,32 @@
<PermissionDeleteModal :id="'permission-delete-modal'" :closeModal="() => {
permissionDeleteModal!.hide();
}" :onSubmit="handleDeleteModalSubmit" title="确定删除该权限吗" content="删除权限"></PermissionDeleteModal>
<PermissionUpsertModal :id="'permission-upsert-modal'" :onSubmit="handleUpsertModalSubmit" :closeModal="() => {
<PermissionFormDialog :id="'permission-upsert-modal'" :onSubmit="handleUpsertModalSubmit" :closeModal="() => {
permissionUpsertModal!.hide();
}" :permission="selectedPermission">
</PermissionUpsertModal>
</PermissionFormDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import PermissionDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import PermissionFormDialog from "@/components/modals/PermissionFormDialog.vue";
import MobileCardList from "@/components/tables/MobileCardList.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import PermissionUpsertModal from "@/components/modals/PermissionUpsertModal.vue";
import PermissionDeleteModal from "@/components/modals/PopupModal.vue";
import usePermissionDelete from "@/composables/permission/usePermissionDelete";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import type { PermissionUpsertModel } from "@/types/PermissionTypes";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, reactive, ref } from "vue";
import usePermissionsQuery from "../composables/permission/usePermissionQuery";
import usePermissionUpsert from "../composables/permission/usePermissionUpsert";
import useAlertStore from "../composables/store/useAlertStore";
import type { PermissionUpsertModel } from "../types/permission";
//
const filterConfig = [

View File

@@ -91,10 +91,10 @@
positionDeleteModal!.hide();
}" :onSubmit="handleDeletePositionSubmit" title="确定删除该岗位吗" content="删除岗位"></PositionDeleteModal>
<PositionUpsertModal :id="'position-upsert-modal'" :onSubmit="handleUpsertPositionSubmit" :closeModal="() => {
<PositionFormDialog :id="'position-upsert-modal'" :onSubmit="handleUpsertPositionSubmit" :closeModal="() => {
positionUpsertModal!.hide();
}" :position="selectedPosition" :allPositions="allPositions">
</PositionUpsertModal>
</PositionFormDialog>
</template>
<script setup lang="ts">
@@ -107,8 +107,8 @@ import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import PositionDeleteModal from "@/components/modals/PopupModal.vue";
import PositionUpsertModal from "@/components/modals/PositionUpsertModal.vue";
import PositionDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import PositionFormDialog from "@/components/modals/PositionFormDialog.vue";
import usePositionDelete from "@/composables/position/usePositionDelete";
import { usePositionQuery } from "@/composables/position/usePositionQuery";
import { usePositionUpsert } from "@/composables/position/usePositionUpsert";

View File

@@ -115,31 +115,31 @@
<RoleDeleteModal :id="'role-delete-modal'" :closeModal="() => {
roleDeleteModal!.hide();
}" :onSubmit="handleDeletedModalSubmit" title="确定删除该角色吗" content="删除角色"></RoleDeleteModal>
<RoleUpsertModal :id="'role-upsert-modal'" :onSubmit="handleUpsertModalSubmit" :closeModal="() => {
<RoleFormDialog :id="'role-upsert-modal'" :onSubmit="handleUpsertModalSubmit" :closeModal="() => {
roleUpsertModal!.hide();
}" :role="selectedRole">
</RoleUpsertModal>
</RoleFormDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import RoleDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import RoleFormDialog from "@/components/modals/RoleFormDialog.vue";
import MobileCardList from "@/components/tables/MobileCardList.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import PlusIcon from "@/components/icons/PlusIcon.vue";
import RoleDeleteModal from "@/components/modals/PopupModal.vue";
import RoleUpsertModal from "@/components/modals/RoleUpsertModal.vue";
import useRoleDelete from "@/composables/role/useRoleDelete";
import { useRolesQuery } from "@/composables/role/useRolesQuery";
import { useRoleUpsert } from "@/composables/role/useRoleUpsert";
import { useRolesQuery } from "@/composables/role/useRolesQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import { Routes } from "@/router/constants";
import type { RoleUpsertModel } from "@/types/role";
import type { RoleUpsertModel } from "@/types/RoleTypes";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";

View File

@@ -91,22 +91,22 @@
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import BindModal from "@/components/modals/ConfirmationDialog.vue";
import UnModal from "@/components/modals/ConfirmationDialog.vue";
import MobileCardListWithCheckbox from "@/components/tables/MobileCardListWithCheckbox.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import BindModal from "@/components/modals/PopupModal.vue";
import UnModal from "@/components/modals/PopupModal.vue";
import { usePermissionBind } from "@/composables/permission/usePermissionBind";
import usePermissionsQuery from "@/composables/permission/usePermissionQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router";
import usePermissionsQuery from "@/composables/permission/usePermissionQuery";
//
const filterConfig: FilterItem[] = [

View File

@@ -140,15 +140,16 @@
<PopupModal :id="'job-pause-modal'" :closeModal="() => {
jobPauseModal!.hide();
}" :onSubmit="handlePauseModalSubmit" title="确定暂停该任务吗" content="暂停任务"></PopupModal>
<SchedulerUpdateModal :job="selectedJob" :id="'job-update-modal'" :closeModal="() => {
<SchedulerFormDialog :job="selectedJob" :id="'job-update-modal'" :closeModal="() => {
jobUpdateModal!.hide();
}" :onSubmit="handleUpdateModalSubmit"></SchedulerUpdateModal>
}" :onSubmit="handleUpdateModalSubmit"></SchedulerFormDialog>
</template>
<script setup lang="ts">
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import PopupModal from "@/components/modals/PopupModal.vue";
import SchedulerUpdateModal from "@/components/modals/SchedulerUpdateModal.vue";
import PopupModal from "@/components/modals/ConfirmationDialog.vue";
import SchedulerFormDialog from "@/components/modals/SchedulerFormDialog.vue";
import MobileCardList from "@/components/tables/MobileCardList.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";

View File

@@ -89,14 +89,14 @@
<script setup lang="ts">
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import BindModal from "@/components/modals/ConfirmationDialog.vue";
import UnModal from "@/components/modals/ConfirmationDialog.vue";
import MobileCardListWithCheckbox from "@/components/tables/MobileCardListWithCheckbox.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import BindModal from "@/components/modals/PopupModal.vue";
import UnModal from "@/components/modals/PopupModal.vue";
import { useDepartmentBind } from "@/composables/department/useDepartmentBind";
import { useDepartmentQuery } from "@/composables/department/useDepartmentQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore";

View File

@@ -150,19 +150,20 @@
<UserDeleteModal :id="'user-delete-modal'" :closeModal="() => {
userDeleteModal!.hide();
}" :onSubmit="handleDeleteUserSubmit" title="确定删除该用户吗" content="删除用户"></UserDeleteModal>
<UserUpsertModal :id="'user-upsert-modal'" :onSubmit="handleUpsertUserSubmit" :closeModal="() => {
}" :onSubmit="handleDeleteUserSubmit" title="确定删除该用户吗"></UserDeleteModal>
<UserFormDialog :id="'user-upsert-modal'" :onSubmit="handleUpsertUserSubmit" :closeModal="() => {
userUpsertModal!.hide();
}" :user="selectedUser">
</UserUpsertModal>
</UserFormDialog>
</template>
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import { PlusIcon } from "@/components/icons";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import UserDeleteModal from "@/components/modals/PopupModal.vue";
import UserUpsertModal from "@/components/modals/UserUpsertModal.vue";
import ConfirmationDialog from "@/components/modals/ConfirmationDialog.vue";
import UserDeleteModal from "@/components/modals/ConfirmationDialog.vue";
import UserFormDialog from "@/components/modals/UserFormDialog.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm, {
type FilterItem,
@@ -171,14 +172,14 @@ import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import Avatar from "@/components/ui/Avatar.vue";
import SortIcon from "@/components/ui/SortIcon.vue";
import { useSort } from "@/composables/sort";
import { useSorting } from "@/composables/common/useSorting";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import useUserDelete from "@/composables/user/useUserDelete";
import { useUserQuery } from "@/composables/user/useUserQuery";
import { useUserUpsert } from "@/composables/user/useUserUpsert";
import { Routes } from "@/router/constants";
import type { UserUpsertSubmitModel } from "@/types/user";
import type { UserUpsertSubmitModel } from "@/types/UserTypes";
import { dayjs, formatDate } from "@/utils/dateUtil";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { nextTick, onMounted, reactive, ref } from "vue";
@@ -223,7 +224,7 @@ const router = useRouter();
const { total, users, fetchUsersWith } = useUserQuery();
const { deleteUser } = useUserDelete();
const userUpsert = useUserUpsert();
const { sortBy, handleSort, getSortField } = useSort();
const { sortBy, handleSort, getSortField } = useSorting();
const alertStore = useAlertStore();
const actionExcStore = useActionExcStore();
//

View File

@@ -81,14 +81,14 @@
<script setup lang="ts">
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import BindModal from "@/components/modals/ConfirmationDialog.vue";
import UnModal from "@/components/modals/ConfirmationDialog.vue";
import MobileCardListWithCheckbox from "@/components/tables/MobileCardListWithCheckbox.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import BindModal from "@/components/modals/PopupModal.vue";
import UnModal from "@/components/modals/PopupModal.vue";
import { usePositionBind } from "@/composables/position/usePositionBind";
import { usePositionQuery } from "@/composables/position/usePositionQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore";

View File

@@ -92,22 +92,22 @@
<script setup lang="ts">
import type { components } from "@/api/types/schema";
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
import BindModal from "@/components/modals/ConfirmationDialog.vue";
import UnModal from "@/components/modals/ConfirmationDialog.vue";
import MobileCardListWithCheckbox from "@/components/tables/MobileCardListWithCheckbox.vue";
import TableButton from "@/components/tables/TableButton.vue";
import TableFilterForm from "@/components/tables/TableFilterForm.vue";
import type { FilterItem } from "@/components/tables/TableFilterForm.vue";
import TableFormLayout from "@/components/tables/TableFormLayout.vue";
import TablePagination from "@/components/tables/TablePagination.vue";
import BindModal from "@/components/modals/PopupModal.vue";
import UnModal from "@/components/modals/PopupModal.vue";
import { useRoleBind } from "@/composables/role/useRoleBind";
import { useRolesQuery } from "@/composables/role/useRolesQuery";
import { useActionExcStore } from "@/composables/store/useActionExcStore";
import useAlertStore from "@/composables/store/useAlertStore";
import { Routes } from "@/router/constants";
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
import { onMounted, reactive, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useRolesQuery } from "@/composables/role/useRolesQuery";
const filterConfig: FilterItem[] = [
{