diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 3b7f8187..9fd86547 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,14 +1,14 @@
# default onwer
-* anncwb@126.com vince292007@gmail.com
+* anncwb@126.com vince292007@gmail.com netfan@foxmail.com
# vben core onwer
-/.github/ anncwb@126.com vince292007@gmail.com
-/.vscode/ anncwb@126.com vince292007@gmail.com
-/packages/ anncwb@126.com vince292007@gmail.com
-/packages/@core/ anncwb@126.com vince292007@gmail.com
-/internal/ anncwb@126.com vince292007@gmail.com
-/scripts/ anncwb@126.com vince292007@gmail.com
+/.github/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
+/.vscode/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
+/packages/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
+/packages/@core/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
+/internal/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
+/scripts/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com
# vben team onwer
-apps/ anncwb@126.com vince292007@gmail.com @vbenjs/team-v5
-docs/ anncwb@126.com vince292007@gmail.com @vbenjs/team-v5
+apps/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5
+docs/ anncwb@126.com vince292007@gmail.com netfan@foxmail.com @vbenjs/team-v5
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 49b28039..b074051d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -99,7 +99,8 @@
"**/.stylelintcache": true,
"**/.DS_Store": true,
"**/vite.config.mts.*": true,
- "**/tea.yaml": true
+ "**/tea.yaml": true,
+ "**/public/tinymce/**": true
},
"files.watcherExclude": {
"**/.git/objects/**": true,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 14e99aa8..676a5698 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,11 @@
- 角色管理 优化Drawer布局
- unplugin-vue-components插件(默认未开启) 需要排除Button组件 全局已经默认导入了
+**BUG FIXES**
+
+- 操作日志详情 在description组件中json预览样式异常
+- 微服务版本 区间查询和中文搜索条件一起使用 无法正确查询
+
# 1.1.2
**Features**
diff --git a/apps/web-antd/.vscode/settings.json b/apps/web-antd/.vscode/settings.json
deleted file mode 100644
index 382d4256..00000000
--- a/apps/web-antd/.vscode/settings.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "editor.tabSize": 2,
- "editor.defaultFormatter": "esbenp.prettier-vscode",
- "editor.formatOnSave": true,
- "editor.codeActionsOnSave": {
- "source.fixAll.eslint": "explicit",
- "source.fixAll.stylelint": "explicit"
- }
-}
diff --git a/apps/web-antd/src/adapter/component/index.ts b/apps/web-antd/src/adapter/component/index.ts
index 9f8a059f..e882435d 100644
--- a/apps/web-antd/src/adapter/component/index.ts
+++ b/apps/web-antd/src/adapter/component/index.ts
@@ -108,7 +108,13 @@ async function initComponentAdapter() {
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
Divider,
- IconPicker,
+ IconPicker: (props, { attrs, slots }) => {
+ return h(
+ IconPicker,
+ { iconSlot: 'addonAfter', inputComponent: Input, ...props, ...attrs },
+ slots,
+ );
+ },
Input: withDefaultPlaceholder(Input, 'input'),
InputNumber: withDefaultPlaceholder(InputNumber, 'input'),
InputPassword: withDefaultPlaceholder(InputPassword, 'input'),
diff --git a/apps/web-antd/src/api/request.ts b/apps/web-antd/src/api/request.ts
index 7d540963..b3d80804 100644
--- a/apps/web-antd/src/api/request.ts
+++ b/apps/web-antd/src/api/request.ts
@@ -10,6 +10,7 @@ import {
authenticateResponseInterceptor,
errorMessageResponseInterceptor,
RequestClient,
+ stringify,
} from '@vben/request';
import { useAccessStore } from '@vben/stores';
@@ -94,6 +95,23 @@ function createRequestClient(baseURL: string) {
// 添加全局clientId
config.headers.clientId = clientId;
+ /**
+ * 格式化get/delete参数
+ * 如果包含自定义的paramsSerializer则不走此逻辑
+ */
+ if (
+ ['DELETE', 'GET'].includes(config.method?.toUpperCase() || '') &&
+ config.params &&
+ !config.paramsSerializer
+ ) {
+ /**
+ * 1. 格式化参数 微服务在传递区间时间选择(后端的params Map类型参数)需要格式化key 否则接收不到
+ * 2. 数组参数需要格式化 后端才能正常接收 会变成arr=1&arr=2&arr=3的格式来接收
+ */
+ config.paramsSerializer = (params) =>
+ stringify(params, { arrayFormat: 'repeat' });
+ }
+
const { encrypt } = config;
// 全局开启请求加密功能 && 该请求开启 && 是post/put请求
if (
diff --git a/apps/web-antd/src/utils/render.tsx b/apps/web-antd/src/utils/render.tsx
index e3a136bb..fcc9102e 100644
--- a/apps/web-antd/src/utils/render.tsx
+++ b/apps/web-antd/src/utils/render.tsx
@@ -68,7 +68,7 @@ export function renderJsonPreview(json: any) {
return {json};
}
if (typeof json === 'object') {
- return ;
+ return ;
}
try {
const obj = JSON.parse(json);
@@ -76,7 +76,7 @@ export function renderJsonPreview(json: any) {
if (typeof obj !== 'object') {
return {obj};
}
- return ;
+ return ;
} catch {
return {json};
}
diff --git a/apps/web-antd/src/views/monitor/operlog/data.tsx b/apps/web-antd/src/views/monitor/operlog/data.tsx
index f5e693ed..1faf87fd 100644
--- a/apps/web-antd/src/views/monitor/operlog/data.tsx
+++ b/apps/web-antd/src/views/monitor/operlog/data.tsx
@@ -157,12 +157,15 @@ export const descSchema: DescItem[] = [
field: 'method',
label: '方法',
},
+ /**
+ * 默认word-break: break-word;会导致json预览样式异常
+ */
{
field: 'operParam',
label: '请求参数',
render(value) {
return (
-
+
{renderJsonPreview(value)}
);
@@ -173,7 +176,7 @@ export const descSchema: DescItem[] = [
label: '响应参数',
render(value) {
return (
-
+
{renderJsonPreview(value)}
);
diff --git a/apps/web-antd/src/views/system/client/client-drawer.vue b/apps/web-antd/src/views/system/client/client-drawer.vue
index cce41494..6ba88e67 100644
--- a/apps/web-antd/src/views/system/client/client-drawer.vue
+++ b/apps/web-antd/src/views/system/client/client-drawer.vue
@@ -28,7 +28,7 @@ const [BasicForm, formApi] = useVbenForm({
layout: 'vertical',
schema: drawerSchema(),
showDefaultActions: false,
- wrapperClass: 'grid-cols-2',
+ wrapperClass: 'grid-cols-2 gap-x-4',
});
function setupForm(update: boolean) {
diff --git a/apps/web-ele/src/adapter/component/index.ts b/apps/web-ele/src/adapter/component/index.ts
index e6d677be..451fef4a 100644
--- a/apps/web-ele/src/adapter/component/index.ts
+++ b/apps/web-ele/src/adapter/component/index.ts
@@ -4,6 +4,7 @@
*/
import type { BaseFormComponentType } from '@vben/common-ui';
+import type { Recordable } from '@vben/types';
import type { Component, SetupContext } from 'vue';
import { h } from 'vue';
@@ -88,15 +89,67 @@ async function initComponentAdapter() {
return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
},
Divider: ElDivider,
- IconPicker,
+ IconPicker: (props, { attrs, slots }) => {
+ return h(
+ IconPicker,
+ {
+ iconSlot: 'append',
+ modelValueProp: 'model-value',
+ inputComponent: ElInput,
+ ...props,
+ ...attrs,
+ },
+ slots,
+ );
+ },
Input: withDefaultPlaceholder(ElInput, 'input'),
InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
RadioGroup: ElRadioGroup,
Select: withDefaultPlaceholder(ElSelect, 'select'),
Space: ElSpace,
Switch: ElSwitch,
- TimePicker: ElTimePicker,
- DatePicker: ElDatePicker,
+ TimePicker: (props, { attrs, slots }) => {
+ const { name, id, isRange } = props;
+ const extraProps: Recordable
= {};
+ if (isRange) {
+ if (name && !Array.isArray(name)) {
+ extraProps.name = [name, `${name}_end`];
+ }
+ if (id && !Array.isArray(id)) {
+ extraProps.id = [id, `${id}_end`];
+ }
+ }
+ return h(
+ ElTimePicker,
+ {
+ ...props,
+ ...attrs,
+ ...extraProps,
+ },
+ slots,
+ );
+ },
+ DatePicker: (props, { attrs, slots }) => {
+ const { name, id, type } = props;
+ const extraProps: Recordable = {};
+ if (type && type.includes('range')) {
+ if (name && !Array.isArray(name)) {
+ extraProps.name = [name, `${name}_end`];
+ }
+ if (id && !Array.isArray(id)) {
+ extraProps.id = [id, `${id}_end`];
+ }
+ }
+ return h(
+ ElDatePicker,
+ {
+ ...props,
+ ...attrs,
+ ...extraProps,
+ },
+ slots,
+ );
+ },
TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
Upload: ElUpload,
};
diff --git a/apps/web-naive/src/adapter/component/index.ts b/apps/web-naive/src/adapter/component/index.ts
index a007d52d..6fa96510 100644
--- a/apps/web-naive/src/adapter/component/index.ts
+++ b/apps/web-naive/src/adapter/component/index.ts
@@ -89,7 +89,13 @@ async function initComponentAdapter() {
return h(NButton, { ...props, attrs, type: 'primary' }, slots);
},
Divider: NDivider,
- IconPicker,
+ IconPicker: (props, { attrs, slots }) => {
+ return h(
+ IconPicker,
+ { iconSlot: 'suffix', inputComponent: NInput, ...props, ...attrs },
+ slots,
+ );
+ },
Input: withDefaultPlaceholder(NInput, 'input'),
InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
RadioGroup: NRadioGroup,
diff --git a/docs/src/components/common-ui/vben-form.md b/docs/src/components/common-ui/vben-form.md
index ea3c53a5..ce27e1f2 100644
--- a/docs/src/components/common-ui/vben-form.md
+++ b/docs/src/components/common-ui/vben-form.md
@@ -316,6 +316,7 @@ useVbenForm 返回的第二个参数,是一个对象,包含了一些表单
| commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - |
| schema | 表单项的每一项配置 | `FormSchema` | - |
| submitOnEnter | 按下回车健时提交表单 | `boolean` | false |
+| submitOnChange | 字段值改变时提交表单 | `boolean` | false |
### TS 类型说明
diff --git a/docs/src/components/layout-ui/page.md b/docs/src/components/layout-ui/page.md
index 8a33775c..29fbdd40 100644
--- a/docs/src/components/layout-ui/page.md
+++ b/docs/src/components/layout-ui/page.md
@@ -18,15 +18,14 @@ outline: deep
### Props
-| 属性名 | 描述 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| title | 页面标题 | `string\|slot` | - |
-| description | 页面描述(标题下的内容) | `string\|slot` | - |
-| contentClass | 内容区域的class | `string` | - |
-| headerClass | 头部区域的class | `string` | - |
-| footerClass | 底部区域的class | `string` | - |
-| autoContentHeight | 自动调整内容区域的高度 | `boolean` | `false` |
-| fixedHeader | 固定头部在页面内容区域顶部,在滚动时保持可见 | `boolean` | `false` |
+| 属性名 | 描述 | 类型 | 默认值 | 说明 |
+| --- | --- | --- | --- | --- |
+| title | 页面标题 | `string\|slot` | - | - |
+| description | 页面描述(标题下的内容) | `string\|slot` | - | - |
+| contentClass | 内容区域的class | `string` | - | - |
+| headerClass | 头部区域的class | `string` | - | - |
+| footerClass | 底部区域的class | `string` | - | - |
+| autoContentHeight | 自动调整内容区域的高度 | `boolean` | `false` | - |
::: tip 注意
diff --git a/docs/src/demos/vben-vxe-table/form/index.vue b/docs/src/demos/vben-vxe-table/form/index.vue
index a5e8a547..b5be6c65 100644
--- a/docs/src/demos/vben-vxe-table/form/index.vue
+++ b/docs/src/demos/vben-vxe-table/form/index.vue
@@ -76,6 +76,8 @@ const formOptions: VbenFormProps = {
submitButtonOptions: {
content: '查询',
},
+ // 是否在字段值改变时提交表单
+ submitOnChange: false,
// 按下回车时是否提交表单
submitOnEnter: false,
};
diff --git a/packages/@core/base/shared/src/utils/date.ts b/packages/@core/base/shared/src/utils/date.ts
index 522e9946..3736b9ad 100644
--- a/packages/@core/base/shared/src/utils/date.ts
+++ b/packages/@core/base/shared/src/utils/date.ts
@@ -16,3 +16,11 @@ export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
export function formatDateTime(time: number | string) {
return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
}
+
+export function isDate(value: any): value is Date {
+ return value instanceof Date;
+}
+
+export function isDayjsObject(value: any): value is dayjs.Dayjs {
+ return dayjs.isDayjs(value);
+}
diff --git a/packages/@core/ui-kit/form-ui/src/form-api.ts b/packages/@core/ui-kit/form-ui/src/form-api.ts
index 08318f3c..585afaff 100644
--- a/packages/@core/ui-kit/form-ui/src/form-api.ts
+++ b/packages/@core/ui-kit/form-ui/src/form-api.ts
@@ -14,6 +14,8 @@ import { Store } from '@vben-core/shared/store';
import {
bindMethods,
createMerge,
+ isDate,
+ isDayjsObject,
isFunction,
isObject,
mergeWithArrayOverride,
@@ -36,6 +38,7 @@ function getDefaultState(): VbenFormProps {
showCollapseButton: false,
showDefaultActions: true,
submitButtonOptions: {},
+ submitOnChange: false,
submitOnEnter: false,
wrapperClass: 'grid-cols-1',
};
@@ -251,10 +254,19 @@ export class FormApi {
return;
}
+ /**
+ * 合并算法有待改进,目前的算法不支持object类型的值。
+ * antd的日期时间相关组件的值类型为dayjs对象
+ * element-plus的日期时间相关组件的值类型可能为Date对象
+ * 以上两种类型需要排除深度合并
+ */
const fieldMergeFn = createMerge((obj, key, value) => {
if (key in obj) {
obj[key] =
- !Array.isArray(obj[key]) && isObject(obj[key])
+ !Array.isArray(obj[key]) &&
+ isObject(obj[key]) &&
+ !isDayjsObject(obj[key]) &&
+ !isDate(obj[key])
? fieldMergeFn(obj[key], value)
: value;
}
diff --git a/packages/@core/ui-kit/form-ui/src/types.ts b/packages/@core/ui-kit/form-ui/src/types.ts
index 5855ccc6..30daaee2 100644
--- a/packages/@core/ui-kit/form-ui/src/types.ts
+++ b/packages/@core/ui-kit/form-ui/src/types.ts
@@ -342,6 +342,12 @@ export interface VbenFormProps<
*/
submitButtonOptions?: ActionButtonOptions;
+ /**
+ * 是否在字段值改变时提交表单
+ * @default false
+ */
+ submitOnChange?: boolean;
+
/**
* 是否在回车时提交表单
* @default false
diff --git a/packages/@core/ui-kit/form-ui/src/vben-use-form.vue b/packages/@core/ui-kit/form-ui/src/vben-use-form.vue
index 0401d48e..a1395328 100644
--- a/packages/@core/ui-kit/form-ui/src/vben-use-form.vue
+++ b/packages/@core/ui-kit/form-ui/src/vben-use-form.vue
@@ -6,7 +6,9 @@ import type { ExtendedFormApi, VbenFormProps } from './types';
import { useForwardPriorityValues } from '@vben-core/composables';
// import { isFunction } from '@vben-core/shared/utils';
-import { useTemplateRef } from 'vue';
+import { toRaw, useTemplateRef, watch } from 'vue';
+
+import { useDebounceFn } from '@vueuse/core';
import FormActions from './components/form-actions.vue';
import {
@@ -56,6 +58,17 @@ function handleKeyDownEnter(event: KeyboardEvent) {
formActionsRef.value?.handleSubmit?.();
}
+
+watch(
+ () => form.values,
+ useDebounceFn(() => {
+ (props.handleValuesChange ?? state.value.handleValuesChange)?.(
+ toRaw(form.values),
+ );
+ state.value.submitOnChange && props.formApi?.submitForm();
+ }, 300),
+ { deep: true },
+);
diff --git a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue
index 98932e25..a598f291 100644
--- a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue
+++ b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue
@@ -503,7 +503,7 @@ function handleHeaderToggle() {
diff --git a/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue b/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue
index a8e56d8c..09460b90 100644
--- a/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue
+++ b/packages/@core/ui-kit/shadcn-ui/src/ui/sheet/SheetFooter.vue
@@ -7,10 +7,7 @@ const props = defineProps<{ class?: any }>();
diff --git a/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue b/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue
index a19855d4..323ce447 100644
--- a/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue
+++ b/packages/effects/common-ui/src/components/icon-picker/icon-picker.vue
@@ -1,12 +1,11 @@
@@ -119,24 +143,18 @@ defineExpose({ toggleOpenState, open, close });
content-class="p-0 pt-3"
>
-
-
-
-
-
-
+
+
+
+
+
-
+
diff --git a/packages/effects/common-ui/src/components/markdown/editor.vue b/packages/effects/common-ui/src/components/markdown/editor.vue
index 8a64c67c..47ffbe04 100644
--- a/packages/effects/common-ui/src/components/markdown/editor.vue
+++ b/packages/effects/common-ui/src/components/markdown/editor.vue
@@ -82,6 +82,13 @@ const content = defineModel('value', {
type: String,
default: '',
});
+/**
+ * 为了保持外部直接(v-model)与编辑器内部的同步
+ * 注意: 下面的input事件也会触发watch
+ */
+watch(content, (value) => {
+ vditorInstance.value?.setValue(value);
+});
// 监听禁用
function changeDisabled(disabled: boolean) {
diff --git a/packages/effects/common-ui/src/components/page/page.vue b/packages/effects/common-ui/src/components/page/page.vue
index a7fea6a5..250ce91e 100644
--- a/packages/effects/common-ui/src/components/page/page.vue
+++ b/packages/effects/common-ui/src/components/page/page.vue
@@ -1,14 +1,7 @@
@@ -84,23 +85,8 @@ const iconValue = ref('ant-design:trademark-outlined');
- 完整替换触发组件:
-
-
-
-
-
-
-
-
-
+ 使用Input:
+
可手动输入,只能点击图标打开弹窗:
@@ -111,14 +97,7 @@ const iconValue = ref('ant-design:trademark-outlined');
style="width: 300px"
>
-
-
-
-
-
+
diff --git a/playground/src/views/examples/form/basic.vue b/playground/src/views/examples/form/basic.vue
index 09a8c74d..c995fe26 100644
--- a/playground/src/views/examples/form/basic.vue
+++ b/playground/src/views/examples/form/basic.vue
@@ -362,7 +362,6 @@ function handleSetFormValue() {
diff --git a/playground/src/views/examples/modal/index.vue b/playground/src/views/examples/modal/index.vue
index 22e9ed8c..d6db2fba 100644
--- a/playground/src/views/examples/modal/index.vue
+++ b/playground/src/views/examples/modal/index.vue
@@ -77,7 +77,6 @@ function openFormModal() {
diff --git a/playground/src/views/examples/vxe-table/form.vue b/playground/src/views/examples/vxe-table/form.vue
index fad0cf58..90035033 100644
--- a/playground/src/views/examples/vxe-table/form.vue
+++ b/playground/src/views/examples/vxe-table/form.vue
@@ -65,6 +65,8 @@ const formOptions: VbenFormProps = {
],
// 控制表单是否显示折叠按钮
showCollapseButton: true,
+ // 是否在字段值改变时提交表单
+ submitOnChange: true,
// 按下回车时是否提交表单
submitOnEnter: false,
};