【新增】私有证书

This commit is contained in:
cai
2025-09-03 15:15:59 +08:00
parent efd052a297
commit 954cd1638d
442 changed files with 76787 additions and 7483 deletions

View File

@@ -115,13 +115,13 @@ const useAxios = <T = unknown, Z = Record<string, unknown>>(instance: HttpClient
// 显示响应消息
const showResponseMessage = () => {
console.log('dataRef.value', dataRef.value)
if (!messageRef.value || !dataRef.value) return
if (dataRef.value && typeof dataRef.value === 'object') {
if ('status' in dataRef.value && 'message' in dataRef.value) {
if ('status' in dataRef.value && ('message' in dataRef.value || 'msg' in dataRef.value)) {
const { request } = useMessage() // 消息提示
console.log(dataRef.value, '+++++++')
const { status, message } = dataRef.value
if (message) request({ status, message })
const { status, message, msg } = dataRef.value
if (message || msg) request({ status, message: message || msg })
}
}
}

View File

@@ -1,51 +1,51 @@
{
"name": "@baota/naive-ui",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "vite",
"test": "vitest",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"
},
"exports": {
"./hooks": "./src/hooks/index.tsx",
"./types/*": "./src/types/*.d.ts",
"./theme": "./src/theme/index.tsx",
"./components/*": "./src/components/*.tsx",
"./i18n": "./src/i18n/index.tsx"
},
"dependencies": {
"@vueuse/core": "^10.7.0",
"naive-ui": "^2.41.0",
"vue": "^3.5.13",
"vue-router": "4",
"vue-i18n": "^11.1.2",
"axios": "^1.8.4",
"@vicons/antd": "^0.13.0",
"@vicons/fluent": "^0.13.0",
"@vicons/ionicons5": "^0.13.0"
},
"devDependencies": {
"@baota/eslint": "workspace:*",
"@baota/typescript": "workspace:*",
"@baota/prettier": "workspace:*",
"@baota/utils": "workspace:*",
"@types/node": "^20.10.5",
"@vitejs/plugin-vue": "^4.5.2",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.5.1",
"tailwindcss": "^3.4.17",
"vite": "^5.0.10",
"vitest": "^1.0.4",
"vue-tsc": "^1.8.25"
},
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"peerDependencies": {
"vue": "^3.5.13",
"vue-i18n": "^11.1.2"
}
}
"name": "@baota/naive-ui",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "vite",
"test": "vitest",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"
},
"exports": {
"./hooks": "./src/hooks/index.tsx",
"./types/*": "./src/types/*.d.ts",
"./theme": "./src/theme/index.tsx",
"./components/*": "./src/components/*.tsx",
"./i18n": "./src/i18n/index.tsx"
},
"dependencies": {
"@vueuse/core": "^10.7.0",
"naive-ui": "^2.41.0",
"vue": "^3.5.13",
"vue-router": "4",
"vue-i18n": "^11.1.2",
"axios": "^1.8.4",
"@vicons/antd": "^0.13.0",
"@vicons/fluent": "^0.13.0",
"@vicons/ionicons5": "^0.13.0"
},
"devDependencies": {
"@baota/eslint": "workspace:*",
"@baota/typescript": "workspace:*",
"@baota/prettier": "workspace:*",
"@baota/utils": "workspace:*",
"@types/node": "^20.10.5",
"@vitejs/plugin-vue": "^4.5.2",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"autoprefixer": "^10.4.20",
"postcss": "^8.5.1",
"tailwindcss": "^3.4.17",
"vite": "^5.0.10",
"vitest": "^1.0.4",
"vue-tsc": "^1.8.25"
},
"main": "index.js",
"keywords": [],
"author": "",
"license": "ISC",
"peerDependencies": {
"vue": "^3.5.13",
"vue-i18n": "^11.1.2"
}
}

View File

@@ -1,5 +1,4 @@
<template>
<!-- 主容器最小高度为屏幕高度使用浅灰色背景 -->
<div class="min-h-screen bg-white">
<div class="container mx-auto py-8">
<!-- 页面标题 -->

View File

