Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin
This commit is contained in:
commit
d1efb4278b
@ -147,7 +147,7 @@ export async function javascript(): Promise<Linter.Config[]> {
|
|||||||
'no-template-curly-in-string': 'error',
|
'no-template-curly-in-string': 'error',
|
||||||
'no-this-before-super': 'error',
|
'no-this-before-super': 'error',
|
||||||
'no-throw-literal': 'error',
|
'no-throw-literal': 'error',
|
||||||
'no-undef': 'error',
|
'no-undef': 'off',
|
||||||
'no-undef-init': 'error',
|
'no-undef-init': 'error',
|
||||||
'no-unexpected-multiline': 'error',
|
'no-unexpected-multiline': 'error',
|
||||||
'no-unmodified-loop-condition': 'error',
|
'no-unmodified-loop-condition': 'error',
|
||||||
|
@ -15,6 +15,22 @@ export async function vue(): Promise<Linter.Config[]> {
|
|||||||
{
|
{
|
||||||
files: ['**/*.vue'],
|
files: ['**/*.vue'],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
|
// globals: {
|
||||||
|
// computed: 'readonly',
|
||||||
|
// defineEmits: 'readonly',
|
||||||
|
// defineExpose: 'readonly',
|
||||||
|
// defineProps: 'readonly',
|
||||||
|
// onMounted: 'readonly',
|
||||||
|
// onUnmounted: 'readonly',
|
||||||
|
// reactive: 'readonly',
|
||||||
|
// ref: 'readonly',
|
||||||
|
// shallowReactive: 'readonly',
|
||||||
|
// shallowRef: 'readonly',
|
||||||
|
// toRef: 'readonly',
|
||||||
|
// toRefs: 'readonly',
|
||||||
|
// watch: 'readonly',
|
||||||
|
// watchEffect: 'readonly',
|
||||||
|
// },
|
||||||
parser: parserVue,
|
parser: parserVue,
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
|
@ -137,12 +137,12 @@ type ApplicationOptions = ApplicationPluginOptions;
|
|||||||
|
|
||||||
type LibraryOptions = LibraryPluginOptions;
|
type LibraryOptions = LibraryPluginOptions;
|
||||||
|
|
||||||
type DefineApplicationOptions = (config?: ConfigEnv) => Promise<{
|
type DefineApplicationOptions = (config: ConfigEnv) => Promise<{
|
||||||
application?: ApplicationOptions;
|
application?: ApplicationOptions;
|
||||||
vite?: UserConfig;
|
vite?: UserConfig;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type DefineLibraryOptions = (config?: ConfigEnv) => Promise<{
|
type DefineLibraryOptions = (config: ConfigEnv) => Promise<{
|
||||||
library?: LibraryOptions;
|
library?: LibraryOptions;
|
||||||
vite?: UserConfig;
|
vite?: UserConfig;
|
||||||
}>;
|
}>;
|
||||||
|
@ -6,7 +6,7 @@ import { FormApi } from '../src/form-api';
|
|||||||
vi.mock('@vben-core/shared/utils', () => ({
|
vi.mock('@vben-core/shared/utils', () => ({
|
||||||
bindMethods: vi.fn(),
|
bindMethods: vi.fn(),
|
||||||
createMerge: vi.fn((mergeFn) => {
|
createMerge: vi.fn((mergeFn) => {
|
||||||
return (stateOrFn, prev) => {
|
return (stateOrFn: any, prev: any) => {
|
||||||
mergeFn(prev, 'key', stateOrFn);
|
mergeFn(prev, 'key', stateOrFn);
|
||||||
return { ...prev, ...stateOrFn };
|
return { ...prev, ...stateOrFn };
|
||||||
};
|
};
|
||||||
@ -144,3 +144,64 @@ describe('formApi', () => {
|
|||||||
expect(isValid).toBe(true);
|
expect(isValid).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('updateSchema', () => {
|
||||||
|
let instance: FormApi;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
instance = new FormApi();
|
||||||
|
instance.state = {
|
||||||
|
schema: [
|
||||||
|
{ component: 'text', fieldName: 'name' },
|
||||||
|
{ component: 'number', fieldName: 'age', label: 'Age' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the schema correctly when fieldName matches', () => {
|
||||||
|
const newSchema = [
|
||||||
|
{ component: 'text', fieldName: 'name' },
|
||||||
|
{ component: 'number', fieldName: 'age', label: 'Age' },
|
||||||
|
];
|
||||||
|
|
||||||
|
instance.updateSchema(newSchema);
|
||||||
|
|
||||||
|
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||||
|
expect(instance.state?.schema?.[1]?.label).toBe('Age');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log an error if fieldName is missing in some items', () => {
|
||||||
|
const newSchema: any[] = [
|
||||||
|
{ component: 'textarea', fieldName: 'name' },
|
||||||
|
{ component: 'number' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const consoleErrorSpy = vi
|
||||||
|
.spyOn(console, 'error')
|
||||||
|
.mockImplementation(() => {});
|
||||||
|
|
||||||
|
instance.updateSchema(newSchema);
|
||||||
|
|
||||||
|
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
||||||
|
'All items in the schema array must have a valid `fieldName` property to be updated',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update schema if fieldName does not match', () => {
|
||||||
|
const newSchema = [{ component: 'textarea', fieldName: 'unknown' }];
|
||||||
|
|
||||||
|
instance.updateSchema(newSchema);
|
||||||
|
|
||||||
|
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||||
|
expect(instance.state?.schema?.[1]?.component).toBe('number');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not update schema if updatedMap is empty', () => {
|
||||||
|
const newSchema: any[] = [{ component: 'textarea' }];
|
||||||
|
|
||||||
|
instance.updateSchema(newSchema);
|
||||||
|
|
||||||
|
expect(instance.state?.schema?.[0]?.component).toBe('text');
|
||||||
|
expect(instance.state?.schema?.[1]?.component).toBe('number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -5,7 +5,7 @@ import type {
|
|||||||
ValidationOptions,
|
ValidationOptions,
|
||||||
} from 'vee-validate';
|
} from 'vee-validate';
|
||||||
|
|
||||||
import type { FormActions, VbenFormProps } from './types';
|
import type { FormActions, FormSchema, VbenFormProps } from './types';
|
||||||
|
|
||||||
import { toRaw } from 'vue';
|
import { toRaw } from 'vue';
|
||||||
|
|
||||||
@ -186,6 +186,37 @@ export class FormApi {
|
|||||||
this.stateHandler.reset();
|
this.stateHandler.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSchema(schema: Partial<FormSchema>[]) {
|
||||||
|
const updated: Partial<FormSchema>[] = [...schema];
|
||||||
|
const hasField = updated.every(
|
||||||
|
(item) => Reflect.has(item, 'fieldName') && item.fieldName,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hasField) {
|
||||||
|
console.error(
|
||||||
|
'All items in the schema array must have a valid `fieldName` property to be updated',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentSchema = [...(this.state?.schema ?? [])];
|
||||||
|
|
||||||
|
const updatedMap: Record<string, any> = {};
|
||||||
|
|
||||||
|
updated.forEach((item) => {
|
||||||
|
if (item.fieldName) {
|
||||||
|
updatedMap[item.fieldName] = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentSchema.forEach((schema, index) => {
|
||||||
|
const updatedData = updatedMap[schema.fieldName];
|
||||||
|
if (updatedData) {
|
||||||
|
currentSchema[index] = merge(updatedData, schema) as FormSchema;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setState({ schema: currentSchema });
|
||||||
|
}
|
||||||
|
|
||||||
async validate(opts?: Partial<ValidationOptions>) {
|
async validate(opts?: Partial<ValidationOptions>) {
|
||||||
const form = await this.getForm();
|
const form = await this.getForm();
|
||||||
return await form.validate(opts);
|
return await form.validate(opts);
|
||||||
|
@ -52,7 +52,6 @@ const {
|
|||||||
license,
|
license,
|
||||||
version,
|
version,
|
||||||
// vite inject-metadata 插件注入的全局变量
|
// vite inject-metadata 插件注入的全局变量
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
} = __VBEN_ADMIN_METADATA__ || {};
|
} = __VBEN_ADMIN_METADATA__ || {};
|
||||||
|
|
||||||
const vbenDescriptionItems: DescriptionItem[] = [
|
const vbenDescriptionItems: DescriptionItem[] = [
|
||||||
|
@ -143,6 +143,19 @@ watch(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => preferences.app.layout,
|
||||||
|
async (val) => {
|
||||||
|
if (val === 'sidebar-mixed-nav' && preferences.sidebar.hidden) {
|
||||||
|
updatePreferences({
|
||||||
|
sidebar: {
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const slots = useSlots();
|
const slots = useSlots();
|
||||||
const headerSlots = computed(() => {
|
const headerSlots = computed(() => {
|
||||||
return Object.keys(slots).filter((key) => key.startsWith('header-'));
|
return Object.keys(slots).filter((key) => key.startsWith('header-'));
|
||||||
|
@ -12,6 +12,6 @@
|
|||||||
@apply dark:border-border/60 dark:border;
|
@apply dark:border-border/60 dark:border;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-app .form-valid-error .ant-select-selector {
|
.form-valid-error .ant-select-selector {
|
||||||
border-color: hsl(var(--destructive));
|
border-color: hsl(var(--destructive));
|
||||||
}
|
}
|
||||||
|
@ -41,12 +41,25 @@ const [BaseForm, formApi] = useVbenForm({
|
|||||||
label: 'field2',
|
label: 'field2',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: 'Input',
|
component: 'Select',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
placeholder: '请输入',
|
allowClear: true,
|
||||||
|
filterOption: true,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '选项1',
|
||||||
|
value: '1',
|
||||||
},
|
},
|
||||||
fieldName: 'field3',
|
{
|
||||||
label: 'field3',
|
label: '选项2',
|
||||||
|
value: '2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
placeholder: '请选择',
|
||||||
|
showSearch: true,
|
||||||
|
},
|
||||||
|
fieldName: 'fieldOptions',
|
||||||
|
label: '下拉选',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
|
||||||
@ -75,9 +88,35 @@ function handleClick(
|
|||||||
| 'showSubmitButton'
|
| 'showSubmitButton'
|
||||||
| 'updateActionAlign'
|
| 'updateActionAlign'
|
||||||
| 'updateResetButton'
|
| 'updateResetButton'
|
||||||
|
| 'updateSchema'
|
||||||
| 'updateSubmitButton',
|
| 'updateSubmitButton',
|
||||||
) {
|
) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
case 'updateSchema': {
|
||||||
|
formApi.updateSchema([
|
||||||
|
{
|
||||||
|
componentProps: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: '选项1',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '选项2',
|
||||||
|
value: '2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '选项3',
|
||||||
|
value: '3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fieldName: 'fieldOptions',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'labelWidth': {
|
case 'labelWidth': {
|
||||||
formApi.setState({
|
formApi.setState({
|
||||||
commonConfig: {
|
commonConfig: {
|
||||||
@ -181,6 +220,7 @@ function handleClick(
|
|||||||
<template>
|
<template>
|
||||||
<Page description="表单组件api操作示例。" title="表单组件">
|
<Page description="表单组件api操作示例。" title="表单组件">
|
||||||
<Space class="mb-5 flex-wrap">
|
<Space class="mb-5 flex-wrap">
|
||||||
|
<Button @click="handleClick('updateSchema')">updateSchema</Button>
|
||||||
<Button @click="handleClick('labelWidth')">更改labelWidth</Button>
|
<Button @click="handleClick('labelWidth')">更改labelWidth</Button>
|
||||||
<Button @click="handleClick('resetLabelWidth')">还原labelWidth</Button>
|
<Button @click="handleClick('resetLabelWidth')">还原labelWidth</Button>
|
||||||
<Button @click="handleClick('disabled')">禁用表单</Button>
|
<Button @click="handleClick('disabled')">禁用表单</Button>
|
||||||
|
Loading…
Reference in New Issue
Block a user