Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
commit
be1889a0e0
|
@ -0,0 +1,28 @@
|
||||||
|
export default eventHandler(async (event) => {
|
||||||
|
const userinfo = verifyAccessToken(event);
|
||||||
|
if (!userinfo) {
|
||||||
|
return unAuthorizedResponse(event);
|
||||||
|
}
|
||||||
|
const data = `
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"message": "success",
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"id": 123456789012345678901234567890123456789012345678901234567890,
|
||||||
|
"name": "John Doe",
|
||||||
|
"age": 30,
|
||||||
|
"email": "john-doe@demo.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 987654321098765432109876543210987654321098765432109876543210,
|
||||||
|
"name": "Jane Smith",
|
||||||
|
"age": 25,
|
||||||
|
"email": "jane@demo.com"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
setHeader(event, 'Content-Type', 'application/json');
|
||||||
|
return data;
|
||||||
|
});
|
|
@ -8,9 +8,9 @@ import type { ComponentType } from './component';
|
||||||
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
/** 手机号正则表达式(中国) */
|
|
||||||
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
||||||
|
|
||||||
|
async function initSetupVbenForm() {
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
// ant design vue组件库默认都是 v-model:value
|
// ant design vue组件库默认都是 v-model:value
|
||||||
|
@ -20,7 +20,6 @@ setupVbenForm<ComponentType>({
|
||||||
modelPropNameMap: {
|
modelPropNameMap: {
|
||||||
Checkbox: 'checked',
|
Checkbox: 'checked',
|
||||||
Radio: 'checked',
|
Radio: 'checked',
|
||||||
RichTextarea: 'modelValue',
|
|
||||||
Switch: 'checked',
|
Switch: 'checked',
|
||||||
Upload: 'fileList',
|
Upload: 'fileList',
|
||||||
},
|
},
|
||||||
|
@ -61,10 +60,11 @@ setupVbenForm<ComponentType>({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const useVbenForm = useForm<ComponentType>;
|
const useVbenForm = useForm<ComponentType>;
|
||||||
|
|
||||||
export { useVbenForm, z };
|
export { initSetupVbenForm, useVbenForm, z };
|
||||||
|
|
||||||
export type VbenFormSchema = FormSchema<ComponentType>;
|
export type VbenFormSchema = FormSchema<ComponentType>;
|
||||||
export type { VbenFormProps };
|
export type { VbenFormProps };
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { $t, setupI18n } from '#/locales';
|
||||||
import { setupFormCreate } from '#/plugins/form-create';
|
import { setupFormCreate } from '#/plugins/form-create';
|
||||||
|
|
||||||
import { initComponentAdapter } from './adapter/component';
|
import { initComponentAdapter } from './adapter/component';
|
||||||
|
import { initSetupVbenForm } from './adapter/form';
|
||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
|
|
||||||
|
@ -21,6 +22,9 @@ async function bootstrap(namespace: string) {
|
||||||
// 初始化组件适配器
|
// 初始化组件适配器
|
||||||
await initComponentAdapter();
|
await initComponentAdapter();
|
||||||
|
|
||||||
|
// 初始化表单组件
|
||||||
|
await initSetupVbenForm();
|
||||||
|
|
||||||
// // 设置弹窗的默认配置
|
// // 设置弹窗的默认配置
|
||||||
// setDefaultModalProps({
|
// setDefaultModalProps({
|
||||||
// fullscreenButton: false,
|
// fullscreenButton: false,
|
||||||
|
|
|
@ -8,9 +8,9 @@ import type { ComponentType } from './component';
|
||||||
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
/** 手机号正则表达式(中国) */
|
|
||||||
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
||||||
|
|
||||||
|
async function initSetupVbenForm() {
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
modelPropNameMap: {
|
modelPropNameMap: {
|
||||||
|
@ -19,14 +19,12 @@ setupVbenForm<ComponentType>({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defineRules: {
|
defineRules: {
|
||||||
// 输入项目必填国际化适配
|
|
||||||
required: (value, _params, ctx) => {
|
required: (value, _params, ctx) => {
|
||||||
if (value === undefined || value === null || value.length === 0) {
|
if (value === undefined || value === null || value.length === 0) {
|
||||||
return $t('ui.formRules.required', [ctx.label]);
|
return $t('ui.formRules.required', [ctx.label]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
// 选择项目必填国际化适配
|
|
||||||
selectRequired: (value, _params, ctx) => {
|
selectRequired: (value, _params, ctx) => {
|
||||||
if (value === undefined || value === null) {
|
if (value === undefined || value === null) {
|
||||||
return $t('ui.formRules.selectRequired', [ctx.label]);
|
return $t('ui.formRules.selectRequired', [ctx.label]);
|
||||||
|
@ -54,10 +52,11 @@ setupVbenForm<ComponentType>({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const useVbenForm = useForm<ComponentType>;
|
const useVbenForm = useForm<ComponentType>;
|
||||||
|
|
||||||
export { useVbenForm, z };
|
export { initSetupVbenForm, useVbenForm, z };
|
||||||
|
|
||||||
export type VbenFormSchema = FormSchema<ComponentType>;
|
export type VbenFormSchema = FormSchema<ComponentType>;
|
||||||
export type { VbenFormProps };
|
export type { VbenFormProps };
|
||||||
|
|
|
@ -14,12 +14,17 @@ import { $t, setupI18n } from '#/locales';
|
||||||
import { setupFormCreate } from '#/plugins/form-create';
|
import { setupFormCreate } from '#/plugins/form-create';
|
||||||
|
|
||||||
import { initComponentAdapter } from './adapter/component';
|
import { initComponentAdapter } from './adapter/component';
|
||||||
|
import { initSetupVbenForm } from './adapter/form';
|
||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
|
|
||||||
async function bootstrap(namespace: string) {
|
async function bootstrap(namespace: string) {
|
||||||
// 初始化组件适配器
|
// 初始化组件适配器
|
||||||
await initComponentAdapter();
|
await initComponentAdapter();
|
||||||
|
|
||||||
|
// 初始化表单组件
|
||||||
|
await initSetupVbenForm();
|
||||||
|
|
||||||
// // 设置弹窗的默认配置
|
// // 设置弹窗的默认配置
|
||||||
// setDefaultModalProps({
|
// setDefaultModalProps({
|
||||||
// fullscreenButton: false,
|
// fullscreenButton: false,
|
||||||
|
|
|
@ -8,9 +8,9 @@ import type { ComponentType } from './component';
|
||||||
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
/** 手机号正则表达式(中国) */
|
|
||||||
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
const MOBILE_REGEX = /(?:0|86|\+86)?1[3-9]\d{9}/;
|
||||||
|
|
||||||
|
async function initSetupVbenForm() {
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
// naive-ui组件的空值为null,不能是undefined,否则重置表单时不生效
|
||||||
|
@ -40,7 +40,7 @@ setupVbenForm<ComponentType>({
|
||||||
if (value === undefined || value === null || value.length === 0) {
|
if (value === undefined || value === null || value.length === 0) {
|
||||||
return true;
|
return true;
|
||||||
} else if (!MOBILE_REGEX.test(value)) {
|
} else if (!MOBILE_REGEX.test(value)) {
|
||||||
return $t('ui.formRules.phone', [ctx.label]);
|
return $t('ui.formRules.mobile', [ctx.label]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
@ -50,16 +50,17 @@ setupVbenForm<ComponentType>({
|
||||||
return $t('ui.formRules.required', [ctx.label]);
|
return $t('ui.formRules.required', [ctx.label]);
|
||||||
}
|
}
|
||||||
if (!MOBILE_REGEX.test(value)) {
|
if (!MOBILE_REGEX.test(value)) {
|
||||||
return $t('ui.formRules.phone', [ctx.label]);
|
return $t('ui.formRules.mobile', [ctx.label]);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const useVbenForm = useForm<ComponentType>;
|
const useVbenForm = useForm<ComponentType>;
|
||||||
|
|
||||||
export { useVbenForm, z };
|
export { initSetupVbenForm, useVbenForm, z };
|
||||||
|
|
||||||
export type VbenFormSchema = FormSchema<ComponentType>;
|
export type VbenFormSchema = FormSchema<ComponentType>;
|
||||||
export type { VbenFormProps };
|
export type { VbenFormProps };
|
||||||
|
|
|
@ -12,12 +12,16 @@ import { useTitle } from '@vueuse/core';
|
||||||
import { $t, setupI18n } from '#/locales';
|
import { $t, setupI18n } from '#/locales';
|
||||||
|
|
||||||
import { initComponentAdapter } from './adapter/component';
|
import { initComponentAdapter } from './adapter/component';
|
||||||
|
import { initSetupVbenForm } from './adapter/form';
|
||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
|
|
||||||
async function bootstrap(namespace: string) {
|
async function bootstrap(namespace: string) {
|
||||||
// 初始化组件适配器
|
// 初始化组件适配器
|
||||||
initComponentAdapter();
|
await initComponentAdapter();
|
||||||
|
|
||||||
|
// 初始化表单组件
|
||||||
|
await initSetupVbenForm();
|
||||||
|
|
||||||
// // 设置弹窗的默认配置
|
// // 设置弹窗的默认配置
|
||||||
// setDefaultModalProps({
|
// setDefaultModalProps({
|
||||||
|
|
|
@ -26,6 +26,12 @@ outline: deep
|
||||||
|
|
||||||
<DemoPreview dir="demos/vben-ellipsis-text/tooltip" />
|
<DemoPreview dir="demos/vben-ellipsis-text/tooltip" />
|
||||||
|
|
||||||
|
## 自动显示 tooltip
|
||||||
|
|
||||||
|
通过`tooltip-when-ellipsis`设置,仅在文本长度超出导致省略号出现时才触发 tooltip。
|
||||||
|
|
||||||
|
<DemoPreview dir="demos/vben-ellipsis-text/auto-display" />
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
|
@ -37,6 +43,8 @@ outline: deep
|
||||||
| maxWidth | 文本区域最大宽度 | `number \| string` | `'100%'` |
|
| maxWidth | 文本区域最大宽度 | `number \| string` | `'100%'` |
|
||||||
| placement | 提示浮层的位置 | `'bottom'\|'left'\|'right'\|'top'` | `'top'` |
|
| placement | 提示浮层的位置 | `'bottom'\|'left'\|'right'\|'top'` | `'top'` |
|
||||||
| tooltip | 启用文本提示 | `boolean` | `true` |
|
| tooltip | 启用文本提示 | `boolean` | `true` |
|
||||||
|
| tooltipWhenEllipsis | 内容超出,自动启用文本提示 | `boolean` | `false` |
|
||||||
|
| ellipsisThreshold | 设置 tooltipWhenEllipsis 后才生效,文本截断检测的像素差异阈值,越大则判断越严格,如果碰见异常情况可以自己设置阈值 | `number` | `3` |
|
||||||
| tooltipBackgroundColor | 提示文本的背景颜色 | `string` | - |
|
| tooltipBackgroundColor | 提示文本的背景颜色 | `string` | - |
|
||||||
| tooltipColor | 提示文本的颜色 | `string` | - |
|
| tooltipColor | 提示文本的颜色 | `string` | - |
|
||||||
| tooltipFontSize | 提示文本的大小 | `string` | - |
|
| tooltipFontSize | 提示文本的大小 | `string` | - |
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { EllipsisText } from '@vben/common-ui';
|
||||||
|
|
||||||
|
const text = `
|
||||||
|
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。
|
||||||
|
`;
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<EllipsisText :line="2" :tooltip-when-ellipsis="true">
|
||||||
|
{{ text }}
|
||||||
|
</EllipsisText>
|
||||||
|
|
||||||
|
<EllipsisText :line="3" :tooltip-when-ellipsis="true">
|
||||||
|
{{ text }}
|
||||||
|
</EllipsisText>
|
||||||
|
</template>
|
|
@ -238,6 +238,7 @@ const defaultPreferences: Preferences = {
|
||||||
},
|
},
|
||||||
logo: {
|
logo: {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
fit: 'contain',
|
||||||
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
|
@ -431,6 +432,8 @@ interface HeaderPreferences {
|
||||||
interface LogoPreferences {
|
interface LogoPreferences {
|
||||||
/** Whether the logo is visible */
|
/** Whether the logo is visible */
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
|
/** Logo image fitting method */
|
||||||
|
fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
/** Logo URL */
|
/** Logo URL */
|
||||||
source: string;
|
source: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,7 @@ const defaultPreferences: Preferences = {
|
||||||
},
|
},
|
||||||
logo: {
|
logo: {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
fit: 'contain',
|
||||||
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
|
@ -431,6 +432,8 @@ interface HeaderPreferences {
|
||||||
interface LogoPreferences {
|
interface LogoPreferences {
|
||||||
/** logo是否可见 */
|
/** logo是否可见 */
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
|
/** logo图片适应方式 */
|
||||||
|
fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
/** logo地址 */
|
/** logo地址 */
|
||||||
source: string;
|
source: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||||
},
|
},
|
||||||
"logo": {
|
"logo": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
|
"fit": "contain",
|
||||||
"source": "https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp",
|
"source": "https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp",
|
||||||
},
|
},
|
||||||
"navigation": {
|
"navigation": {
|
||||||
|
|
|
@ -62,6 +62,7 @@ const defaultPreferences: Preferences = {
|
||||||
|
|
||||||
logo: {
|
logo: {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
fit: 'contain',
|
||||||
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
|
|
|
@ -134,6 +134,8 @@ interface HeaderPreferences {
|
||||||
interface LogoPreferences {
|
interface LogoPreferences {
|
||||||
/** logo是否可见 */
|
/** logo是否可见 */
|
||||||
enable: boolean;
|
enable: boolean;
|
||||||
|
/** logo图片适应方式 */
|
||||||
|
fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
/** logo地址 */
|
/** logo地址 */
|
||||||
source: string;
|
source: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import type { Recordable } from '@vben-core/typings';
|
||||||
|
|
||||||
import type { FormActions, FormSchema, VbenFormProps } from './types';
|
import type { FormActions, FormSchema, VbenFormProps } from './types';
|
||||||
|
|
||||||
import { toRaw } from 'vue';
|
import { isRef, toRaw } from 'vue';
|
||||||
|
|
||||||
import { Store } from '@vben-core/shared/store';
|
import { Store } from '@vben-core/shared/store';
|
||||||
import {
|
import {
|
||||||
|
@ -100,9 +100,26 @@ export class FormApi {
|
||||||
getFieldComponentRef<T = ComponentPublicInstance>(
|
getFieldComponentRef<T = ComponentPublicInstance>(
|
||||||
fieldName: string,
|
fieldName: string,
|
||||||
): T | undefined {
|
): T | undefined {
|
||||||
return this.componentRefMap.has(fieldName)
|
let target = this.componentRefMap.has(fieldName)
|
||||||
? (this.componentRefMap.get(fieldName) as T)
|
? (this.componentRefMap.get(fieldName) as ComponentPublicInstance)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
if (
|
||||||
|
target &&
|
||||||
|
target.$.type.name === 'AsyncComponentWrapper' &&
|
||||||
|
target.$.subTree.ref
|
||||||
|
) {
|
||||||
|
if (Array.isArray(target.$.subTree.ref)) {
|
||||||
|
if (
|
||||||
|
target.$.subTree.ref.length > 0 &&
|
||||||
|
isRef(target.$.subTree.ref[0]?.r)
|
||||||
|
) {
|
||||||
|
target = target.$.subTree.ref[0]?.r.value as ComponentPublicInstance;
|
||||||
|
}
|
||||||
|
} else if (isRef(target.$.subTree.ref.r)) {
|
||||||
|
target = target.$.subTree.ref.r.value as ComponentPublicInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { createContext } from '@vben-core/shadcn-ui';
|
||||||
import { isString, mergeWithArrayOverride, set } from '@vben-core/shared/utils';
|
import { isString, mergeWithArrayOverride, set } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
import { useForm } from 'vee-validate';
|
import { useForm } from 'vee-validate';
|
||||||
import { object } from 'zod';
|
import { object, ZodIntersection, ZodNumber, ZodObject, ZodString } from 'zod';
|
||||||
import { getDefaultsForSchema } from 'zod-defaults';
|
import { getDefaultsForSchema } from 'zod-defaults';
|
||||||
|
|
||||||
type ExtendFormProps = VbenFormProps & { formApi: ExtendedFormApi };
|
type ExtendFormProps = VbenFormProps & { formApi: ExtendedFormApi };
|
||||||
|
@ -52,7 +52,12 @@ export function useFormInitial(
|
||||||
if (Reflect.has(item, 'defaultValue')) {
|
if (Reflect.has(item, 'defaultValue')) {
|
||||||
set(initialValues, item.fieldName, item.defaultValue);
|
set(initialValues, item.fieldName, item.defaultValue);
|
||||||
} else if (item.rules && !isString(item.rules)) {
|
} else if (item.rules && !isString(item.rules)) {
|
||||||
|
// 检查规则是否适合提取默认值
|
||||||
|
const customDefaultValue = getCustomDefaultValue(item.rules);
|
||||||
zodObject[item.fieldName] = item.rules;
|
zodObject[item.fieldName] = item.rules;
|
||||||
|
if (customDefaultValue !== undefined) {
|
||||||
|
initialValues[item.fieldName] = customDefaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -64,6 +69,38 @@ export function useFormInitial(
|
||||||
}
|
}
|
||||||
return mergeWithArrayOverride(initialValues, zodDefaults);
|
return mergeWithArrayOverride(initialValues, zodDefaults);
|
||||||
}
|
}
|
||||||
|
// 自定义默认值提取逻辑
|
||||||
|
function getCustomDefaultValue(rule: any): any {
|
||||||
|
if (rule instanceof ZodString) {
|
||||||
|
return ''; // 默认为空字符串
|
||||||
|
} else if (rule instanceof ZodNumber) {
|
||||||
|
return null; // 默认为 null(避免显示 0)
|
||||||
|
} else if (rule instanceof ZodObject) {
|
||||||
|
// 递归提取嵌套对象的默认值
|
||||||
|
const defaultValues: Record<string, any> = {};
|
||||||
|
for (const [key, valueSchema] of Object.entries(rule.shape)) {
|
||||||
|
defaultValues[key] = getCustomDefaultValue(valueSchema);
|
||||||
|
}
|
||||||
|
return defaultValues;
|
||||||
|
} else if (rule instanceof ZodIntersection) {
|
||||||
|
// 对于交集类型,从schema 提取默认值
|
||||||
|
const leftDefaultValue = getCustomDefaultValue(rule._def.left);
|
||||||
|
const rightDefaultValue = getCustomDefaultValue(rule._def.right);
|
||||||
|
|
||||||
|
// 如果左右两边都能提取默认值,合并它们
|
||||||
|
if (
|
||||||
|
typeof leftDefaultValue === 'object' &&
|
||||||
|
typeof rightDefaultValue === 'object'
|
||||||
|
) {
|
||||||
|
return { ...leftDefaultValue, ...rightDefaultValue };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则优先使用左边的默认值
|
||||||
|
return leftDefaultValue ?? rightDefaultValue;
|
||||||
|
} else {
|
||||||
|
return undefined; // 其他类型不提供默认值
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
delegatedSlots,
|
delegatedSlots,
|
||||||
|
|
|
@ -5,6 +5,8 @@ import type {
|
||||||
AvatarRootProps,
|
AvatarRootProps,
|
||||||
} from 'radix-vue';
|
} from 'radix-vue';
|
||||||
|
|
||||||
|
import type { CSSProperties } from 'vue';
|
||||||
|
|
||||||
import type { ClassType } from '@vben-core/typings';
|
import type { ClassType } from '@vben-core/typings';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
@ -16,6 +18,7 @@ interface Props extends AvatarFallbackProps, AvatarImageProps, AvatarRootProps {
|
||||||
class?: ClassType;
|
class?: ClassType;
|
||||||
dot?: boolean;
|
dot?: boolean;
|
||||||
dotClass?: ClassType;
|
dotClass?: ClassType;
|
||||||
|
fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
size?: number;
|
size?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +31,15 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
as: 'button',
|
as: 'button',
|
||||||
dot: false,
|
dot: false,
|
||||||
dotClass: 'bg-green-500',
|
dotClass: 'bg-green-500',
|
||||||
|
fit: 'cover',
|
||||||
|
});
|
||||||
|
|
||||||
|
const imageStyle = computed<CSSProperties>(() => {
|
||||||
|
const { fit } = props;
|
||||||
|
if (fit) {
|
||||||
|
return { objectFit: fit };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
const text = computed(() => {
|
const text = computed(() => {
|
||||||
|
@ -51,7 +63,7 @@ const rootStyle = computed(() => {
|
||||||
class="relative flex flex-shrink-0 items-center"
|
class="relative flex flex-shrink-0 items-center"
|
||||||
>
|
>
|
||||||
<Avatar :class="props.class" class="size-full">
|
<Avatar :class="props.class" class="size-full">
|
||||||
<AvatarImage :alt="alt" :src="src" />
|
<AvatarImage :alt="alt" :src="src" :style="imageStyle" />
|
||||||
<AvatarFallback>{{ text }}</AvatarFallback>
|
<AvatarFallback>{{ text }}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -6,6 +6,10 @@ interface Props {
|
||||||
* @zh_CN 是否收起文本
|
* @zh_CN 是否收起文本
|
||||||
*/
|
*/
|
||||||
collapsed?: boolean;
|
collapsed?: boolean;
|
||||||
|
/**
|
||||||
|
* @zh_CN Logo 图片适应方式
|
||||||
|
*/
|
||||||
|
fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
|
||||||
/**
|
/**
|
||||||
* @zh_CN Logo 跳转地址
|
* @zh_CN Logo 跳转地址
|
||||||
*/
|
*/
|
||||||
|
@ -38,6 +42,7 @@ withDefaults(defineProps<Props>(), {
|
||||||
logoSize: 32,
|
logoSize: 32,
|
||||||
src: '',
|
src: '',
|
||||||
theme: 'light',
|
theme: 'light',
|
||||||
|
fit: 'cover',
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -53,6 +58,7 @@ withDefaults(defineProps<Props>(), {
|
||||||
:alt="text"
|
:alt="text"
|
||||||
:src="src"
|
:src="src"
|
||||||
:size="logoSize"
|
:size="logoSize"
|
||||||
|
:fit="fit"
|
||||||
class="relative rounded-none bg-transparent"
|
class="relative rounded-none bg-transparent"
|
||||||
/>
|
/>
|
||||||
<template v-if="!collapsed">
|
<template v-if="!collapsed">
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CSSProperties } from 'vue';
|
import type { CSSProperties } from 'vue';
|
||||||
|
|
||||||
import { computed, ref, watchEffect } from 'vue';
|
import {
|
||||||
|
computed,
|
||||||
|
onBeforeUnmount,
|
||||||
|
onMounted,
|
||||||
|
onUpdated,
|
||||||
|
ref,
|
||||||
|
watchEffect,
|
||||||
|
} from 'vue';
|
||||||
|
|
||||||
import { VbenTooltip } from '@vben-core/shadcn-ui';
|
import { VbenTooltip } from '@vben-core/shadcn-ui';
|
||||||
|
|
||||||
|
@ -33,6 +40,16 @@ interface Props {
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
tooltip?: boolean;
|
tooltip?: boolean;
|
||||||
|
/**
|
||||||
|
* 是否只在文本被截断时显示提示框
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
tooltipWhenEllipsis?: boolean;
|
||||||
|
/**
|
||||||
|
* 文本截断检测的像素差异阈值,越大则判断越严格
|
||||||
|
* @default 3
|
||||||
|
*/
|
||||||
|
ellipsisThreshold?: number;
|
||||||
/**
|
/**
|
||||||
* 提示框背景颜色,优先级高于 overlayStyle
|
* 提示框背景颜色,优先级高于 overlayStyle
|
||||||
*/
|
*/
|
||||||
|
@ -62,12 +79,15 @@ const props = withDefaults(defineProps<Props>(), {
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
|
tooltipWhenEllipsis: false,
|
||||||
|
ellipsisThreshold: 3,
|
||||||
tooltipBackgroundColor: '',
|
tooltipBackgroundColor: '',
|
||||||
tooltipColor: '',
|
tooltipColor: '',
|
||||||
tooltipFontSize: 14,
|
tooltipFontSize: 14,
|
||||||
tooltipMaxWidth: undefined,
|
tooltipMaxWidth: undefined,
|
||||||
tooltipOverlayStyle: () => ({ textAlign: 'justify' }),
|
tooltipOverlayStyle: () => ({ textAlign: 'justify' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits<{ expandChange: [boolean] }>();
|
const emit = defineEmits<{ expandChange: [boolean] }>();
|
||||||
|
|
||||||
const textMaxWidth = computed(() => {
|
const textMaxWidth = computed(() => {
|
||||||
|
@ -79,9 +99,67 @@ const textMaxWidth = computed(() => {
|
||||||
const ellipsis = ref();
|
const ellipsis = ref();
|
||||||
const isExpand = ref(false);
|
const isExpand = ref(false);
|
||||||
const defaultTooltipMaxWidth = ref();
|
const defaultTooltipMaxWidth = ref();
|
||||||
|
const isEllipsis = ref(false);
|
||||||
|
|
||||||
const { width: eleWidth } = useElementSize(ellipsis);
|
const { width: eleWidth } = useElementSize(ellipsis);
|
||||||
|
|
||||||
|
// 检测文本是否被截断
|
||||||
|
const checkEllipsis = () => {
|
||||||
|
if (!ellipsis.value || !props.tooltipWhenEllipsis) return;
|
||||||
|
|
||||||
|
const element = ellipsis.value;
|
||||||
|
|
||||||
|
const originalText = element.textContent || '';
|
||||||
|
const originalTrimmed = originalText.trim();
|
||||||
|
|
||||||
|
// 对于空文本直接返回 false
|
||||||
|
if (!originalTrimmed) {
|
||||||
|
isEllipsis.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const widthDiff = element.scrollWidth - element.clientWidth;
|
||||||
|
const heightDiff = element.scrollHeight - element.clientHeight;
|
||||||
|
|
||||||
|
// 使用足够大的差异阈值确保只有真正被截断的文本才会显示 tooltip
|
||||||
|
isEllipsis.value =
|
||||||
|
props.line === 1
|
||||||
|
? widthDiff > props.ellipsisThreshold
|
||||||
|
: heightDiff > props.ellipsisThreshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用 ResizeObserver 监听尺寸变化
|
||||||
|
let resizeObserver: null | ResizeObserver = null;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (typeof ResizeObserver !== 'undefined' && props.tooltipWhenEllipsis) {
|
||||||
|
resizeObserver = new ResizeObserver(() => {
|
||||||
|
checkEllipsis();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ellipsis.value) {
|
||||||
|
resizeObserver.observe(ellipsis.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始检测
|
||||||
|
checkEllipsis();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用onUpdated钩子检测内容变化
|
||||||
|
onUpdated(() => {
|
||||||
|
if (props.tooltipWhenEllipsis) {
|
||||||
|
checkEllipsis();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
resizeObserver = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
watchEffect(
|
watchEffect(
|
||||||
() => {
|
() => {
|
||||||
if (props.tooltip && eleWidth.value) {
|
if (props.tooltip && eleWidth.value) {
|
||||||
|
@ -91,9 +169,13 @@ watchEffect(
|
||||||
},
|
},
|
||||||
{ flush: 'post' },
|
{ flush: 'post' },
|
||||||
);
|
);
|
||||||
|
|
||||||
function onExpand() {
|
function onExpand() {
|
||||||
isExpand.value = !isExpand.value;
|
isExpand.value = !isExpand.value;
|
||||||
emit('expandChange', isExpand.value);
|
emit('expandChange', isExpand.value);
|
||||||
|
if (props.tooltipWhenEllipsis) {
|
||||||
|
checkEllipsis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleExpand() {
|
function handleExpand() {
|
||||||
|
@ -110,7 +192,9 @@ function handleExpand() {
|
||||||
color: tooltipColor,
|
color: tooltipColor,
|
||||||
backgroundColor: tooltipBackgroundColor,
|
backgroundColor: tooltipBackgroundColor,
|
||||||
}"
|
}"
|
||||||
:disabled="!props.tooltip || isExpand"
|
:disabled="
|
||||||
|
!props.tooltip || isExpand || (props.tooltipWhenEllipsis && !isEllipsis)
|
||||||
|
"
|
||||||
:side="placement"
|
:side="placement"
|
||||||
>
|
>
|
||||||
<slot name="tooltip">
|
<slot name="tooltip">
|
||||||
|
|
|
@ -234,6 +234,7 @@ const headerSlots = computed(() => {
|
||||||
<template #logo>
|
<template #logo>
|
||||||
<VbenLogo
|
<VbenLogo
|
||||||
v-if="preferences.logo.enable"
|
v-if="preferences.logo.enable"
|
||||||
|
:fit="preferences.logo.fit"
|
||||||
:class="logoClass"
|
:class="logoClass"
|
||||||
:collapsed="logoCollapsed"
|
:collapsed="logoCollapsed"
|
||||||
:src="preferences.logo.source"
|
:src="preferences.logo.source"
|
||||||
|
@ -324,6 +325,7 @@ const headerSlots = computed(() => {
|
||||||
<template #side-extra-title>
|
<template #side-extra-title>
|
||||||
<VbenLogo
|
<VbenLogo
|
||||||
v-if="preferences.logo.enable"
|
v-if="preferences.logo.enable"
|
||||||
|
:fit="preferences.logo.fit"
|
||||||
:text="preferences.app.name"
|
:text="preferences.app.name"
|
||||||
:theme="theme"
|
:theme="theme"
|
||||||
>
|
>
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { $t } from '@vben/locales';
|
||||||
import { useVbenModal } from '@vben-core/popup-ui';
|
import { useVbenModal } from '@vben-core/popup-ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// 轮训时间,分钟
|
// 轮询时间,分钟
|
||||||
checkUpdatesInterval?: number;
|
checkUpdatesInterval?: number;
|
||||||
// 检查更新的地址
|
// 检查更新的地址
|
||||||
checkUpdateUrl?: string;
|
checkUpdateUrl?: string;
|
||||||
|
@ -46,6 +46,7 @@ async function getVersionTag() {
|
||||||
const response = await fetch(props.checkUpdateUrl, {
|
const response = await fetch(props.checkUpdateUrl, {
|
||||||
cache: 'no-cache',
|
cache: 'no-cache',
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
|
redirect: 'manual',
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -208,7 +208,7 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
||||||
const keys: string[] = [];
|
const keys: string[] = [];
|
||||||
|
|
||||||
for (const key of closeKeys) {
|
for (const key of closeKeys) {
|
||||||
if (key !== tab.key) {
|
if (key !== getTabKeyFromTab(tab)) {
|
||||||
const closeTab = this.tabs.find(
|
const closeTab = this.tabs.find(
|
||||||
(item) => getTabKeyFromTab(item) === key,
|
(item) => getTabKeyFromTab(item) === key,
|
||||||
);
|
);
|
||||||
|
|
|
@ -48,8 +48,12 @@
|
||||||
"@vueuse/core": "catalog:",
|
"@vueuse/core": "catalog:",
|
||||||
"ant-design-vue": "catalog:",
|
"ant-design-vue": "catalog:",
|
||||||
"dayjs": "catalog:",
|
"dayjs": "catalog:",
|
||||||
|
"json-bigint": "catalog:",
|
||||||
"pinia": "catalog:",
|
"pinia": "catalog:",
|
||||||
"vue": "catalog:",
|
"vue": "catalog:",
|
||||||
"vue-router": "catalog:"
|
"vue-router": "catalog:"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/json-bigint": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { ComponentType } from './component';
|
||||||
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
|
||||||
import { $t } from '@vben/locales';
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
|
async function initSetupVbenForm() {
|
||||||
setupVbenForm<ComponentType>({
|
setupVbenForm<ComponentType>({
|
||||||
config: {
|
config: {
|
||||||
// ant design vue组件库默认都是 v-model:value
|
// ant design vue组件库默认都是 v-model:value
|
||||||
|
@ -37,9 +38,10 @@ setupVbenForm<ComponentType>({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const useVbenForm = useForm<ComponentType>;
|
const useVbenForm = useForm<ComponentType>;
|
||||||
|
|
||||||
export { useVbenForm, z };
|
export { initSetupVbenForm, useVbenForm, z };
|
||||||
export type VbenFormSchema = FormSchema<ComponentType>;
|
export type VbenFormSchema = FormSchema<ComponentType>;
|
||||||
export type { VbenFormProps };
|
export type { VbenFormProps };
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起请求
|
||||||
|
*/
|
||||||
|
async function getBigIntData() {
|
||||||
|
return requestClient.get('/demo/bigint');
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getBigIntData };
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* 该文件可自行根据业务逻辑进行调整
|
* 该文件可自行根据业务逻辑进行调整
|
||||||
*/
|
*/
|
||||||
import type { RequestClientOptions } from '@vben/request';
|
import type { AxiosResponseHeaders, RequestClientOptions } from '@vben/request';
|
||||||
|
|
||||||
import { useAppConfig } from '@vben/hooks';
|
import { useAppConfig } from '@vben/hooks';
|
||||||
import { preferences } from '@vben/preferences';
|
import { preferences } from '@vben/preferences';
|
||||||
|
@ -12,8 +12,10 @@ import {
|
||||||
RequestClient,
|
RequestClient,
|
||||||
} from '@vben/request';
|
} from '@vben/request';
|
||||||
import { useAccessStore } from '@vben/stores';
|
import { useAccessStore } from '@vben/stores';
|
||||||
|
import { cloneDeep } from '@vben/utils';
|
||||||
|
|
||||||
import { message } from 'ant-design-vue';
|
import { message } from 'ant-design-vue';
|
||||||
|
import JSONBigInt from 'json-bigint';
|
||||||
|
|
||||||
import { useAuthStore } from '#/store';
|
import { useAuthStore } from '#/store';
|
||||||
|
|
||||||
|
@ -25,6 +27,14 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
||||||
const client = new RequestClient({
|
const client = new RequestClient({
|
||||||
...options,
|
...options,
|
||||||
baseURL,
|
baseURL,
|
||||||
|
transformResponse: (data: any, header: AxiosResponseHeaders) => {
|
||||||
|
// storeAsString指示将BigInt存储为字符串,设为false则会存储为内置的BigInt类型
|
||||||
|
return header.getContentType()?.toString().includes('application/json')
|
||||||
|
? cloneDeep(
|
||||||
|
JSONBigInt({ storeAsString: true, strict: true }).parse(data),
|
||||||
|
)
|
||||||
|
: data;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,12 +13,16 @@ import { $t, setupI18n } from '#/locales';
|
||||||
import { router } from '#/router';
|
import { router } from '#/router';
|
||||||
|
|
||||||
import { initComponentAdapter } from './adapter/component';
|
import { initComponentAdapter } from './adapter/component';
|
||||||
|
import { initSetupVbenForm } from './adapter/form';
|
||||||
import App from './app.vue';
|
import App from './app.vue';
|
||||||
|
|
||||||
async function bootstrap(namespace: string) {
|
async function bootstrap(namespace: string) {
|
||||||
// 初始化组件适配器
|
// 初始化组件适配器
|
||||||
await initComponentAdapter();
|
await initComponentAdapter();
|
||||||
|
|
||||||
|
// 初始化表单组件
|
||||||
|
await initSetupVbenForm();
|
||||||
|
|
||||||
// 设置弹窗的默认配置
|
// 设置弹窗的默认配置
|
||||||
// setDefaultModalProps({
|
// setDefaultModalProps({
|
||||||
// fullscreenButton: false,
|
// fullscreenButton: false,
|
||||||
|
|
|
@ -255,6 +255,16 @@ const routes: RouteRecordRaw[] = [
|
||||||
title: $t('demos.features.requestParamsSerializer'),
|
title: $t('demos.features.requestParamsSerializer'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'BigIntDemo',
|
||||||
|
path: '/demos/features/json-bigint',
|
||||||
|
component: () =>
|
||||||
|
import('#/views/demos/features/json-bigint/index.vue'),
|
||||||
|
meta: {
|
||||||
|
icon: 'lucide:grape',
|
||||||
|
title: 'JSON BigInt',
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// 面包屑导航
|
// 面包屑导航
|
||||||
|
|
|
@ -111,10 +111,11 @@ const loginRef =
|
||||||
async function onSubmit(params: Recordable<any>) {
|
async function onSubmit(params: Recordable<any>) {
|
||||||
authStore.authLogin(params).catch(() => {
|
authStore.authLogin(params).catch(() => {
|
||||||
// 登陆失败,刷新验证码的演示
|
// 登陆失败,刷新验证码的演示
|
||||||
|
const formApi = loginRef.value?.getFormApi();
|
||||||
|
// 重置验证码组件的值
|
||||||
|
formApi?.setFieldValue('captcha', false, false);
|
||||||
// 使用表单API获取验证码组件实例,并调用其resume方法来重置验证码
|
// 使用表单API获取验证码组件实例,并调用其resume方法来重置验证码
|
||||||
loginRef.value
|
formApi
|
||||||
?.getFormApi()
|
|
||||||
?.getFieldComponentRef<InstanceType<typeof SliderCaptcha>>('captcha')
|
?.getFieldComponentRef<InstanceType<typeof SliderCaptcha>>('captcha')
|
||||||
?.resume();
|
?.resume();
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { Alert, Button, Card } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { getBigIntData } from '#/api/examples/json-bigint';
|
||||||
|
|
||||||
|
const response = ref('');
|
||||||
|
function fetchData() {
|
||||||
|
getBigIntData().then((res) => {
|
||||||
|
response.value = res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Page
|
||||||
|
title="JSON BigInt Support"
|
||||||
|
description="解析后端返回的长整数(long/bigInt)。代码位置:playground/src/api/request.ts中的transformResponse"
|
||||||
|
>
|
||||||
|
<Card>
|
||||||
|
<Alert>
|
||||||
|
<template #message>
|
||||||
|
有些后端接口返回的ID是长整数,但javascript原生的JSON解析是不支持超过2^53-1的长整数的。
|
||||||
|
这种情况可以建议后端返回数据前将长整数转换为字符串类型。如果后端不接受我们的建议😡……
|
||||||
|
<br />
|
||||||
|
下面的按钮点击后会发起请求,接口返回的JSON数据中的id字段是超出整数范围的数字,已自动将其解析为字符串
|
||||||
|
</template>
|
||||||
|
</Alert>
|
||||||
|
<Button class="mt-4" type="primary" @click="fetchData">发起请求</Button>
|
||||||
|
<div>
|
||||||
|
<pre>
|
||||||
|
{{ response }}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Page>
|
||||||
|
</template>
|
|
@ -134,7 +134,7 @@ function handleClick(
|
||||||
}
|
}
|
||||||
case 'componentRef': {
|
case 'componentRef': {
|
||||||
// 获取下拉组件的实例,并调用它的focus方法
|
// 获取下拉组件的实例,并调用它的focus方法
|
||||||
formApi.getFieldComponentRef<RefSelectProps>('fieldOptions')?.focus();
|
formApi.getFieldComponentRef<RefSelectProps>('fieldOptions')?.focus?.();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'disabled': {
|
case 'disabled': {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function getMenuTypeOptions() {
|
||||||
value: 'catalog',
|
value: 'catalog',
|
||||||
},
|
},
|
||||||
{ color: 'default', label: $t('system.menu.typeMenu'), value: 'menu' },
|
{ color: 'default', label: $t('system.menu.typeMenu'), value: 'menu' },
|
||||||
{ color: 'error', label: $t('system.menu.typeButton'), value: 'action' },
|
{ color: 'error', label: $t('system.menu.typeButton'), value: 'button' },
|
||||||
{
|
{
|
||||||
color: 'success',
|
color: 'success',
|
||||||
label: $t('system.menu.typeEmbedded'),
|
label: $t('system.menu.typeEmbedded'),
|
||||||
|
|
|
@ -99,6 +99,9 @@ catalogs:
|
||||||
'@types/html-minifier-terser':
|
'@types/html-minifier-terser':
|
||||||
specifier: ^7.0.2
|
specifier: ^7.0.2
|
||||||
version: 7.0.2
|
version: 7.0.2
|
||||||
|
'@types/json-bigint':
|
||||||
|
specifier: ^1.0.4
|
||||||
|
version: 1.0.4
|
||||||
'@types/jsonwebtoken':
|
'@types/jsonwebtoken':
|
||||||
specifier: ^9.0.9
|
specifier: ^9.0.9
|
||||||
version: 9.0.9
|
version: 9.0.9
|
||||||
|
@ -315,6 +318,9 @@ catalogs:
|
||||||
is-ci:
|
is-ci:
|
||||||
specifier: ^4.1.0
|
specifier: ^4.1.0
|
||||||
version: 4.1.0
|
version: 4.1.0
|
||||||
|
json-bigint:
|
||||||
|
specifier: ^1.0.0
|
||||||
|
version: 1.0.0
|
||||||
jsonc-eslint-parser:
|
jsonc-eslint-parser:
|
||||||
specifier: ^2.4.0
|
specifier: ^2.4.0
|
||||||
version: 2.4.0
|
version: 2.4.0
|
||||||
|
@ -1984,6 +1990,9 @@ importers:
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 1.11.13
|
version: 1.11.13
|
||||||
|
json-bigint:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 1.0.0
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^3.0.2
|
specifier: ^3.0.2
|
||||||
version: 3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))
|
version: 3.0.2(typescript@5.8.3)(vue@3.5.13(typescript@5.8.3))
|
||||||
|
@ -1993,6 +2002,10 @@ importers:
|
||||||
vue-router:
|
vue-router:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 4.5.1(vue@3.5.13(typescript@5.8.3))
|
version: 4.5.1(vue@3.5.13(typescript@5.8.3))
|
||||||
|
devDependencies:
|
||||||
|
'@types/json-bigint':
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 1.0.4
|
||||||
|
|
||||||
scripts/turbo-run:
|
scripts/turbo-run:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4536,6 +4549,9 @@ packages:
|
||||||
'@types/html-minifier-terser@7.0.2':
|
'@types/html-minifier-terser@7.0.2':
|
||||||
resolution: {integrity: sha512-mm2HqV22l8lFQh4r2oSsOEVea+m0qqxEmwpc9kC1p/XzmjLWrReR9D/GRs8Pex2NX/imyEH9c5IU/7tMBQCHOA==}
|
resolution: {integrity: sha512-mm2HqV22l8lFQh4r2oSsOEVea+m0qqxEmwpc9kC1p/XzmjLWrReR9D/GRs8Pex2NX/imyEH9c5IU/7tMBQCHOA==}
|
||||||
|
|
||||||
|
'@types/json-bigint@1.0.4':
|
||||||
|
resolution: {integrity: sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
|
@ -5429,6 +5445,9 @@ packages:
|
||||||
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
|
resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
bignumber.js@9.3.0:
|
||||||
|
resolution: {integrity: sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==}
|
||||||
|
|
||||||
binary-extensions@2.3.0:
|
binary-extensions@2.3.0:
|
||||||
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -7852,6 +7871,9 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
json-bigint@1.0.0:
|
||||||
|
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
|
||||||
|
|
||||||
json-buffer@3.0.1:
|
json-buffer@3.0.1:
|
||||||
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||||
|
|
||||||
|
@ -14445,6 +14467,8 @@ snapshots:
|
||||||
|
|
||||||
'@types/html-minifier-terser@7.0.2': {}
|
'@types/html-minifier-terser@7.0.2': {}
|
||||||
|
|
||||||
|
'@types/json-bigint@1.0.4': {}
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/jsonwebtoken@9.0.9':
|
'@types/jsonwebtoken@9.0.9':
|
||||||
|
@ -15500,6 +15524,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-windows: 1.0.2
|
is-windows: 1.0.2
|
||||||
|
|
||||||
|
bignumber.js@9.3.0: {}
|
||||||
|
|
||||||
binary-extensions@2.3.0: {}
|
binary-extensions@2.3.0: {}
|
||||||
|
|
||||||
bindings@1.5.0:
|
bindings@1.5.0:
|
||||||
|
@ -18197,6 +18223,10 @@ snapshots:
|
||||||
|
|
||||||
jsesc@3.1.0: {}
|
jsesc@3.1.0: {}
|
||||||
|
|
||||||
|
json-bigint@1.0.0:
|
||||||
|
dependencies:
|
||||||
|
bignumber.js: 9.3.0
|
||||||
|
|
||||||
json-buffer@3.0.1: {}
|
json-buffer@3.0.1: {}
|
||||||
|
|
||||||
json-parse-even-better-errors@2.3.1: {}
|
json-parse-even-better-errors@2.3.1: {}
|
||||||
|
|
|
@ -45,6 +45,7 @@ catalog:
|
||||||
'@types/archiver': ^6.0.3
|
'@types/archiver': ^6.0.3
|
||||||
'@types/eslint': ^9.6.1
|
'@types/eslint': ^9.6.1
|
||||||
'@types/html-minifier-terser': ^7.0.2
|
'@types/html-minifier-terser': ^7.0.2
|
||||||
|
'@types/json-bigint': ^1.0.4
|
||||||
'@types/jsonwebtoken': ^9.0.9
|
'@types/jsonwebtoken': ^9.0.9
|
||||||
'@types/lodash.clonedeep': ^4.5.9
|
'@types/lodash.clonedeep': ^4.5.9
|
||||||
'@types/lodash.get': ^4.4.9
|
'@types/lodash.get': ^4.4.9
|
||||||
|
@ -119,6 +120,7 @@ catalog:
|
||||||
happy-dom: ^17.4.6
|
happy-dom: ^17.4.6
|
||||||
html-minifier-terser: ^7.2.0
|
html-minifier-terser: ^7.2.0
|
||||||
is-ci: ^4.1.0
|
is-ci: ^4.1.0
|
||||||
|
json-bigint: ^1.0.0
|
||||||
jsonc-eslint-parser: ^2.4.0
|
jsonc-eslint-parser: ^2.4.0
|
||||||
jsonwebtoken: ^9.0.2
|
jsonwebtoken: ^9.0.2
|
||||||
lefthook: ^1.11.12
|
lefthook: ^1.11.12
|
||||||
|
|
Loading…
Reference in New Issue