@@ -1,4 +1,4 @@
import { defineComponent, watch } from 'vue'
import { defineComponent } from 'vue'
import {
NConfigProvider,
NDialogProvider,

View File

@@ -44,7 +44,6 @@ import {
type FormProps,
type FormItemProps,
type CheckboxGroupProps,
SwitchSlots,
} from 'naive-ui'
import { DownOutlined, UpOutlined } from '@vicons/antd'
import { translation, TranslationModule, type TranslationLocale } from '../locals/translation'
@@ -152,7 +151,10 @@ const createFormItem = <T extends keyof typeof componentMap>(
type: T,
props: FormElementPropsMap[T],
itemAttrs?: FormItemProps,
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
const { prefixElements, suffixElements } = processFormItemSlots(slot)
return {
@@ -184,12 +186,12 @@ export default function useForm<T>(options: UseFormOptions<T>) {
// 创建 effectScope 用于管理响应式副作用
const scope = effectScope()
return scope.run(() => {
const { config, request, defaultValue = {}, rules: rulesVal } = options
const { config, request, defaultValue = ref({}), rules: rulesVal } = options
// 表单响应式状态
const loading = ref(false) // 表单加载状态
const formRef = ref<FormInst | null>(null) // 表单实例引用
const data = isRef(defaultValue) ? (defaultValue as Ref<T>) : ref(defaultValue as T) // 使用ref而不是reactive避免响应丢失
const data: Ref<T> = isRef(defaultValue) ? (defaultValue as Ref<T>) : (ref(defaultValue) as Ref<T>) // 使用ref而不是reactive避免响应丢失
const formConfig = ref<FormConfig>(config) // 表单配置
const rules = shallowRef({ ...rulesVal }) // 表单验证规则
@@ -371,16 +373,19 @@ export default function useForm<T>(options: UseFormOptions<T>) {
/**
* 提交表单
* 验证表单并调用提交请求函数
* @param
* @returns 返回一个Promise解析为请求的响应结果
*/
const fetch = async () => {
const fetch = async (isValid = true) => {
if (!request) return
try {
loading.value = true
if (!isValid) return await request(data.value, formRef)
const valid = await validate()
if (!valid) throw new Error('表单验证失败')
return await request(data.value, formRef)
} catch (error) {
console.log(error)
throw new Error('表单验证失败')
} finally {
loading.value = false
@@ -432,7 +437,10 @@ const useFormInput = (
key: string,
other?: InputProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => createFormItem(label, key, 'input', { placeholder: hookT('placeholder', label), ...other }, itemAttrs, slot)
/**
@@ -449,7 +457,10 @@ const useFormTextarea = (
key: string,
other?: InputProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) =>
createFormItem(
label,
@@ -474,7 +485,10 @@ const useFormPassword = (
key: string,
other?: InputProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) =>
createFormItem(
label,
@@ -499,7 +513,10 @@ const useFormInputNumber = (
key: string,
other?: InputNumberProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => createFormItem(label, key, 'inputNumber', { showButton: false, ...other }, itemAttrs, slot)
/**
@@ -593,7 +610,10 @@ const useFormSelect = (
options: SelectOption[],
other?: SelectProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'select', { options, ...other }, itemAttrs, slot)
}
@@ -632,7 +652,10 @@ const useFormRadio = (
options: RadioOptionItem[],
other?: RadioProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'radio', { options, ...other }, itemAttrs, slot || {})
}
@@ -648,7 +671,10 @@ const useFormRadioButton = (
options: RadioOptionItem[],
other?: RadioButtonProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'radioButton', { options, ...other }, itemAttrs, slot || {})
}
@@ -663,7 +689,10 @@ const useFormCheckbox = (
options: CheckboxOptionItem[],
other?: Partial<CheckboxGroupProps> & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'checkbox', { options, ...other } as any, itemAttrs, slot || {})
}
@@ -678,7 +707,10 @@ const useFormSwitch = (
key: string,
other?: SwitchProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'switch', { ...other }, itemAttrs, slot)
}
@@ -693,7 +725,10 @@ const useFormDatepicker = (
key: string,
other?: DatePickerProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'datepicker', { ...other }, itemAttrs, slot)
}
@@ -708,7 +743,10 @@ const useFormTimepicker = (
key: string,
other?: TimePickerProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'timepicker', { ...other }, itemAttrs, slot)
}
@@ -723,7 +761,10 @@ const useFormSlider = (
key: string,
other?: SliderProps & { class?: string },
itemAttrs?: FormItemProps & { class?: string },
slot?: { prefix?: Array<() => JSX.Element>; suffix?: Array<() => JSX.Element> },
slot?: {
prefix?: Array<() => JSX.Element>
suffix?: Array<() => JSX.Element>
},
) => {
return createFormItem(label, key, 'slider', { ...other }, itemAttrs, slot)
}

View File

@@ -48,7 +48,6 @@ export function useMessage(): MessageApiExtended {
...options,
onAfterLeave: () => {
options.onAfterLeave?.()
unmount()
},
}
return method(content, newOptions)
@@ -67,7 +66,6 @@ export function useMessage(): MessageApiExtended {
...options,
onAfterLeave: () => {
options.onAfterLeave?.()
unmount()
},
}

View File

@@ -1,411 +1,454 @@
import {
type Component,
type VNodeChild,
ref,
h,
getCurrentInstance,
provide,
defineComponent,
inject,
App,
Ref,
computed,
ComputedRef,
} from 'vue'
type Component,
type VNodeChild,
ref,
h,
getCurrentInstance,
provide,
defineComponent,
inject,
App,
Ref,
computed,
ComputedRef,
} from "vue";
import {
useModal as useNaiveModal,
createDiscreteApi,
type ButtonProps,
type ModalReactive,
NButton,
ModalOptions,
} from 'naive-ui'
import { isBoolean } from '@baota/utils/type'
import { useTheme } from '../theme'
import { translation } from '../locals/translation'
useModal as useNaiveModal,
createDiscreteApi,
type ButtonProps,
type ModalReactive,
NButton,
ModalOptions,
} from "naive-ui";
import { isBoolean } from "@baota/utils/type";
import { useTheme } from "../theme";
import { translation } from "../locals/translation";
import customProvider from '../components/customProvider'
import customProvider from "../components/customProvider";
// 定义provide/inject的key
export const MODAL_CLOSE_KEY = Symbol('modal-close')
export const MODAL_CLOSEABLE_KEY = Symbol('modal-closeable')
export const MODAL_LOADING_KEY = Symbol('modal-loading')
export const MODAL_CONFIRM_KEY = Symbol('modal-confirm')
export const MODAL_CANCEL_KEY = Symbol('modal-cancel')
export const MODAL_CLOSE_KEY = Symbol("modal-close");
export const MODAL_CLOSEABLE_KEY = Symbol("modal-closeable");
export const MODAL_LOADING_KEY = Symbol("modal-loading");
export const MODAL_CONFIRM_KEY = Symbol("modal-confirm");
export const MODAL_CANCEL_KEY = Symbol("modal-cancel");
// export const MODAL_I18N_KEY = Symbol('modal-i18n')e')
export const MODAL_MESSAGE_KEY = Symbol('modal-message')
export const MODAL_OPTIONS_KEY = Symbol('modal-options')
export const MODAL_MESSAGE_KEY = Symbol("modal-message");
export const MODAL_OPTIONS_KEY = Symbol("modal-options");
// 自定义Modal配置类型
export interface CustomModalOptions {
title?: string | (() => VNodeChild) // 标题
area?: string | string[] | number | number[] // 视图大小
maskClosable?: boolean // 是否可通过遮罩层关闭
destroyOnClose?: boolean // 是否在关闭时销毁
draggable?: boolean // 是否可拖拽
closable?: boolean // 是否显示关闭按钮
footer?: boolean | (() => VNodeChild) // 是否显示底部按钮
confirmText?: string | Ref<string> | ComputedRef<string> // 确认按钮文本
cancelText?: string | Ref<string> | ComputedRef<string> // 取消按钮文本
modalStyle?: Record<string, any> // 弹窗样式
confirmButtonProps?: ButtonProps // 确认按钮props
cancelButtonProps?: ButtonProps // 取消按钮props
component?: (() => Promise<Component>) | Component // 组件
componentProps?: Record<string, unknown> // 组件props
onConfirm?: (close: () => void) => Promise<unknown> | void // 确认回调
onCancel?: (close: () => void) => Promise<unknown> | void // 取消回调
onClose?: (close: () => void) => void // 关闭回调
onUpdateShow?: (show: boolean) => void // 更新显示状态回调
modelOptions?: ModalOptions // Modal配置
'z-index'?: number
title?: string | (() => VNodeChild); // 标题
area?: string | string[] | number | number[]; // 视图大小
maskClosable?: boolean; // 是否可通过遮罩层关闭
destroyOnClose?: boolean; // 是否在关闭时销毁
draggable?: boolean; // 是否可拖拽
closable?: boolean; // 是否显示关闭按钮
footer?: boolean | (() => VNodeChild); // 是否显示底部按钮
confirmText?: string | Ref<string> | ComputedRef<string>; // 确认按钮文本
cancelText?: string | Ref<string> | ComputedRef<string>; // 取消按钮文本
modalStyle?: Record<string, any>; // 弹窗样式
confirmButtonProps?: ButtonProps; // 确认按钮props
cancelButtonProps?: ButtonProps; // 取消按钮props
component?: (() => Promise<Component>) | Component; // 组件
componentProps?: Record<string, unknown>; // 组件props
onConfirm?: (close: () => void) => Promise<unknown> | void; // 确认回调
onCancel?: (close: () => void) => Promise<unknown> | void; // 取消回调
onClose?: (close: () => void) => void; // 关闭回调
onUpdateShow?: (show: boolean) => void; // 更新显示状态回调
modelOptions?: ModalOptions; // Modal配置
"z-index"?: number;
}
const appsUseList = {
router: null,
i18n: null,
pinia: null,
}
router: null,
i18n: null,
pinia: null,
};
// 挂载资源
const mountApps = (app: App, resources: any) => {
if (app && resources) app.use(resources)
}
console.log(app && resources);
if (app && resources) app.use(resources);
};
// 自定义Modal钩子函数
const useModal = (options: CustomModalOptions) => {
const { theme, themeOverrides } = useTheme()
console.log(themeOverrides.value, theme.value)
// 创建discreteModal实例 - 这个可以在任何地方使用
const { modal, message, unmount, app } = createDiscreteApi(['modal', 'message'], {
configProviderProps: { theme: theme.value, themeOverrides: themeOverrides.value },
})
const { theme, themeOverrides } = useTheme();
// 创建discreteModal实例 - 这个可以在任何地方使用
const { modal, message, unmount, app } = createDiscreteApi(
["modal", "message"],
{
configProviderProps: {
theme: theme.value,
themeOverrides: themeOverrides.value,
},
}
);
mountApps(app, appsUseList['i18n'])
mountApps(app, appsUseList['router'])
mountApps(app, appsUseList['pinia'])
mountApps(app, appsUseList["i18n"]);
mountApps(app, appsUseList["router"]);
mountApps(app, appsUseList["pinia"]);
// 判断是否在setup中使用
const instance = getCurrentInstance()
// 控制Modal显示状态
const visible = ref(false)
// Modal实例引用
const modalInstance = ref<ModalReactive | null>(null)
// 获取naiveModal实例 - 只在setup中使用
const getNaiveModal = () => {
if (instance) {
return useNaiveModal()
}
return null
}
// 判断是否在setup中使用
const instance = getCurrentInstance();
// 控制Modal显示状态
const visible = ref(false);
// Modal实例引用
const modalInstance = ref<ModalReactive | null>(null);
// 获取naiveModal实例 - 只在setup中使用
const getNaiveModal = () => {
if (instance) {
return useNaiveModal();
}
return null;
};
// const naiveModal = getNaiveModal()
// 获取组件实例引用
const wrapperRef = ref()
// 创建Modal方法
const create = async (optionsNew: CustomModalOptions) => {
const {
component,
componentProps,
onConfirm,
onCancel,
footer = false,
confirmText,
cancelText,
confirmButtonProps = { type: 'primary' },
cancelButtonProps = { type: 'default' },
...modelOptions
} = optionsNew
// const naiveModal = getNaiveModal()
// 获取组件实例引用
const wrapperRef = ref();
// 创建Modal方法
const create = async (optionsNew: CustomModalOptions) => {
const {
component,
componentProps,
onConfirm,
onCancel,
footer = false,
confirmText,
cancelText,
confirmButtonProps = { type: "primary" },
cancelButtonProps = { type: "default" },
...modelOptions
} = optionsNew;
const optionsRef = ref({ footer, confirmText, cancelText, confirmButtonProps, cancelButtonProps })
const optionsRef = ref({
footer,
confirmText,
cancelText,
confirmButtonProps,
cancelButtonProps,
});
// 处理视图高度和宽度
const getViewSize = (areaNew: string | string[] | number | number[] = '50%') => {
if (Array.isArray(areaNew)) {
return {
width: typeof areaNew[0] === 'number' ? areaNew[0] + 'px' : areaNew[0],
height: typeof areaNew[1] === 'number' ? areaNew[1] + 'px' : areaNew[1],
}
}
return {
width: typeof areaNew === 'number' ? areaNew + 'px' : areaNew,
height: 'auto',
}
}
// 处理视图高度和宽度
const getViewSize = (
areaNew: string | string[] | number | number[] = "50%"
) => {
if (Array.isArray(areaNew)) {
return {
width:
typeof areaNew[0] === "number" ? areaNew[0] + "px" : areaNew[0],
height:
typeof areaNew[1] === "number" ? areaNew[1] + "px" : areaNew[1],
};
}
return {
width: typeof areaNew === "number" ? areaNew + "px" : areaNew,
height: "auto",
};
};
// 处理组件
const content = async () => {
if (typeof component === 'function') {
try {
// 处理异步组件函数
const syncComponent = await (component as () => Promise<Component>)()
return syncComponent.default || syncComponent
} catch (e) {
// 处理普通函数组件
return component
}
}
return component
}
// 处理组件
const content = async () => {
if (typeof component === "function") {
try {
// 处理异步组件函数
const syncComponent = await (component as () => Promise<Component>)();
return syncComponent.default || syncComponent;
} catch (e) {
// 处理普通函数组件
return component;
}
}
return component;
};
// 组件
const componentNew = (await content()) as Component
// 视图大小
const { width, height } = await getViewSize(optionsNew.area)
// 组件
const componentNew = (await content()) as Component;
// 视图大小
const { width, height } = await getViewSize(optionsNew.area);
// 存储组件内部注册的方法
const confirmHandler = ref<(close: () => void) => Promise<void> | void>()
const cancelHandler = ref<(close: () => void) => Promise<void> | void>()
const closeable = ref(true)
const loading = ref(false)
// 存储组件内部注册的方法
const confirmHandler = ref<(close: () => void) => Promise<void> | void>();
const cancelHandler = ref<(close: () => void) => Promise<void> | void>();
const closeable = ref(true);
const loading = ref(false);
// 获取当前语言
const currentLocale = localStorage.getItem('activeLocales') || '"zhCN"'
// 获取翻译文本
const hookT = (key: string) => {
const locale = currentLocale.replace('-', '_').replace(/"/g, '')
return (
translation[locale as keyof typeof translation]?.useModal?.[key as keyof typeof translation.zhCN.useModal] ||
translation.zhCN.useModal[key as keyof typeof translation.zhCN.useModal]
)
}
// 获取当前语言
const currentLocale = localStorage.getItem("activeLocales") || '"zhCN"';
// 获取翻译文本
const hookT = (key: string) => {
const locale = currentLocale.replace("-", "_").replace(/"/g, "");
return (
translation[locale as keyof typeof translation]?.useModal?.[
key as keyof typeof translation.zhCN.useModal
] ||
translation.zhCN.useModal[key as keyof typeof translation.zhCN.useModal]
);
};
const closeMessage = ref(hookT('cannotClose'))
const closeMessage = ref(hookT("cannotClose"));
// 合并Modal配置
const config: ModalOptions = {
preset: 'card',
style: { width, height, ...modelOptions.modalStyle },
closeOnEsc: false,
maskClosable: false,
onClose: () => {
if (!closeable.value || loading.value) {
message.error(closeMessage.value)
return false
}
// 调用组件内注册的取消方法
cancelHandler.value?.()
// 调用外部传入的取消回调
onCancel?.(() => {})
unmount() // 卸载
return true
},
content: () => {
const Wrapper = defineComponent({
setup() {
// 提供Modal配置
provide(MODAL_OPTIONS_KEY, optionsRef)
// 合并Modal配置
const config: ModalOptions = {
preset: "card",
style: { width, height, ...modelOptions.modalStyle },
closeOnEsc: false,
maskClosable: false,
onClose: () => {
if (!closeable.value || loading.value) {
message.error(closeMessage.value);
return false;
}
// 调用组件内注册的取消方法
cancelHandler.value?.();
// 调用外部传入的取消回调
onCancel?.(() => {});
unmount(); // 卸载
return true;
},
content: () => {
const Wrapper = defineComponent({
setup() {
// 提供Modal配置
provide(MODAL_OPTIONS_KEY, optionsRef);
// 提供关闭方法
provide(MODAL_CLOSE_KEY, close)
// 提供关闭方法
provide(MODAL_CLOSE_KEY, close);
// 提供信息方法
provide(MODAL_MESSAGE_KEY, message)
// 提供信息方法
provide(MODAL_MESSAGE_KEY, message);
// 模块-确认按钮
provide(MODAL_CONFIRM_KEY, (handler: (close: () => void) => Promise<void> | void) => {
confirmHandler.value = handler
})
// 模块-确认按钮
provide(
MODAL_CONFIRM_KEY,
(handler: (close: () => void) => Promise<void> | void) => {
confirmHandler.value = handler;
}
);
// 模块-取消按钮
provide(MODAL_CANCEL_KEY, (handler: (close: () => void) => Promise<void> | void) => {
cancelHandler.value = handler
})
// 模块-取消按钮
provide(
MODAL_CANCEL_KEY,
(handler: (close: () => void) => Promise<void> | void) => {
cancelHandler.value = handler;
}
);
// 模块 - 可关闭状态
provide(MODAL_CLOSEABLE_KEY, (canClose: boolean) => {
closeable.value = canClose
})
// 模块 - 可关闭状态
provide(MODAL_CLOSEABLE_KEY, (canClose: boolean) => {
closeable.value = canClose;
});
// 模块-过度
provide(MODAL_LOADING_KEY, (loadStatus: boolean, closeMsg?: string) => {
loading.value = loadStatus
closeMessage.value = closeMsg || hookT('cannotClose')
})
// 模块-过度
provide(
MODAL_LOADING_KEY,
(loadStatus: boolean, closeMsg?: string) => {
loading.value = loadStatus;
closeMessage.value = closeMsg || hookT("cannotClose");
}
);
// 暴露给父级使用
return {
confirmHandler,
cancelHandler,
render: () => h(componentNew as Component, { ...componentProps }),
}
},
render() {
return this.render()
},
})
// 暴露给父级使用
return {
confirmHandler,
cancelHandler,
render: () => h(componentNew as Component, { ...componentProps }),
};
},
render() {
return this.render();
},
});
const wrapper = instance ? h(Wrapper) : h(customProvider, {}, () => h(Wrapper))
const wrapper = instance
? h(Wrapper)
: h(customProvider, {}, () => h(Wrapper));
return h(wrapper, { ref: wrapperRef })
},
// onAfterLeave: () => {
// // 调用组件内注册的取消方法
// cancelHandler.value?.()
// // 调用外部传入的取消回调
// onCancel?.(() => {})
// },
}
const footerComp = computed(() => {
if (isBoolean(optionsRef.value.footer) && optionsRef.value.footer) {
// 确认事件
const confirmEvent = async () => {
await confirmHandler.value?.(close)
// 调用外部传入的确认回调
await onConfirm?.(close)
}
// 取消事件
const cancelEvent = async () => {
await cancelHandler.value?.(close)
// 调用外部传入的取消回调
await onCancel?.(close)
if (!cancelHandler.value && !onCancel) {
close()
}
}
return (
<div class="flex justify-end">
<NButton
disabled={loading.value}
{...cancelButtonProps}
style={{ marginRight: '8px' }}
onClick={cancelEvent}
>
{optionsRef.value.cancelText || hookT('cancel')}
</NButton>
<NButton disabled={loading.value} {...confirmButtonProps} onClick={confirmEvent}>
{optionsRef.value.confirmText || hookT('confirm')}
</NButton>
</div>
)
}
return null
})
// 底部按钮配置
if (optionsRef.value.footer) config.footer = () => footerComp.value
// 合并Modal配置
Object.assign(config, modelOptions)
if (instance) {
const currentNaiveModal = getNaiveModal()
if (currentNaiveModal) {
modalInstance.value = currentNaiveModal.create(config)
return modalInstance.value
}
}
// 使用createDiscreteApi创建
const discreteModal = modal.create(config)
modalInstance.value = discreteModal
options.onUpdateShow?.(true)
return discreteModal
}
return h(wrapper, { ref: wrapperRef });
},
// onAfterLeave: () => {
// // 调用组件内注册的取消方法
// cancelHandler.value?.()
// // 调用外部传入的取消回调
// onCancel?.(() => {})
// },
};
const footerComp = computed(() => {
if (isBoolean(optionsRef.value.footer) && optionsRef.value.footer) {
// 确认事件
const confirmEvent = async () => {
await confirmHandler.value?.(close);
// 调用外部传入的确认回调
await onConfirm?.(close);
};
// 取消事件
const cancelEvent = async () => {
await cancelHandler.value?.(close);
// 调用外部传入的取消回调
await onCancel?.(close);
if (!cancelHandler.value && !onCancel) {
close();
}
};
return (
<div class="flex justify-end">
<NButton
disabled={loading.value}
{...cancelButtonProps}
style={{ marginRight: "8px" }}
onClick={cancelEvent}
>
{optionsRef.value.cancelText || hookT("cancel")}
</NButton>
<NButton
disabled={loading.value}
{...confirmButtonProps}
onClick={confirmEvent}
>
{optionsRef.value.confirmText || hookT("confirm")}
</NButton>
</div>
);
}
return null;
});
// 底部按钮配置
if (optionsRef.value.footer) config.footer = () => footerComp.value;
// 合并Modal配置
Object.assign(config, modelOptions);
if (instance) {
const currentNaiveModal = getNaiveModal();
if (currentNaiveModal) {
modalInstance.value = currentNaiveModal.create(config);
return modalInstance.value;
}
}
// 使用createDiscreteApi创建
const discreteModal = modal.create(config);
modalInstance.value = discreteModal;
options.onUpdateShow?.(true);
return discreteModal;
};
// 关闭Modal方法
const close = () => {
visible.value = false
if (modalInstance.value) {
modalInstance.value.destroy()
}
options.onUpdateShow?.(false)
}
// 关闭Modal方法
const close = () => {
visible.value = false;
if (modalInstance.value) {
modalInstance.value.destroy();
}
options.onUpdateShow?.(false);
};
// 销毁所有Modal实例方法
const destroyAll = () => {
// 销毁当前实例
if (modalInstance.value) {
modalInstance.value.destroy()
modalInstance.value = null
}
visible.value = false
// 销毁所有实例
const currentNaiveModal = getNaiveModal()
if (currentNaiveModal) {
currentNaiveModal.destroyAll()
} else {
modal.destroyAll()
}
}
// 销毁所有Modal实例方法
const destroyAll = () => {
// 销毁当前实例
if (modalInstance.value) {
modalInstance.value.destroy();
modalInstance.value = null;
}
visible.value = false;
// 销毁所有实例
const currentNaiveModal = getNaiveModal();
if (currentNaiveModal) {
currentNaiveModal.destroyAll();
} else {
modal.destroyAll();
}
};
// 更新显示状态
const updateShow = (show: boolean) => {
visible.value = show
}
// 更新显示状态
const updateShow = (show: boolean) => {
visible.value = show;
};
return {
...create(options),
updateShow,
close,
destroyAll,
}
}
return {
...create(options),
updateShow,
close,
destroyAll,
};
};
/**
* @description 重新设置Modal配置的钩子函数
* @returns {Object} Modal配置
*/
export const useModalOptions = (): Ref<CustomModalOptions> => {
return inject(MODAL_OPTIONS_KEY, ref({}))
}
return inject(MODAL_OPTIONS_KEY, ref({}));
};
/**
* @description 获取Modal关闭方法的钩子函数
*/
export const useModalClose = () =>
inject(MODAL_CLOSE_KEY, () => {
console.warn('useModalClose 必须在 Modal 组件内部使用')
})
inject(MODAL_CLOSE_KEY, () => {
console.warn("useModalClose 必须在 Modal 组件内部使用");
});
/**
* @description 注册Modal确认按钮点击处理方法的钩子函数
* @param handler 确认按钮处理函数接收一个关闭Modal的函数作为参数
* @returns void
*/
export const useModalConfirm = (handler: (close: () => void) => Promise<any> | void) => {
const registerConfirm = inject(MODAL_CONFIRM_KEY, (fn: (close: () => void) => Promise<void> | void) => {
console.warn('useModalConfirm 必须在 Modal 组件内部使用')
return
})
// 注册确认处理方法
registerConfirm(handler)
}
export const useModalConfirm = (
handler: (close: () => void) => Promise<any> | void
) => {
const registerConfirm = inject(
MODAL_CONFIRM_KEY,
(fn: (close: () => void) => Promise<void> | void) => {
console.warn("useModalConfirm 必须在 Modal 组件内部使用");
return;
}
);
// 注册确认处理方法
registerConfirm(handler);
};
/**
* @description 注册Modal取消按钮点击处理方法的钩子函数
* @param handler 取消按钮处理函数接收一个关闭Modal的函数作为参数
* @returns void
*/
export const useModalCancel = (handler: (close: () => void) => Promise<void> | void) => {
const registerCancel = inject(MODAL_CANCEL_KEY, (fn: (close: () => void) => Promise<void> | void) => {
console.warn('useModalCancel 必须在 Modal 组件内部使用')
return
})
// 注册取消处理方法
registerCancel(handler)
}
export const useModalCancel = (
handler: (close: () => void) => Promise<void> | void
) => {
const registerCancel = inject(
MODAL_CANCEL_KEY,
(fn: (close: () => void) => Promise<void> | void) => {
console.warn("useModalCancel 必须在 Modal 组件内部使用");
return;
}
);
// 注册取消处理方法
registerCancel(handler);
};
/**
* @description 控制Modal是否可关闭的钩子函数
* @returns {(canClose: boolean) => void} 设置Modal可关闭状态的函数
*/
export const useModalCloseable = () => {
const registerCloseable = inject(MODAL_CLOSEABLE_KEY, (canClose: boolean) => {
console.warn('useModalCloseable 必须在 Modal 组件内部使用')
return
})
return registerCloseable
}
const registerCloseable = inject(MODAL_CLOSEABLE_KEY, (canClose: boolean) => {
console.warn("useModalCloseable 必须在 Modal 组件内部使用");
return;
});
return registerCloseable;
};
/**
* @description 获取Modal消息提示实例的钩子函数
* @returns {Object} Message消息实例包含loading, success, error, warning, info等方法
*/
export const useModalMessage = () => {
const message = inject(MODAL_MESSAGE_KEY, {
loading: (str: string) => {},
success: (str: string) => {},
error: (str: string) => {},
warning: (str: string) => {},
info: (str: string) => {},
})
return message
}
const message = inject(MODAL_MESSAGE_KEY, {
loading: (str: string) => {},
success: (str: string) => {},
error: (str: string) => {},
warning: (str: string) => {},
info: (str: string) => {},
});
return message;
};
/**
* @description 控制Modal加载状态的钩子函数
@@ -413,59 +456,62 @@ export const useModalMessage = () => {
* loadStatus为true时显示加载状态并禁止关闭closeMsg为自定义禁止关闭时的提示消息
*/
export const useModalLoading = () => {
const registerLoading = inject(MODAL_LOADING_KEY, (loadStatus: boolean, closeMsg?: string) => {
console.warn('useModalLoading 必须在 Modal 组件内部使用')
return
})
return registerLoading
}
const registerLoading = inject(
MODAL_LOADING_KEY,
(loadStatus: boolean, closeMsg?: string) => {
console.warn("useModalLoading 必须在 Modal 组件内部使用");
return;
}
);
return registerLoading;
};
/**
* @description 获取Modal所有钩子函数的集合
* @returns {Object} 包含所有Modal相关钩子函数的对象
*/
export const useModalHooks = () => ({
/**
* 设置Modal配置用于修改Modal的配置
*/
options: useModalOptions,
/**
* 设置Modal配置用于修改Modal的配置
*/
options: useModalOptions,
/**
* 关闭当前Modal的函数
*/
close: useModalClose,
/**
* 关闭当前Modal的函数
*/
close: useModalClose,
/**
* 注册Modal确认按钮点击处理方法
*/
confirm: useModalConfirm,
/**
* 注册Modal确认按钮点击处理方法
*/
confirm: useModalConfirm,
/**
* 注册Modal取消按钮点击处理方法
*/
cancel: useModalCancel,
/**
* 注册Modal取消按钮点击处理方法
*/
cancel: useModalCancel,
/**
* 设置Modal是否可关闭的状态控制函数
*/
closeable: useModalCloseable,
/**
* 设置Modal是否可关闭的状态控制函数
*/
closeable: useModalCloseable,
/**
* 获取Modal内部可用的消息提示实例
*/
message: useModalMessage,
/**
* 获取Modal内部可用的消息提示实例
*/
message: useModalMessage,
/**
* 设置Modal加载状态的控制函数
*/
loading: useModalLoading,
})
/**
* 设置Modal加载状态的控制函数
*/
loading: useModalLoading,
});
// 设置资源
export const useModalUseDiscrete = ({ router, i18n, pinia }: any) => {
appsUseList['i18n'] = i18n
appsUseList['router'] = router
appsUseList['pinia'] = pinia
}
appsUseList["i18n"] = i18n || false;
appsUseList["router"] = router || false;
appsUseList["pinia"] = pinia || false;
};
export default useModal
export default useModal;

View File

@@ -2,7 +2,6 @@ import { ref, shallowRef, ShallowRef, Ref, effectScope, watch, onUnmounted, isRe
import {
type DataTableProps,
type DataTableSlots,
type DataTableColumns,
type PaginationProps,
type PaginationSlots,
NDataTable,
@@ -298,6 +297,7 @@ export default function useTable<T = Record<string, any>, Z extends Record<strin
list: rdata[tableAlias.value.list as keyof TableResponse<T>] as [],
total: rdata[tableAlias.value.total as keyof TableResponse<T>] as number,
}
console.log(data.value)
// 如果需要重置页码,则重置页码
if (resetPage) (param.value as Record<string, unknown>)[page] = 1
return data.value
@@ -336,6 +336,11 @@ export default function useTable<T = Record<string, any>, Z extends Record<strin
mergedProps.scrollX = dynamicScrollX.value
}
watch(data.value, (newVal) => {
console.log(data.value)
})
return (
<NDataTable
remote

View File

@@ -15,7 +15,7 @@ const defaultLight: ThemeTemplate = {
title: '默认亮色主题', // 主题名称
themeOverrides: {
common: {
borderRadius: '0.6rem', // 圆角
// borderRadius: '0.6rem', // 圆角
// primaryColor: '#4caf50', // 主色
// primaryColorHover: '#20a53a', // 主色悬停
// primaryColorPressed: '#157f3a', // 主色按下

View File

@@ -1,148 +1,151 @@
import type {
FormRules,
FormProps,
FormItemProps,
GridProps,
InputProps,
InputNumberProps,
SelectProps,
RadioGroupProps,
RadioProps,
RadioButtonProps,
CheckboxGroupProps,
SwitchProps,
DatePickerProps,
TimePickerProps,
ColorPickerProps,
SliderProps,
RateProps,
TransferProps,
MentionProps,
DynamicInputProps,
AutoCompleteProps,
CascaderProps,
TreeSelectProps,
UploadProps,
InputGroupProps,
FormInst,
FormProps,
GridItemProps,
} from 'naive-ui'
import type { Ref, ShallowRef, ComputedRef, ToRefs } from 'vue'
FormRules,
FormProps,
FormItemProps,
GridProps,
InputProps,
InputNumberProps,
SelectProps,
RadioGroupProps,
RadioProps,
RadioButtonProps,
CheckboxGroupProps,
SwitchProps,
DatePickerProps,
TimePickerProps,
ColorPickerProps,
SliderProps,
RateProps,
TransferProps,
MentionProps,
DynamicInputProps,
AutoCompleteProps,
CascaderProps,
TreeSelectProps,
UploadProps,
InputGroupProps,
FormInst,
FormProps,
GridItemProps,
} from "naive-ui";
import type { Ref, ShallowRef, ComputedRef, ToRefs } from "vue";
/** 选项接口 */
export interface RadioOptionItem extends Partial<RadioProps> {
label: string
value: string | number
label: string;
value: string | number;
}
/** 复选框选项接口 */
export interface CheckboxOptionItem extends Partial<CheckboxProps> {
label: string
value: string | number
label: string;
value: string | number;
}
/** 表单元素类型定义 */
export type FormElementType =
| 'input' // 输入框
| 'inputNumber' // 数字输入框
| 'inputGroup' // 输入框组
| 'select' // 选择器
| 'radio' // 单选框
| 'radioButton' // 单选按钮
| 'checkbox' // 复选框
| 'switch' // 开关
| 'datepicker' // 日期选择器
| 'timepicker' // 时间选择器
| 'colorPicker' // 颜色选择器
| 'slider' // 滑块
| 'rate' // 评分
| 'transfer' // 穿梭框
| 'mention' // 提及
| 'dynamicInput' // 动态输入
| 'dynamicTags' // 动态标签
| 'autoComplete' // 自动完成
| 'cascader' // 级联选择
| 'treeSelect' // 树选择
| 'upload' // 上传
| 'uploadDragger' // 拖拽上传
| 'formItem' // 表单项
| 'formItemGi' // 表单项 - Grid
| 'slot' // 插槽
| 'render' // 自定义渲染
| "input" // 输入框
| "inputNumber" // 数字输入框
| "inputGroup" // 输入框组
| "select" // 选择器
| "radio" // 单选框
| "radioButton" // 单选按钮
| "checkbox" // 复选框
| "switch" // 开关
| "datepicker" // 日期选择器
| "timepicker" // 时间选择器
| "colorPicker" // 颜色选择器
| "slider" // 滑块
| "rate" // 评分
| "transfer" // 穿梭框
| "mention" // 提及
| "dynamicInput" // 动态输入
| "dynamicTags" // 动态标签
| "autoComplete" // 自动完成
| "cascader" // 级联选择
| "treeSelect" // 树选择
| "upload" // 上传
| "uploadDragger" // 拖拽上传
| "formItem" // 表单项
| "formItemGi" // 表单项 - Grid
| "slot" // 插槽
| "render"; // 自定义渲染
/** Props 类型映射 */
type FormElementPropsMap = {
input: InputProps
inputNumber: InputNumberProps
inputGroup: InputGroupProps
select: SelectProps
radio: RadioProps & { options: RadioOptionItem[] }
radioButton: RadioButtonProps & { options: RadioOptionItem[] }
checkbox: CheckboxGroupProps & { options: CheckboxOptionItem[] }
switch: SwitchProps
datepicker: DatePickerProps
timepicker: TimePickerProps
colorPicker: ColorPickerProps
slider: SliderProps
rate: RateProps
transfer: TransferProps
mention: MentionProps
dynamicInput: DynamicInputProps
dynamicTags: InputProps
autoComplete: AutoCompleteProps
cascader: CascaderProps
treeSelect: TreeSelectProps
upload: UploadProps
uploadDragger: UploadProps
formItem: FormItemProps
formItemGi: FormItemProps & GridProps
}
input: InputProps;
inputNumber: InputNumberProps;
inputGroup: InputGroupProps;
select: SelectProps;
radio: RadioProps & { options: RadioOptionItem[] };
radioButton: RadioButtonProps & { options: RadioOptionItem[] };
checkbox: CheckboxGroupProps & { options: CheckboxOptionItem[] };
switch: SwitchProps;
datepicker: DatePickerProps;
timepicker: TimePickerProps;
colorPicker: ColorPickerProps;
slider: SliderProps;
rate: RateProps;
transfer: TransferProps;
mention: MentionProps;
dynamicInput: DynamicInputProps;
dynamicTags: InputProps;
autoComplete: AutoCompleteProps;
cascader: CascaderProps;
treeSelect: TreeSelectProps;
upload: UploadProps;
uploadDragger: UploadProps;
formItem: FormItemProps;
formItemGi: FormItemProps & GridProps;
};
/** 基础表单元素接口 */
export type BaseFormElement<T extends FormElementType = FormElementType> = {
/** 元素类型 */
type: T
/** 字段名称 */
field: string
} & (T extends keyof FormElementPropsMap ? FormElementPropsMap[T] : Record<string, any>)
/** 元素类型 */
type: T;
/** 字段名称 */
field: string;
} & (T extends keyof FormElementPropsMap
? FormElementPropsMap[T]
: Record<string, any>);
/** 插槽表单元素接口 */
export interface SlotFormElement {
type: 'slot'
/** 插槽名称 */
slot: string
type: "slot";
/** 插槽名称 */
slot: string;
}
/** 自定义渲染表单元素接口 */
export interface RenderFormElement {
type: 'custom'
/** 自定义渲染函数 */
render: (formData: any, formRef: any) => any
type: "custom";
/** 自定义渲染函数 */
render: (formData: any, formRef: any) => any;
}
/** 表单元素联合类型 */
export type FormElement = BaseFormElement | SlotFormElement | RenderFormElement
export type FormElement = BaseFormElement | SlotFormElement | RenderFormElement;
/** 栅格项配置接口 */
export interface GridItemConfig extends Partial<GridProps> {
type: 'grid'
/** 栅格子元素 */
children: FormItemGiConfig[]
type: "grid";
/** 栅格子元素 */
children: FormItemGiConfig[];
}
/** 表单项 - Grid 配置接口 */
export interface FormItemGiConfig extends Partial<FormItemProps & GridItemProps> {
type: 'formItemGi'
/** 栅格子元素 */
children: FormElement[]
export interface FormItemGiConfig
extends Partial<FormItemProps & GridItemProps> {
type: "formItemGi";
/** 栅格子元素 */
children: FormElement[];
}
/** 表单项配置接口 */
export interface FormItemConfig extends Partial<FormItemProps> {
type: 'formItem'
/** 子元素配置 */
children: FormElement[]
type: "formItem";
/** 子元素配置 */
children: FormElement[];
}
/** 表单项 - 自定义渲染配置接口 */
@@ -153,19 +156,26 @@ export interface FormItemConfig extends Partial<FormItemProps> {
// }
/** 表单配置类型 */
export type FormBaseConfig = (FormItemConfi| GridItemConfig | FormItemCustomConfig)[]/** 表单配置类型-动态表单 */
export type FormConfig = Ref<FormBaseConfig> | ComputedRef<FormBaseConfig> | FormBaseConfig
export type FormBaseConfig = (
| FormItemConfi
| GridItemConfig
| FormItemCustomConfig
)[]; /** 表单配置类型-动态表单 */
export type FormConfig =
| Ref<FormBaseConfig>
| ComputedRef<FormBaseConfig>
| FormBaseConfig;
/** 表单 Hook 配置项接口 */
export interface UseFormOptions<T, Z = any> {
/** 表单配置 */
config: FormConfig
/** 表单提交请求函数 */
request?: (data: T, formRef: Ref<FormInst>) => Promise<Z>
/** 默认表单数据 */
defaultValue?: T | Ref<T>
/** 表单验证规则 */
rules?: FormRules
/** 表单配置 */
config: FormConfig;
/** 表单提交请求函数 */
request?: (data: T, formRef: Ref<FormInst>) => Promise<Z>;
/** 默认表单数据 */
defaultValue?: T | Ref<T>;
/** 表单验证规则 */
rules?: FormRules;
}
/**
@@ -173,15 +183,18 @@ export interface UseFormOptions<T, Z = any> {
* 在基础表单实例的基础上添加表单渲染组件方法
*/
export interface FormInstanceWithComponent<T> {
component: (attrs: FormProps, context: unknown) => JSX.Element // 表单渲染组件
example: Ref<FormInst | null> // 表单实例引用
data: Ref<T> // 表单数据引用
loading: Ref<boolean> // 加载状态
config: Ref<FormConfig> // 表单配置引用
props: Ref<FormProps> // 表单属性引用
rules: ShallowRef<FormRules> // 表单验证规则引用
dataToRef: () => ToRefs<T> // 响应式数据转ref
validate: () => Promise<boolean> // 验证方法
fetch: () => Promise<T> // 提交方法
reset: () => void // 重置方法
component: (
attrs: FormProps & ComponentProps,
context: unknown
) => JSX.Element; // 表单渲染组件
example: Ref<FormInst | null>; // 表单实例引用
data: Ref<T>; // 表单数据引用
loading: Ref<boolean>; // 加载状态
config: Ref<FormConfig>; // 表单配置引用
props: Ref<FormProps>; // 表单属性引用
rules: ShallowRef<FormRules>; // 表单验证规则引用
dataToRef: () => ToRefs<T>; // 响应式数据转ref
validate: () => Promise<boolean>; // 验证方法
fetch: () => Promise<T>; // 提交方法
reset: () => void; // 重置方法
}

View File

@@ -40,7 +40,8 @@ export interface TableResponse<T = Record<string, unknown>> {
}
/** 表格 Hook 配置项接口 */
export interface UseTableOptions<T = Record<string, any>, Z extends Record<string, any>> extends Partial<DataTableProps> {
export interface UseTableOptions<T = Record<string, any>, Z extends Record<string, any>>
extends Partial<DataTableProps> {
/** 表格列配置 */
config: DataTableColumns<T>
/** 数据请求函数 */

View File

@@ -38,8 +38,8 @@
}
},
"dependencies": {
"pinia": "^2.3.0",
"pinia-plugin-persistedstate": "^4.2.0"
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0"
},
"devDependencies": {
"@baota/eslint": "workspace:*",

View File

@@ -1,12 +1,12 @@
import type { RouteRecordRaw } from 'vue-router'
import { kebabCase } from '@baota/utils/string'
import type { RouteRecordRaw } from "vue-router";
import { kebabCase } from "@baota/utils/string";
// 路由配置选项
export interface RouteOptions {
framework: string[] // 框架路由
system: string[] // 系统路由
sort: { name: string; title: string }[] // 路由排序
disabled: string[] // 禁用路由
framework: string[]; // 框架路由
system: string[]; // 系统路由
sort: { name: string; title: string }[]; // 路由排序
disabled: string[]; // 禁用路由
}
/**
@@ -23,74 +23,89 @@ export interface RouteOptions {
* src/views/userManagement/children/userDetail/index.tsx -> /user-management/user-detail
*/
export function generateRoutes(
mainRoute: Record<string, () => Promise<unknown>>,
childrenRoutes: Record<string, () => Promise<unknown>>,
routesOptions: RouteOptions,
): { system: RouteRecordRaw[]; framework: RouteRecordRaw[]; routes: RouteRecordRaw[] } {
const { framework, system, sort: routesSort, disabled: routesDisabled } = routesOptions
mainRoute: Record<string, () => Promise<unknown>>,
childrenRoutes: Record<string, () => Promise<unknown>>,
routesOptions: RouteOptions
): {
system: RouteRecordRaw[];
framework: RouteRecordRaw[];
routes: RouteRecordRaw[];
} {
const {
framework,
system,
sort: routesSort,
disabled: routesDisabled,
} = routesOptions;
const routes: RouteRecordRaw[] = [] // 路由列表
const systemRoutes: RouteRecordRaw[] = [] // 系统路由
const frameworkRoutes: RouteRecordRaw[] = [] // 框架路由
const routes: RouteRecordRaw[] = []; // 路由列表
const systemRoutes: RouteRecordRaw[] = []; // 系统路由
const frameworkRoutes: RouteRecordRaw[] = []; // 框架路由
// 导入所有视图组件,基于 src/views 目录
// 使用 Vite 的 import.meta.glob 进行自动导入
const modules = mainRoute
const childrenModules = childrenRoutes
const modulesRegex = /\/views\/([^/]+)\/index\.tsx$/
const childrenModulesRegex = /\/views\/([^/]+)\/children\/([^/]+)\/index\.tsx$/
// 导入所有视图组件,基于 src/views 目录
// 使用 Vite 的 import.meta.glob 进行自动导入
const modules = mainRoute;
const childrenModules = childrenRoutes;
const modulesRegex = /\/views\/([^/]+)\/index\.tsx$/;
const childrenModulesRegex =
/\/views\/([^/]+)\/children\/([^/]+)\/index\.tsx$/;
// 遍历所有视图组件
for (const path in modules) {
// 路由禁用,用于测试和开发处理
if (routesDisabled.includes(path)) continue
// 遍历所有视图组件
for (const path in modules) {
// 路由禁用,用于测试和开发处理
if (routesDisabled.includes(path)) continue;
// 提取路由名称
const routeName = path.match(modulesRegex)![1] || ''
// 提取路由名称
const routeName = path.match(modulesRegex)![1] || "";
// 获取路由中文标题
const metaName = routesSort.find((item) => item.name === routeName)
// 获取路由中文标题
const metaName = routesSort.find((item) => item.name === routeName);
// 创建路由配置
const route: RouteRecordRaw = {
name: routeName,
path: `/${kebabCase(routeName)}`,
meta: { title: metaName?.title || routeName, icon: routeName },
component: modules[path],
children: [],
}
// 创建路由配置
const route: RouteRecordRaw = {
name: routeName,
path: `/${kebabCase(routeName)}`,
meta: { title: metaName?.title || routeName, icon: routeName },
component: modules[path],
children: [],
};
// 系统路由
if (system.length && system.includes(routeName)) {
systemRoutes.push(route)
// 框架路由
} else if (framework.length && framework.includes(routeName)) {
route.path = '/' // 框架路由路径为根路径
// 查找第一个未禁用的路由作为重定向目标
const firstEnabledRoute = routesSort.find((item) => !routesDisabled.includes(item.name))
route.redirect = firstEnabledRoute?.name // 框架路由重定向为第一个未禁用的路由
frameworkRoutes.push(route)
} else {
// 非系统路由,添加到路由列表,并处理子路由
for (const childPath in childrenModules) {
const [, routeName, childRouteName] = childPath.match(childrenModulesRegex) || []
// 系统路由
if (system.length && system.includes(routeName)) {
systemRoutes.push(route);
// 框架路由
} else if (framework.length && framework.includes(routeName)) {
route.path = "/"; // 框架路由路径为根路径
// 查找第一个未禁用的路由作为重定向目标
const firstEnabledRoute = routesSort.find(
(item) => !routesDisabled.includes(item.name)
);
route.redirect = firstEnabledRoute?.name; // 框架路由重定向为第一个未禁用的路由
frameworkRoutes.push(route);
} else {
// 非系统路由,添加到路由列表,并处理子路由
for (const childPath in childrenModules) {
const [, routeName, childRouteName] =
childPath.match(childrenModulesRegex) || [];
// 非当前路由的子路由,跳过
if (routeName !== route.name) continue
// 获取路由中文标题
const metaName = routesSort.find((item) => item.name === childRouteName)
// 添加子路由配置
route.children.push({
path: kebabCase(childRouteName || ''),
name: kebabCase(childRouteName || ''),
meta: { title: metaName?.title || routeName },
component: childrenModules[childPath] as unknown as Promise<unknown>,
})
}
routes.push(route)
}
}
return { system: systemRoutes, framework: frameworkRoutes, routes }
// 非当前路由的子路由,跳过
if (routeName !== route.name) continue;
// 获取路由中文标题
const metaName = routesSort.find(
(item) => item.name === childRouteName
);
// 添加子路由配置
route.children.push({
path: kebabCase(childRouteName || ""),
name: kebabCase(childRouteName || ""),
meta: { title: metaName?.title || routeName },
component: childrenModules[childPath] as unknown as Promise<unknown>,
});
}
routes.push(route);
}
}
return { system: systemRoutes, framework: frameworkRoutes, routes };
}
/**
@@ -99,11 +114,14 @@ export function generateRoutes(
* @param {string[]} rolesName 允许的路由名称列表
* @returns {RouteRecordRaw[]} 过滤后的路由配置
*/
export function filterSystemRoutes(routes: RouteRecordRaw[], rolesName: string[]): RouteRecordRaw[] {
return routes.filter((route) => {
const routeName = route.name
return typeof routeName === 'string' && rolesName.includes(routeName)
})
export function filterSystemRoutes(
routes: RouteRecordRaw[],
rolesName: string[]
): RouteRecordRaw[] {
return routes.filter((route) => {
const routeName = route.name;
return typeof routeName === "string" && rolesName.includes(routeName);
});
}
/**
@@ -111,13 +129,16 @@ export function filterSystemRoutes(routes: RouteRecordRaw[], rolesName: string[]
* @param {RouteRecordRaw[]} routes 路由配置
* @returns {RouteRecordRaw[]} 排序后的路由配置
*/
export function sortRoutes(routes: RouteRecordRaw[], rolesSort: { name: string; title: string }[]): RouteRecordRaw[] {
// 根据 rolesSort 顺序进行排序
return routes.sort((a, b) => {
const aIndex = rolesSort.findIndex((item) => item.name === a.name)
const bIndex = rolesSort.findIndex((item) => item.name === b.name)
return aIndex - bIndex
})
export function sortRoutes(
routes: RouteRecordRaw[],
rolesSort: { name: string; title: string }[]
): RouteRecordRaw[] {
// 根据 rolesSort 顺序进行排序
return routes.sort((a, b) => {
const aIndex = rolesSort.findIndex((item) => item.name === a.name);
const bIndex = rolesSort.findIndex((item) => item.name === b.name);
return aIndex - bIndex;
});
}
/**
@@ -128,18 +149,24 @@ export function sortRoutes(routes: RouteRecordRaw[], rolesSort: { name: string;
* @returns {RouteRecordRaw[]} 异步路由配置
*/
export function getBuildRoutes(
mainRoute: Record<string, () => Promise<unknown>>,
childrenRoutes: Record<string, () => Promise<unknown>>,
routesOptions: RouteOptions,
mainRoute: Record<string, () => Promise<unknown>>,
childrenRoutes: Record<string, () => Promise<unknown>>,
routesOptions: RouteOptions
): { routeGroup: RouteRecordRaw[]; routes: RouteRecordRaw[] } {
// 生成框架路由
const { framework, system, routes } = generateRoutes(mainRoute, childrenRoutes, routesOptions)
// 排序路由
const sortedRoutes = sortRoutes(routes, [...routesOptions.sort])
// 如果框架路由存在,则将排序后的路由添加到框架路由的子路由中
if (framework[0]) framework[0].children = [...sortedRoutes]
// 返回排序后的路由
return { routeGroup: [...framework, ...system], routes }
// 生成框架路由
const { framework, system, routes } = generateRoutes(
mainRoute,
childrenRoutes,
routesOptions
);
// 排序路由
const sortedRoutes = sortRoutes(routes, [...routesOptions.sort]);
// console.log(sortedRoutes);
// 如果框架路由存在,则将排序后的路由添加到框架路由的子路由中
if (framework[0]) framework[0].children = [...sortedRoutes];
// 返回排序后的路由
return { routeGroup: [...framework, ...system], routes };
}
export default getBuildRoutes
export default getBuildRoutes;