Compare commits

..

43 Commits
v2.11.5 ... v2

Author SHA1 Message Date
Tang
038936ff7d fix(table): Fixed table tree structure bug (#4543) 2024-09-29 10:50:10 +08:00
li-yi-hong
960f1d3c0b fix: 修复table setting 上下不居中 (#4410) 2024-09-15 21:36:36 +08:00
lijian3828940
f67b5d8569 table控件settingCache在非开发模式下为true,优化用户体验 (#4310) 2024-09-03 21:26:16 +08:00
YanQi
f99cc9b9fe fix: modify the default image type to avoid cropping images that become too large. (#4307)
Co-authored-by: YanQi <yanqirj@gmail.com>
2024-09-03 21:26:01 +08:00
lijian3828940
0cf2271667 fix:修复showAdvancedButton为true时,FormSchema中ifshow是与model有关的函数时候,查询按钮位置不重新计算的问题。 (#4304) 2024-09-03 13:02:49 +08:00
alucardxh
6d2de002ef Support array parameter parsing (#4300) 2024-09-02 09:55:11 +08:00
张阿文
617e594d8d refactor(form): 使用空值合并运算符 (??) 和 isDef 优化宽度判断逻辑,处理 labelWidth 可能为 0 的情况 (#4086) 2024-08-08 20:50:32 +08:00
coderPeng3yang
4aac1c388c 删除了多余的菜单数据的步骤,减少性能开销,优化初始化速度。 (#4012)
* types(logic): 减少冗沉,用了泛型

* perf(router): 删除了多余的菜单数据的步骤,减少性能开销,优化初始化速度。

删除了每次刷新页面都会获取静态菜单数据的操作,改为在角色权限控制时才进行数据获取。

此更改优化了应用的初始化速度,减少了不必要的性能开销,并且确保获取静态菜单数据时不会污染路由数据。

这样可以确保其他地方更清晰地跟踪路由数据

---------

Co-authored-by: zach.zqy <bianzhixiaoyuan@163.com>
2024-08-06 18:36:18 +08:00
No name
7b6531a309 fix: The projectSettings default dark mode is not taking effect (#4052)
The projectSettings default dark mode is not taking effect. In the getDarkMode function, setting.menuSetting.theme should be present must be higher priority than darkMode.
2024-08-06 10:58:26 +08:00
1455668754
65651fc25c feat: 1.ApiSelect增加远程搜索功能 2.ApiSelect设定懒加载时允许控制空搜索时不查询 3.增加下拉远程搜索Json版本demo (#3992)
* feat: 1.ApiSelect增加远程搜索功能 2.ApiSelect设定懒加载时允许控制空搜索时不查询

* feat: 增加下拉远程搜索Json版本demo
2024-08-02 08:24:21 +08:00
vince
4fcbdd3925 Merge pull request #3991 from vbenjs/update-upgrade-prompt
chore: update UpgradePrompt
2024-08-01 09:55:25 +08:00
Li Kui
db2a27060c chore: update UpgradePrompt 2024-08-01 07:50:30 +08:00
vince
d9bfe96dad Merge pull request #3986 from 1455668754/main
fix: Echarts初始宽度监听修复
2024-08-01 05:11:35 +08:00
vince
77a0ad450d Merge pull request #3987 from mrmsl/main
chore(multipleTab): Make the code more readable
2024-08-01 05:10:56 +08:00
vince
c37ed8f7e9 Merge pull request #3988 from snapea/fix/mult-upload
fix(upload): 修复上传组件删除无效bug
2024-08-01 05:10:24 +08:00
vince
1698be7ce4 chore: update upgrade prompt 2024-08-01 05:07:53 +08:00
vince
ea5c66b6eb feat: add upgrade prompt 2024-07-31 22:15:01 +08:00
wen zhenjin
371c972cc1 fix(upload): 修复上传组件删除无效bug 2024-07-31 11:50:40 +08:00
mrmsl
2880174be2 fix(multipleTab): 已经打开的动态路由数判断bug 2024-07-31 10:20:51 +08:00
vince
b0c0b916fd fix: Wrong color value 2024-07-31 00:26:08 +08:00
雪忆
f314826230 Revert "feat: ApiSelect增加远程搜索功能"
This reverts commit 56c5dce99f.
2024-07-29 15:18:30 +08:00
雪忆
56c5dce99f feat: ApiSelect增加远程搜索功能 2024-07-29 15:14:07 +08:00
雪忆
95abe06107 fix: Echarts初始宽度监听修复 2024-07-29 15:11:06 +08:00
雪忆
ecfe66a019 Merge remote-tracking branch 'origin/main' 2024-07-29 15:10:40 +08:00
苗大
25699c0b60 feat(Preview): 优化实例创建更新逻辑, 防止重复创建dom (#3979)
* perf(Preview): 优化实例创建更新逻辑, 防止重复创建dom

* perf: 逻辑优化
2024-07-26 14:30:14 +08:00
Sny
5b7b6b1780 chore(component): 优化EditableCell组件handleSubmit方法报错时增加warn日志显示 (#3981)
closed #3869
2024-07-26 14:28:20 +08:00
coderPeng3yang
57ff038d82 chore: types(logic) 减少冗沉,用了泛型 (#3977)
Co-authored-by: zach.zqy <bianzhixiaoyuan@163.com>
2024-07-25 10:08:20 +08:00
clddup
baf406e7e2 chore: 格式化代码 (#3972) 2024-07-19 16:47:21 +08:00
苗大
1745f480fd fix: typo opend -> opened (#3968) 2024-07-17 13:56:09 +08:00
fourteendp
cec5c11289 fix(VxeTable): 修复VxeTable自定义组件重复注册导致控制台警告 (#3944) 2024-07-04 14:12:52 +08:00
Allure-eve
dd1b16acdc fix(BasicTable): ColumnSettings.vue columnOptions typeof lost (#3941) 2024-07-04 08:50:58 +08:00
fourteendp
64a4992a84 fix(VxeTable): 更新vxe-table以及相关依赖,修改废弃API至最新 (#3939) 2024-07-04 08:49:47 +08:00
jinmao88
cae5538aba fix(VxeTable): update vxeTable ,fix imports and support theme change 2024-06-24 16:33:55 +08:00
1455668754
e7868e7193 fix: vxe-table index.css已废弃,切换至all (#3926)
fix: vxe-table index.css已废弃,切换至all
2024-06-24 16:06:25 +08:00
No name
71c4edad63 chore: improve build file naming convention and caching (#3908)
* fix: improve build file naming convention

* remove js to the entryFileName path

* replace dot to hyphen
2024-06-14 15:26:49 +08:00
Electrolux
65fba1c329 perf(UploadPreviewModal): delete invalid assign (#3915) 2024-06-13 18:24:11 +08:00
Li Kui
8d3981f599 fix: axios retry losing headers (#3902) 2024-06-07 11:42:48 +08:00
Electrolux
cca7f59fac fix(BasicForm->Upload): setValue and defaultValue uncertain && rule about first render (#3900)
* chore: upload component defaulttype should be array

* chore: upload component setFieldsValue  should be array

* chore(upload): split event between change and  update:value

* update

* update
2024-06-06 15:27:15 +08:00
苗大
1a5692060b perf: 未登录重定向路径存储改为完整路径 (#3897) 2024-06-06 11:31:50 +08:00
1455668754
4974de2553 chore: typo destroy word 2024-06-04 16:23:02 +08:00
No name
f83002441d fix(dataSource): BasicTable Component with dataSource is not working (hot fix) (#3888) 2024-06-04 16:22:09 +08:00
雪忆
e84c4051f3 fix: destroy方法命名修正 2024-06-03 17:33:50 +08:00
Fifteen
af39afa24b perf(demo->screenshot): optimize the screenshot code && add print and download (#3885) 2024-06-03 08:56:55 +08:00
81 changed files with 716 additions and 373 deletions

View File

@@ -5,4 +5,4 @@
PATH="/usr/local/bin:$PATH"
npx --no-install commitlint --edit "$1"
# npx --no-install commitlint --edit "$1"

View File

@@ -7,4 +7,4 @@
PATH="/usr/local/bin:$PATH"
# Format and submit code according to lintstagedrc.js configuration
pnpm exec lint-staged
# pnpm exec lint-staged

View File

@@ -63,8 +63,8 @@ function defineApplicationConfig(defineOptions: DefineOptions = {}) {
cssTarget: 'chrome80',
rollupOptions: {
output: {
// 入口文件名(不能变,否则所有打包的 js hash 值全变了)
entryFileNames: 'index.js',
// 入口文件名
entryFileNames: 'assets/entry/[name]-[hash].js',
manualChunks: {
vue: ['vue', 'pinia', 'vue-router'],
antd: ['ant-design-vue', '@ant-design/icons-vue'],

View File

@@ -107,9 +107,10 @@
"vue-router": "^4.3.2",
"vue-types": "^5.1.1",
"vuedraggable": "^4.1.0",
"vxe-table": "^4.6.3",
"vxe-table-plugin-export-xlsx": "^4.0.1",
"xe-utils": "^3.5.25",
"vxe-pc-ui": "^4.0.44",
"vxe-table": "^4.7.40",
"vxe-table-plugin-export-xlsx": "^4.0.4",
"xe-utils": "^3.5.28",
"xlsx": "^0.18.5"
},
"devDependencies": {

62
pnpm-lock.yaml generated
View File

@@ -122,15 +122,18 @@ importers:
vuedraggable:
specifier: ^4.1.0
version: 4.1.0(vue@3.4.25(typescript@5.4.5))
vxe-pc-ui:
specifier: ^4.0.44
version: 4.0.44
vxe-table:
specifier: ^4.6.3
version: 4.6.3(vue@3.4.25(typescript@5.4.5))
specifier: ^4.7.40
version: 4.7.40
vxe-table-plugin-export-xlsx:
specifier: ^4.0.1
version: 4.0.1(vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5)))
specifier: ^4.0.4
version: 4.0.4(vxe-table@4.7.40)
xe-utils:
specifier: ^3.5.25
version: 3.5.25
specifier: ^3.5.28
version: 3.5.28
xlsx:
specifier: ^0.18.5
version: 0.18.5
@@ -2005,6 +2008,9 @@ packages:
'@vueuse/shared@10.9.0':
resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
'@vxe-ui/core@1.0.12':
resolution: {integrity: sha512-s79mQw6uYSbTVGBWbxrisHwJV1b770vZMT9XpY3khcFQhXNo25+PS3FLrNCSsBBJR0ZkBLOXDER/ft9DIqgFTw==}
'@zxcvbn-ts/core@3.0.4':
resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==}
@@ -3096,8 +3102,8 @@ packages:
dom-serializer@2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dom-zindex@1.0.2:
resolution: {integrity: sha512-QceDZxPlvzhpg6e8szxNiKPUt5Y9SfFTe3nZy8og3JoPQPlAlzBzHa/lhDkhgeG3cjbKyQcuoic+wymF0o0d1Q==}
dom-zindex@1.0.4:
resolution: {integrity: sha512-PNk7u71TJ1C9Lwjjp5nNuQcVWuECFMmr9kZAwi2UbgWUM7jXdTCe4O4x5bhLUa07jpcZUVA5Du3ho7/FXzS9Ng==}
domelementtype@1.3.1:
resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==}
@@ -7060,15 +7066,16 @@ packages:
peerDependencies:
vue: ^3.0.1
vxe-table-plugin-export-xlsx@4.0.1:
resolution: {integrity: sha512-puUOUfptu5ciEiFqTlVni3twLICSbkl87uXOsjZzrEyXJHJS9dYu7ZTD7/DRMqyuWyU3Idg7AekfcdcslP4Y/A==}
vxe-pc-ui@4.0.44:
resolution: {integrity: sha512-wiauFMmSvEkVKa/AsKGb5CMi91Ojts+Ydcn+iespgl3xMBD01BR/CGzeCI478P3XAFBsiN4gWlgxHmGP5TR8UA==}
vxe-table-plugin-export-xlsx@4.0.4:
resolution: {integrity: sha512-Og2ZcIWTV7msT1ddPT/spxJaP1T8wxs3Uuu1LO/3HL5Ugt9tShEY3FJ7YGic3j1Nk6ZZT+VsU+afgT5EzpcUJw==}
peerDependencies:
vxe-table: ^4.5.0
vxe-table@4.6.3:
resolution: {integrity: sha512-71FOi0lFQbvs1dUIZPTDCLaSJkRjLHlBuNzWIR9RofBe4EvhX4OowrhaCCsCXXKCCGSlJRp6+/O2c71lEZY9PQ==}
peerDependencies:
vue: ^3.2.28
vxe-table@4.7.40:
resolution: {integrity: sha512-y9VC3oLJgusxFj3xZ28G4gU+YClBuDIV8oM75Dx3doYJ7vanXZnSf70XJ+W5xEKflamUmjGre66XZ2b4XuqtMw==}
w3c-hr-time@1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
@@ -7206,8 +7213,8 @@ packages:
utf-8-validate:
optional: true
xe-utils@3.5.25:
resolution: {integrity: sha512-d/ty5eo4hXtho/3195XAvqereIoSYJ+XfC52f3ZEPxTaCeyLFivDZTyX6gTdsR65ISH1Irvn85H0bSL60dUhSQ==}
xe-utils@3.5.28:
resolution: {integrity: sha512-oeLLJ0b54QdOSSgYQ9TiKW/xAGrc9r0weCA/5UfyGdm3n3js4cNOuuf9Tml7UwgBQpl4uWMbMwUZKLh2yqPF3A==}
xlsx@0.18.5:
resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==}
@@ -9228,6 +9235,11 @@ snapshots:
- '@vue/composition-api'
- vue
'@vxe-ui/core@1.0.12':
dependencies:
dom-zindex: 1.0.4
xe-utils: 3.5.28
'@zxcvbn-ts/core@3.0.4':
dependencies:
fastest-levenshtein: 1.0.16
@@ -10389,7 +10401,7 @@ snapshots:
domhandler: 5.0.3
entities: 4.5.0
dom-zindex@1.0.2: {}
dom-zindex@1.0.4: {}
domelementtype@1.3.1: {}
@@ -15005,15 +15017,17 @@ snapshots:
sortablejs: 1.14.0
vue: 3.4.25(typescript@5.4.5)
vxe-table-plugin-export-xlsx@4.0.1(vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5))):
vxe-pc-ui@4.0.44:
dependencies:
vxe-table: 4.6.3(vue@3.4.25(typescript@5.4.5))
'@vxe-ui/core': 1.0.12
vxe-table@4.6.3(vue@3.4.25(typescript@5.4.5)):
vxe-table-plugin-export-xlsx@4.0.4(vxe-table@4.7.40):
dependencies:
dom-zindex: 1.0.2
vue: 3.4.25(typescript@5.4.5)
xe-utils: 3.5.25
vxe-table: 4.7.40
vxe-table@4.7.40:
dependencies:
vxe-pc-ui: 4.0.44
w3c-hr-time@1.0.2:
dependencies:
@@ -15138,7 +15152,7 @@ snapshots:
ws@8.16.0: {}
xe-utils@3.5.25: {}
xe-utils@3.5.28: {}
xlsx@0.18.5:
dependencies:

View File

@@ -151,7 +151,7 @@
fileReader.onerror = () => {
emit('cropendError');
};
}, 'image/png');
}, 'image/jpeg');
}
// Get a circular picture canvas

View File

@@ -54,7 +54,7 @@
import { useFormValues } from './hooks/useFormValues';
import useAdvanced from './hooks/useAdvanced';
import { useFormEvents } from './hooks/useFormEvents';
import { itemIsUploadComponent, useFormEvents } from './hooks/useFormEvents';
import { createFormContext } from './hooks/useFormContext';
import { useAutoFocus } from './hooks/useAutoFocus';
import { useModalContext } from '@/components/Modal';
@@ -64,7 +64,7 @@
import { useDesign } from '@/hooks/web/useDesign';
import { cloneDeep } from 'lodash-es';
import { TableActionType } from '@/components/Table';
import { isFunction } from '@/utils/is';
import { isArray, isFunction } from '@/utils/is';
defineOptions({ name: 'BasicForm' });
@@ -124,7 +124,9 @@
const getBindValue = computed(() => ({ ...attrs, ...props, ...unref(getProps) }) as AntFormProps);
const getSchema = computed((): FormSchema[] => {
const schemas: FormSchema[] = cloneDeep(unref(schemaRef) || (unref(getProps).schemas as any));
const schemas: (FormSchema & { ifshow2?: boolean })[] = cloneDeep(
unref(schemaRef) || (unref(getProps).schemas as any),
);
for (const schema of schemas) {
const {
defaultValue,
@@ -134,7 +136,16 @@
field,
isHandleDefaultValue = true,
valueFormat,
ifShow,
} = schema;
//fix:修复showAdvancedButton为true时FormSchema中ifshow是与model有关的函数时候查询按钮位置不重新计算的问题。
if (unref(getProps).showAdvancedButton) {
schema.ifshow2 = isFunction(ifShow)
? ifShow({ schema, values: formModel, model: formModel, field })
: ifShow;
}
// handle date type
if (
isHandleDateDefaultValue &&
@@ -165,14 +176,17 @@
schema.defaultValue = def;
}
}
// handle upload type
if (defaultValue && itemIsUploadComponent(schema?.component)) {
if (isArray(defaultValue)) {
schema.defaultValue = defaultValue;
} else if (typeof defaultValue == 'string') {
schema.defaultValue = [defaultValue];
}
}
// handle schema.valueFormat
if (
isHandleDefaultValue &&
defaultValue &&
component &&
isFunction(valueFormat)
) {
if (isHandleDefaultValue && defaultValue && component && isFunction(valueFormat)) {
schema.defaultValue = valueFormat({
value: defaultValue,
schema,

View File

@@ -3,6 +3,7 @@
@dropdown-visible-change="handleFetch"
v-bind="$attrs"
@change="handleChange"
@search="debounceSearchFn"
:options="getOptions"
v-model:value="state"
>
@@ -20,26 +21,41 @@
</template>
</Select>
</template>
<script lang="ts" setup>
import { PropType, ref, computed, unref, watch } from 'vue';
import { computed, PropType, ref, unref, watch } from 'vue';
import { Select } from 'ant-design-vue';
import type { SelectValue } from 'ant-design-vue/es/select';
import { isFunction } from '@/utils/is';
import { isEmpty, isFunction } from '@/utils/is';
import { useRuleFormItem } from '@/hooks/component/useFormItem';
import { get, omit, isEqual } from 'lodash-es';
import { assignIn, get, isEqual, omit } from 'lodash-es';
import { LoadingOutlined } from '@ant-design/icons-vue';
import { useI18n } from '@/hooks/web/useI18n';
import { propTypes } from '@/utils/propTypes';
import { useDebounceFn } from '@vueuse/core';
type OptionsItem = { label?: string; value?: string; disabled?: boolean; [name: string]: any };
type ApiSearchOption = {
// 展示搜索
show?: boolean;
// 待搜索字段名
searchName?: string;
// 是否允许空搜索
emptySearch?: boolean;
// 搜索前置方法
beforeFetch?: (value?: string) => Promise<string>;
// 拦截方法
interceptFetch?: (value?: string) => Promise<boolean>;
};
defineOptions({ name: 'ApiSelect', inheritAttrs: false });
const props = defineProps({
value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
numberToString: propTypes.bool,
api: {
type: Function as PropType<(arg?: any) => Promise<OptionsItem[] | Recordable<any>>>,
type: Function as PropType<(arg?: any) => Promise<OptionsItem[] | Recordable>>,
default: null,
},
// api params
@@ -54,6 +70,10 @@
type: Array<OptionsItem>,
default: [],
},
apiSearch: {
type: Object as PropType<ApiSearchOption>,
default: () => null,
},
beforeFetch: {
type: Function as PropType<Fn>,
default: null,
@@ -72,6 +92,7 @@
// 首次是否加载过了
const isFirstLoaded = ref(false);
const emitData = ref<OptionsItem[]>([]);
const searchParams = ref<any>({});
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
@@ -110,16 +131,29 @@
{ deep: true, immediate: props.immediate },
);
watch(
() => searchParams.value,
(value, oldValue) => {
if (isEmpty(value) || isEqual(value, oldValue)) return;
(async () => {
await fetch();
searchParams.value = {};
})();
},
{ deep: true, immediate: props.immediate },
);
async function fetch() {
let { api, beforeFetch, afterFetch, params, resultField } = props;
if (!api || !isFunction(api) || loading.value) return;
optionsRef.value = [];
try {
loading.value = true;
let apiParams = assignIn({}, params, searchParams.value);
if (beforeFetch && isFunction(beforeFetch)) {
params = (await beforeFetch(params)) || params;
apiParams = (await beforeFetch(apiParams)) || apiParams;
}
let res = await api(params);
let res = await api(apiParams);
if (afterFetch && isFunction(afterFetch)) {
res = (await afterFetch(res)) || res;
}
@@ -147,11 +181,43 @@
if (props.alwaysLoad) {
await fetch();
} else if (!props.immediate && !unref(isFirstLoaded)) {
await fetch();
// 动态搜索查询时,允许控制初始不加载数据
if (!(!!props.apiSearch && !!props.apiSearch.show && !props.apiSearch.emptySearch)) {
await fetch();
} else {
optionsRef.value = [];
emitChange();
}
}
}
}
let debounceSearchFn = useDebounceFn(handleSearch, 500);
async function handleSearch(value: any) {
if (!props.apiSearch) {
return;
}
const { show, searchName, beforeFetch, interceptFetch } = props.apiSearch;
if (!show || !searchName) {
return;
}
value = value || undefined;
if (beforeFetch && isFunction(beforeFetch)) {
value = (await beforeFetch(value)) || value;
}
if (interceptFetch && isFunction(interceptFetch)) {
if (!(await interceptFetch(value))) {
return;
}
}
searchParams.value = {
[searchName]: value,
};
}
function emitChange() {
emit('options-change', unref(getOptions));
}

View File

@@ -287,11 +287,11 @@
const on = {
[eventKey]: (...args: Nullable<Recordable<any>>[]) => {
const [e] = args;
const target = e ? e.target : null;
let value = target ? (isCheck ? target.checked : target.value) : e;
if(isFunction(valueFormat)){
value = valueFormat({...unref(getValues),value});
if (isFunction(valueFormat)) {
value = valueFormat({ ...unref(getValues), value });
}
props.setFormModel(field, value, props.schema);

View File

@@ -31,8 +31,13 @@ export function createPlaceholderMessage(component: ComponentType) {
const DATE_TYPE = ['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'];
/**
* 上传组件
*/
export const uploadItemType: ComponentType[] = ['Upload', 'ImageUpload'];
function genType() {
return [...DATE_TYPE, 'RangePicker',"TimeRangePicker"];
return [...DATE_TYPE, 'RangePicker', 'TimeRangePicker'];
}
export function setComponentRuleType(
@@ -45,7 +50,7 @@ export function setComponentRuleType(
}
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) {
rule.type = valueFormat ? 'string' : 'object';
} else if (['RangePicker', 'Upload', 'CheckboxGroup'].includes(component)) {
} else if (['RangePicker', 'CheckboxGroup'].includes(component)) {
rule.type = 'array';
} else if (['InputNumber'].includes(component)) {
rule.type = 'number';

View File

@@ -1,6 +1,15 @@
import type { ColEx } from '../types';
import type { AdvanceState } from '../types/hooks';
import { ComputedRef, getCurrentInstance, Ref, shallowReactive, computed, unref, watch } from 'vue';
import {
ComputedRef,
getCurrentInstance,
Ref,
shallowReactive,
computed,
unref,
watch,
nextTick,
} from 'vue';
import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
import { isBoolean, isFunction, isNumber, isObject } from '@/utils/is';
import { useBreakpoint } from '@/hooks/event/useBreakpoint';
@@ -49,14 +58,17 @@ export default function ({
return 0;
});
const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30);
// const debounceUpdateAdvanced = useDebounceFn(updateAdvanced, 30);
watch(
[() => unref(getSchema), () => advanceState.isAdvanced, () => unref(realWidthRef)],
() => {
const { showAdvancedButton } = unref(getProps);
if (showAdvancedButton) {
debounceUpdateAdvanced();
// debounceUpdateAdvanced();
nextTick(() => {
updateAdvanced();
});
}
},
{ immediate: true },

View File

@@ -4,10 +4,16 @@ import type { NamePath } from 'ant-design-vue/lib/form/interface';
import { unref, toRaw, nextTick } from 'vue';
import { isArray, isFunction, isObject, isString, isNil } from '@/utils/is';
import { deepMerge } from '@/utils';
import { dateItemType, defaultValueComponents, isIncludeSimpleComponents } from '../helper';
import {
dateItemType,
defaultValueComponents,
isIncludeSimpleComponents,
uploadItemType,
} from '../helper';
import { dateUtil } from '@/utils/dateUtil';
import { cloneDeep, has, uniqBy, get, set } from 'lodash-es';
import { error } from '@/utils/log';
import { ComponentProps } from '../types';
interface UseFormActionContext {
emit: EmitType;
@@ -19,7 +25,12 @@ interface UseFormActionContext {
schemaRef: Ref<FormSchema[]>;
handleFormValues: Fn;
}
/**
* @description: Is it upload
*/
export function itemIsUploadComponent(key: keyof ComponentProps) {
return uploadItemType.includes(key);
}
function tryConstructArray(field: string, values: Recordable = {}): any[] | undefined {
const pattern = /^\[(.+)\]$/;
if (pattern.test(field)) {
@@ -123,7 +134,20 @@ export function useFormEvents({
}
}
}
// Adapt upload component
if (itemIsUploadComponent(schema?.component)) {
constructValue = get(value, key);
const fieldValue = constructValue || value;
if (fieldValue) {
if (isArray(fieldValue)) {
unref(formModel)[key] = fieldValue;
} else if (typeof fieldValue == 'string') {
unref(formModel)[key] = [fieldValue];
}
}
validKeys.push(key);
return;
}
// Adapt common component
if (hasKey) {
constructValue = get(value, key);

View File

@@ -1,7 +1,7 @@
import type { Ref } from 'vue';
import { computed, unref } from 'vue';
import type { FormProps, FormSchemaInner as FormSchema } from '../types/form';
import { isNumber } from '@/utils/is';
import { isDef, isNumber } from '@/utils/is';
export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<FormProps>) {
return computed(() => {
@@ -23,11 +23,11 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
};
return { labelCol, wrapperCol };
}
let width = labelWidth || globalLabelWidth;
let width = labelWidth ?? globalLabelWidth;
const col = { ...globalLabelCol, ...labelCol };
const wrapCol = { ...globWrapperCol, ...wrapperCol };
if (width) {
if (isDef(width)) {
width = isNumber(width) ? `${width}px` : width;
}

View File

@@ -54,7 +54,7 @@
justify-content: center;
width: 100%;
height: 100%;
background-color: rgb(240 242 245 / 40%);
background-color: #f0f2f566;
&.absolute {
position: absolute;

View File

@@ -1,4 +1,4 @@
import { VNode, defineComponent, createVNode, render, reactive, h } from 'vue';
import { createVNode, defineComponent, h, reactive, render, VNode } from 'vue';
import type { LoadingProps } from './typing';
import Loading from './Loading.vue';
@@ -41,7 +41,7 @@ export function createLoading(props?: Partial<LoadingProps>, target?: HTMLElemen
target.appendChild(vm.el as HTMLElement);
}
function destory() {
function destroy() {
container && render(null, container);
container = vm = null;
}
@@ -53,7 +53,7 @@ export function createLoading(props?: Partial<LoadingProps>, target?: HTMLElemen
vm,
close,
open,
destory,
destroy,
setTip: (tip: string) => {
data.tip = tip;
},

View File

@@ -1,5 +1,5 @@
import { unref } from 'vue';
import type { Ref } from 'vue';
import { unref } from 'vue';
import { tryOnUnmounted } from '@vueuse/core';
import { createLoading } from './createLoading';
import type { LoadingProps } from './typing';
@@ -47,7 +47,7 @@ export function useLoading(
};
tryOnUnmounted(() => {
instance.destory();
instance.destroy();
});
return [open, close, setTip];

View File

@@ -1,7 +1,7 @@
import type { Options, Props } from './typing';
import ImgPreview from './Functional.vue';
import { isClient } from '@/utils/is';
import { createVNode, render } from 'vue';
import ImgPreview from './Functional.vue';
import type { Options, Props } from './typing';
let instance: ReturnType<typeof createVNode> | null = null;
export function createImgPreview(options: Options) {
@@ -10,8 +10,13 @@ export function createImgPreview(options: Options) {
const container = document.createElement('div');
Object.assign(propsData, { show: true, index: 0, scaleStep: 100 }, options);
instance = createVNode(ImgPreview, propsData);
render(instance, container);
document.body.appendChild(container);
if (instance?.component) {
// 存在实例时更新props
Object.assign(instance.component.props, propsData);
} else {
instance = createVNode(ImgPreview, propsData);
render(instance, container);
document.body.appendChild(container);
}
return instance.component?.exposed;
}

View File

@@ -153,11 +153,11 @@
height: 0;
transition: 0.3s background-color;
border-radius: inherit;
background-color: rgb(144 147 153 / 30%);
background-color: #9093994d;
cursor: pointer;
&:hover {
background-color: rgb(144 147 153 / 50%);
background-color: #90939980;
}
}

View File

@@ -17,11 +17,11 @@
</template>
<script lang="ts" setup>
import { PropType, ref, computed, unref, getCurrentInstance, watch, useSlots } from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { Tooltip } from 'ant-design-vue';
import { computed, getCurrentInstance, PropType, ref, unref, useSlots, watch } from 'vue';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
defineOptions({ name: 'MenuItem' });
@@ -76,7 +76,7 @@
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
opened: false,
parent: instance?.parent,
uidList: uidList,
});

View File

@@ -57,27 +57,27 @@
</template>
<script lang="ts" setup>
import { type TimeoutHandle, type Recordable } from '@vben/types';
import type { CSSProperties, PropType } from 'vue';
import type { SubMenuProvider } from './types';
import {
computed,
unref,
getCurrentInstance,
reactive,
provide,
onBeforeMount,
inject,
} from 'vue';
import { useDesign } from '@/hooks/web/useDesign';
import { propTypes } from '@/utils/propTypes';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
import { CollapseTransition } from '@/components/Transition';
import Icon from '@/components/Icon/Icon.vue';
import { Popover } from 'ant-design-vue';
import { CollapseTransition } from '@/components/Transition';
import { useDesign } from '@/hooks/web/useDesign';
import { isBoolean, isObject } from '@/utils/is';
import { mitt } from '@/utils/mitt';
import { propTypes } from '@/utils/propTypes';
import { type Recordable, type TimeoutHandle } from '@vben/types';
import { Popover } from 'ant-design-vue';
import type { CSSProperties, PropType } from 'vue';
import {
computed,
getCurrentInstance,
inject,
onBeforeMount,
provide,
reactive,
unref,
} from 'vue';
import type { SubMenuProvider } from './types';
import { useMenuItem } from './useMenu';
import { useSimpleRootMenuContext } from './useSimpleMenuContext';
defineOptions({ name: 'SubMenu' });
@@ -184,7 +184,7 @@
if (unref(getAccordion)) {
const { uidList } = getParentList();
rootMenuEmitter.emit('on-update-opened', {
opend: false,
opened: false,
parent: instance?.parent,
uidList: uidList,
});
@@ -267,9 +267,9 @@
return;
}
if (isObject(data) && rootProps.accordion) {
const { opend, parent, uidList } = data as Recordable<any>;
const { opened, parent, uidList } = data as Recordable<any>;
if (parent === instance?.parent) {
state.opened = opend;
state.opened = opened;
} else if (!uidList.includes(instance?.uid)) {
state.opened = false;
}

View File

@@ -1,12 +1,12 @@
import type { InjectionKey, Ref, ComponentInternalInstance } from 'vue';
import type { Emitter } from '@/utils/mitt';
import { createContext, useContext } from '@/hooks/core/useContext';
import type { Emitter } from '@/utils/mitt';
import type { ComponentInternalInstance, InjectionKey, Ref } from 'vue';
export type MenuEmitterEvents = {
'on-update-opened':
| (string | number)[]
| {
opend: boolean;
opened: boolean;
parent?: ComponentInternalInstance | null;
uidList: number[];
};

View File

@@ -17,6 +17,7 @@
import { treeToList } from '@/utils/helper/treeHelper';
import { Spin } from 'ant-design-vue';
import { parseRowKey } from '../../helper';
import { warn } from '@/utils/log';
export default defineComponent({
name: 'EditableCell',
@@ -282,6 +283,7 @@
});
} catch (e) {
result = false;
warn(e);
} finally {
spinning.value = false;
}

View File

@@ -540,13 +540,13 @@
label:
typeof col.title === 'string'
? col.title
: col.customTitle === 'string'
: typeof col.customTitle === 'string'
? col.customTitle
: '',
value:
typeof col.dataIndex === 'string'
? col.dataIndex
: col.title === 'string'
: typeof col.title === 'string'
? col.title
: '',
column: {

View File

@@ -39,7 +39,7 @@
redo: true,
size: true,
setting: true,
settingCache: false,
settingCache: !import.meta.env.DEV,
fullScreen: false,
...props.setting,
};
@@ -55,6 +55,8 @@
</script>
<style lang="less">
.table-settings {
display: flex;
& > * {
margin-right: 12px;
}

View File

@@ -146,6 +146,7 @@ export function useDataSource(
},
{
deep: true,
immediate: true,
},
);

View File

@@ -33,7 +33,7 @@ export function useRowSelection(
// 点击 checkbox/radiobox 触发
// 取出【当前页】所有 keyValues
const currentPageKeys = tableData.value.map((o) => parseRowKeyValue(unref(getRowKey), o));
const currentPageKeys = getCcurrentPageKeys();
// 从【所有分页】已选的 keyValues且属于【当前页】的部分
for (const selectedKey of selectedRowKeysRef.value.filter((k) =>
@@ -110,6 +110,18 @@ export function useRowSelection(
const { rowKey } = unref(propsRef);
return unref(getAutoCreateKey) ? ROW_KEY : rowKey;
});
function getCcurrentPageKeys() {
const { childrenColumnName = 'children' } = unref(propsRef);
const keys: Key[] = [];
const extractKeys = (record: Recordable) => {
keys.push(parseRowKeyValue(unref(getRowKey), record));
if (record[childrenColumnName]?.length) {
record[childrenColumnName].forEach(extractKeys);
}
};
tableData.value.forEach(extractKeys);
return keys;
}
function setSelectedRowKeys(keyValues?: Key[]) {
selectedRowKeysRef.value = keyValues || [];

View File

@@ -59,6 +59,7 @@
import UploadPreviewModal from './components/UploadPreviewModal.vue';
import { BaseFileItem } from './types/typing';
import { buildUUID } from '@/utils/uuid';
defineOptions({ name: 'BasicUpload' });
const props = defineProps(uploadContainerProps);
@@ -85,7 +86,10 @@
const value = { ...attrs, ...props };
return omit(value, 'onChange');
});
function getValue(valueKey="url") {
const isFirstRender = ref<boolean>(true);
function getValue(valueKey = 'url') {
const list = (fileList.value || []).map((item: any) => {
return item[valueKey];
});
@@ -110,7 +114,7 @@
} else if (typeof v == 'string') {
values.push(v);
}
fileList.value = values.map((item,i) => {
fileList.value = values.map((item) => {
if (item && isString(item)) {
return {
uid: buildUUID(),
@@ -124,13 +128,19 @@
}) as any;
}
emit('update:value', values);
emit('change', values);
if (!isFirstRender.value) {
emit('change', values);
isFirstRender.value = false;
}
},
{
immediate: true,
deep: true,
},
{ immediate: true },
);
// 上传modal保存操作
function handleChange(urls: string[],valueKey:string) {
function handleChange(urls: string[], valueKey: string) {
fileList.value = [...unref(fileList), ...(genFileListByUrls(urls) || [])];
const values = getValue(valueKey);
emit('update:value', values);
@@ -138,7 +148,7 @@
}
// 预览modal保存操作
function handlePreviewChange(fileItems: string[],valueKey:string) {
function handlePreviewChange(fileItems: string[], valueKey: string) {
fileList.value = [...(fileItems || [])];
const values = getValue(valueKey);
emit('update:value', values);

View File

@@ -63,6 +63,7 @@
const fileList = ref<UploadProps['fileList']>([]);
const isLtMsg = ref<boolean>(true);
const isActMsg = ref<boolean>(true);
const isFirstRender = ref<boolean>(true);
watch(
() => props.value,
@@ -94,7 +95,10 @@
}) as UploadProps['fileList'];
}
emit('update:value', value);
emit('change', value);
if (!isFirstRender.value) {
emit('change', value);
isFirstRender.value = false;
}
},
{
immediate: true,

View File

@@ -57,7 +57,7 @@
import { useMessage } from '@/hooks/web/useMessage';
// types
import { FileItem, UploadResultStatus } from '../types/typing';
import { basicProps } from '../props';
import { handleFnKey, basicProps } from '../props';
import { createTableColumns, createActionColumn } from './data';
// utils
import { checkImgType, getBase64WithFile } from '../helper';
@@ -161,13 +161,13 @@
}
// 删除
function handleRemove(record: FileItem) {
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
index !== -1 && fileListRef.value.splice(index, 1);
isUploadingRef.value = fileListRef.value.some(
(item) => item.status === UploadResultStatus.UPLOADING,
);
emit('delete', record);
function handleRemove(obj: Record<handleFnKey, any>) {
let { record = {}, uidKey = 'uid' } = obj;
const index = fileListRef.value.findIndex((item) => item[uidKey] === record[uidKey]);
if (index !== -1) {
const removed = fileListRef.value.splice(index, 1);
emit('delete', removed[0][uidKey]);
}
}
async function uploadApiByItem(item: FileItem) {

View File

@@ -23,6 +23,7 @@
import { BasicColumn } from '@/components/Table';
import { useMessage } from '@/hooks/web/useMessage';
import { buildUUID } from '@/utils/uuid';
const { createMessage } = useMessage();
const props = defineProps(previewProps);
@@ -97,7 +98,6 @@
return createMessage.warning(t('component.upload.maxNumber', [maxNumber]));
}
record[uidKey] = record[uidKey] ?? buildUUID();
record[valueKey] = record[valueKey];
fileListRef.value = [...fileListRef.value, record];
emit('list-change', fileListRef.value, valueKey);
}

View File

@@ -14,7 +14,7 @@ type SortableOptions = Merge<
// ...可扩展
}
>;
export type handleFnKey = "record" | "valueKey" | "uidKey"
export type handleFnKey = 'record' | 'valueKey' | 'uidKey';
export type previewColumnsFnType = {
handleRemove: (record: Record<handleFnKey, any>) => any;
handleAdd: (record: Record<handleFnKey, any>) => any;

View File

@@ -1,6 +1,6 @@
import { withInstall } from '@/utils';
import vxeBasicTable from './src/VxeBasicTable';
import { VXETable } from 'vxe-table';
import { VxeUI } from 'vxe-table';
import VXETablePluginAntd from './src/components';
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx';
import ExcelJS from 'exceljs';
@@ -10,4 +10,4 @@ export const VxeBasicTable = withInstall(vxeBasicTable);
export * from 'vxe-table';
export * from './src/types';
VXETable.use(VXETablePluginAntd).use(VXETablePluginExportXLSX, { ExcelJS });
VxeUI.use(VXETablePluginAntd).use(VXETablePluginExportXLSX, { ExcelJS });

View File

@@ -1,22 +1,25 @@
import { defineComponent, computed, ref } from 'vue';
import { defineComponent, computed, ref, watch } from 'vue';
import { BasicTableProps } from './types';
import { basicProps } from './props';
import { ignorePropKeys } from './const';
import { basicEmits } from './emits';
import XEUtils from 'xe-utils';
import type {
import {
VxeGridInstance,
VxeGridEventProps,
GridMethods,
TableMethods,
TableEditMethods,
TableValidatorMethods,
VxeUI,
VxeGlobalThemeName,
VxeGrid,
} from 'vxe-table';
import { Grid as VxeGrid } from 'vxe-table';
import { extendSlots } from '@/utils/helper/tsxHelper';
import { gridComponentMethodKeys } from './methods';
import { omit } from 'lodash-es';
import { useRootSetting } from '@/hooks/setting/useRootSetting';
export default defineComponent({
name: 'VxeBasicTable',
@@ -25,7 +28,14 @@ export default defineComponent({
setup(props, { emit, attrs }) {
const tableElRef = ref<VxeGridInstance>();
const emitEvents: VxeGridEventProps = {};
const { getDarkMode } = useRootSetting();
watch(
() => getDarkMode.value,
() => {
VxeUI.setTheme(getDarkMode.value as VxeGlobalThemeName);
},
{ immediate: true },
);
const extendTableMethods = (methodKeys) => {
const funcs: any = {};
methodKeys.forEach((name) => {

View File

@@ -1,20 +1,21 @@
import XEUtils from 'xe-utils';
import { createDefaultRender, createEditRender, createFormItemRender } from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender({}, (_, params) => {
renderTableDefault: createDefaultRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderEdit: createEditRender({}, (_, params) => {
renderTableEdit: createEditRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderItemContent: createFormItemRender({}, (_, params) => {
renderFormItemContent: createFormItemRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,20 +1,21 @@
import XEUtils from 'xe-utils';
import { createDefaultRender, createEditRender, createFormItemRender } from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender({}, (_, params) => {
renderTableDefault: createDefaultRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderEdit: createEditRender({}, (_, params) => {
renderTableEdit: createEditRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
renderItemContent: createFormItemRender({}, (_, params) => {
renderFormItemContent: createFormItemRender({}, (_, params) => {
return {
params: XEUtils.get(params, 'row'),
};
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,8 +1,9 @@
import { h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
VxeGlobalRendererOptions,
} from 'vxe-table';
import XEUtils from 'xe-utils';
import { cellText, createEvents, createProps, getComponent } from './common';
@@ -11,8 +12,8 @@ const COMPONENT_NAME = 'AButton';
export function createEditRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
@@ -29,8 +30,8 @@ export function createEditRender() {
export function createDefaultRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
@@ -50,7 +51,10 @@ export function createDefaultRender() {
}
export function createFormItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const { attrs, content } = renderOpts;
const { property, $form, data } = params;
const props = createProps(renderOpts, null);
@@ -113,8 +117,8 @@ function createToolbarButtonRender() {
}
export default {
renderEdit: createEditRender(),
renderDefault: createDefaultRender(),
renderItemContent: createFormItemRender(),
renderTableEdit: createEditRender(),
renderTableDefault: createDefaultRender(),
renderFormItemContent: createFormItemRender(),
renderToolbarButton: createToolbarButtonRender(),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,20 +1,21 @@
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
VxeGlobalRendererOptions,
} from 'vxe-table';
import { createDefaultRender, createEditRender, createFormItemRender } from './AButton';
function createEditButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const buttonEditRender = createEditRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: VxeGlobalRendererHandles.RenderEditOptions) =>
(childRenderOpts: VxeGlobalRendererHandles.RenderTableEditOptions) =>
buttonEditRender(childRenderOpts, params)[0],
);
}
@@ -25,7 +26,7 @@ function createEditButtonRender() {
function createDefaultButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) {
const buttonDefaultRender = createDefaultRender();
const { children } = renderOpts;
@@ -40,12 +41,16 @@ function createDefaultButtonRender() {
}
function createButtonItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const buttonItemRender = createFormItemRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: FormItemRenderOptions) => buttonItemRender(childRenderOpts, params)[0],
(childRenderOpts: VxeFormItemPropTypes.ItemRender) =>
buttonItemRender(childRenderOpts, params)[0],
);
}
return [];
@@ -53,7 +58,7 @@ function createButtonItemRender() {
}
export default {
renderEdit: createEditButtonRender(),
renderDefault: createDefaultButtonRender(),
renderItemContent: createButtonItemRender(),
};
renderTableEdit: createEditButtonRender(),
renderTableDefault: createDefaultButtonRender(),
renderFormItemContent: createButtonItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
@@ -21,7 +21,7 @@ function matchCascaderData(index: number, list: any[], values: any[], labels: an
function getCascaderCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
@@ -35,8 +35,8 @@ function getCascaderCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getCascaderCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getCascaderCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getCascaderCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getCascaderCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,6 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
@@ -9,7 +9,9 @@ import {
export function getDatePickerCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
defaultFormat: string,
) {
const { props = {} } = renderOpts;
@@ -22,12 +24,12 @@ export function getDatePickerCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,9 +1,9 @@
import { h } from 'vue';
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import { getComponent } from './common';
function createEmptyRender() {
return function (renderOpts: VxeGlobalRendererHandles.RenderEmptyOptions) {
return function (renderOpts: VxeGlobalRendererHandles.RenderTableEmptyOptions) {
const { name, attrs, props } = renderOpts;
const Component = getComponent(name);
@@ -23,5 +23,5 @@ function createEmptyRender() {
}
export default {
renderEmpty: createEmptyRender(),
};
renderTableEmptyView: createEmptyRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createFilterRender,
@@ -7,10 +8,10 @@ import {
} from './common';
export default {
autofocus: 'input.ant-input-number-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableAutoFocus: 'input.ant-input-number-input',
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -8,10 +9,10 @@ import {
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
renderToolbarTool: createToolbarToolRender(),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createCellRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,6 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import { VxeColumnPropTypes, VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
@@ -9,7 +9,9 @@ import {
function getRangePickerCellValue(
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
@@ -23,8 +25,8 @@ function getRangePickerCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getRangePickerCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getRangePickerCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getRangePickerCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getRangePickerCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import {
createEditRender,
createDefaultRender,
@@ -7,9 +8,9 @@ import {
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,5 +1,5 @@
import { ComponentOptions, h, resolveComponent } from 'vue';
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import { VxeColumnPropTypes, VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
cellText,
@@ -32,7 +32,7 @@ function renderOptions(options: any[], optionProps: VxeGlobalRendererHandles.Ren
function createEditRender() {
return function (
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderEditParams,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const { row, column, $table } = params;
@@ -100,8 +100,8 @@ function createEditRender() {
}
function getSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const {
options = [],
@@ -144,7 +144,7 @@ function getSelectCellValue(
function createFilterRender() {
return function (
renderOpts: VxeColumnPropTypes.FilterRender,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const groupOptions = optionGroupProps.options || 'options';
@@ -249,10 +249,10 @@ function createFilterRender() {
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getSelectCellValue),
renderFilter: createFilterRender(),
defaultFilterMethod(params) {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getSelectCellValue),
renderTableFilter: createFilterRender(),
tableFilterDefaultMethod(params) {
const { option, row, column } = params;
const { data } = option;
const { field, filterRender: renderOpts } = column;
@@ -266,6 +266,6 @@ export default {
}
return cellValue == data;
},
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getSelectCellValue),
};
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getSelectCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -9,11 +9,12 @@ import {
createFormItemRender,
getComponent,
} from './common';
import { VxeGlobalRendererOptions } from 'vxe-table';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter(renderOpts, params) {
renderTableDefault: createDefaultRender(),
renderTableEdit: createEditRender(),
renderTableFilter(renderOpts, params) {
const { column } = params;
const { name, attrs } = renderOpts;
const Component = getComponent(name);
@@ -48,6 +49,6 @@ export default {
),
];
},
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};
tableFilterDefaultMethod: createDefaultFilterRender(),
renderFormItemContent: createFormItemRender(),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,4 +1,4 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import { VxeGlobalRendererHandles, VxeGlobalRendererOptions } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
@@ -10,7 +10,9 @@ import {
function getTreeSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
params:
| VxeGlobalRendererHandles.RenderTableCellParams
| VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { treeData, treeCheckable } = props;
@@ -28,8 +30,8 @@ function getTreeSelectCellValue(
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getTreeSelectCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getTreeSelectCellValue),
};
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getTreeSelectCellValue),
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getTreeSelectCellValue),
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,3 +1,4 @@
import { VxeGlobalRendererOptions } from 'vxe-table';
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
@@ -7,12 +8,12 @@ import {
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
renderTableEdit: createEditRender(),
renderTableCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
renderFormItemContent: createFormItemRender(),
tableExportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY'];
}),
};
} as VxeGlobalRendererOptions;

View File

@@ -1,7 +1,7 @@
import { ComponentOptions, h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeFormItemPropTypes,
VxeGlobalRendererHandles,
} from 'vxe-table';
import XEUtils from 'xe-utils';
@@ -160,12 +160,12 @@ export function createDefaultRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
params: VxeGlobalRendererHandles.RenderTableDefaultParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
@@ -195,13 +195,13 @@ export function createDefaultRender(
export function createEditRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
renderOpts: VxeGlobalRendererHandles.RenderTableEditOptions,
params: VxeGlobalRendererHandles.RenderTableEditParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
@@ -232,12 +232,12 @@ export function createFilterRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
params: VxeGlobalRendererHandles.RenderTableFilterParams,
) {
const { column } = params;
const { name, attrs } = renderOpts;
@@ -287,7 +287,7 @@ export function createFilterRender(
*/
export function createDefaultFilterRender() {
return function (params: VxeGlobalRendererHandles.FilterMethodParams) {
return function (params: VxeGlobalRendererHandles.TableFilterMethodParams) {
const { option, row, column } = params;
const { data } = option;
const cellValue = XEUtils.get(row, column.field as string);
@@ -301,11 +301,14 @@ export function createDefaultFilterRender() {
export function createFormItemRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: FormItemRenderOptions,
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) => Record<string, any>,
) {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
return function (
renderOpts: VxeFormItemPropTypes.ItemRender,
params: FormItemContentRenderParams,
) {
const args = (callBack && callBack(renderOpts, params)) ?? {};
const { data, property, $form } = params;
const { name } = renderOpts;
@@ -344,13 +347,13 @@ export function createFormItemRender(
export function createCellRender(
getSelectCellValue: Function,
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) => Array<any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
renderOpts: VxeGlobalRendererHandles.RenderTableCellOptions,
params: VxeGlobalRendererHandles.RenderTableCellParams,
) {
const args = (callBack && callBack(renderOpts, params)) ?? [];
const cellLabel = getSelectCellValue && getSelectCellValue(renderOpts, params, ...args);

View File

@@ -1,4 +1,4 @@
import { VXETableCore, VxeGlobalInterceptorHandles } from 'vxe-table';
import { VxeUIExport, VxeGlobalInterceptorHandles } from 'vxe-table';
import AAutoComplete from './AAutoComplete';
import AInput from './AInput';
import AInputNumber from './AInputNumber';
@@ -50,7 +50,7 @@ function getEventTargetNode(evnt: any, container: HTMLElement, className: string
function handleClearEvent(
params:
| VxeGlobalInterceptorHandles.InterceptorClearFilterParams
| VxeGlobalInterceptorHandles.InterceptorClearActivedParams
| VxeGlobalInterceptorHandles.InterceptorClearEditParams
| VxeGlobalInterceptorHandles.InterceptorClearAreasParams,
) {
const { $event } = params;
@@ -73,10 +73,10 @@ function handleClearEvent(
* 基于 vxe-table 表格的适配插件,用于兼容 ant-design-vue 组件库
*/
export const VXETablePluginAntd = {
install(vxetablecore: VXETableCore) {
install(vxetablecore: VxeUIExport) {
const { interceptor, renderer } = vxetablecore;
renderer.mixin({
const customRenderComponents = {
AAutoComplete,
AInput,
AInputNumber,
@@ -99,16 +99,21 @@ export const VXETablePluginAntd = {
AEmpty,
AInputSearch,
AYearPicker,
};
Object.keys(customRenderComponents).forEach((name) => {
if (renderer.get(name)) return;
renderer.add(name, customRenderComponents[name]);
});
interceptor.add('event.clearFilter', handleClearEvent);
interceptor.add('event.clearActived', handleClearEvent);
interceptor.add('event.clearEdit', handleClearEvent);
interceptor.add('event.clearAreas', handleClearEvent);
},
};
if (typeof window !== 'undefined' && window.VXETable && window.VXETable.use) {
window.VXETable.use(VXETablePluginAntd);
if (typeof window !== 'undefined' && window.VxeUI && window.VxeUI.use) {
window.VxeUI.use(VXETablePluginAntd);
}
export default VXETablePluginAntd;

View File

@@ -2,4 +2,5 @@
@import './variable';
@import './toolbar';
@import './component';
@import 'vxe-table/styles/index';
@import 'vxe-table/styles/all';
@import 'vxe-pc-ui/styles/all';

View File

@@ -1,4 +1,4 @@
import { VXETable } from '..';
import { VxeUI } from '..';
import componentSetting from '@/settings/componentSetting';
VXETable.setup(componentSetting.vxeTable);
VxeUI.setConfig(componentSetting.vxeTable);

View File

@@ -2,7 +2,8 @@ import type { App } from 'vue';
import { Button } from './Button';
import { Input, Layout } from 'ant-design-vue';
import VXETable from 'vxe-table';
import VXEUI from 'vxe-pc-ui';
export function registerGlobComp(app: App) {
app.use(Input).use(Button).use(Layout).use(VXETable);
app.use(Input).use(Button).use(Layout).use(VXETable).use(VXEUI);
}

View File

@@ -17,15 +17,15 @@
// }
::-webkit-scrollbar-track {
background-color: rgb(0 0 0 / 5%);
background-color: #0000000d;
}
::-webkit-scrollbar-thumb {
// background-color: rgba(144, 147, 153, 0.3);
border-radius: 2px;
// background: rgba(0, 0, 0, 0.6);
background-color: rgb(144 147 153 / 30%);
box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
background-color: #9093994d;
box-shadow: inset 0 0 6px #00000033;
}
::-webkit-scrollbar-thumb:hover {

View File

@@ -1,5 +1,5 @@
import { createLoading } from '@/components/Loading';
import type { Directive, App } from 'vue';
import type { App, Directive } from 'vue';
const loadingDirective: Directive = {
mounted(el, binding) {
@@ -28,7 +28,7 @@ const loadingDirective: Directive = {
}
},
unmounted(el) {
el?.instance?.destory();
el?.instance?.destroy();
},
};

View File

@@ -1,8 +1,8 @@
import type { EChartsOption } from 'echarts';
import type { Ref } from 'vue';
import { computed, nextTick, ref, unref, watch } from 'vue';
import { useTimeoutFn } from '@vben/hooks';
import { tryOnUnmounted, useDebounceFn } from '@vueuse/core';
import { unref, nextTick, watch, computed, ref } from 'vue';
import { useEventListener } from '@/hooks/event/useEventListener';
import { useBreakpoint } from '@/hooks/event/useBreakpoint';
import echarts from '@/utils/lib/echarts';
@@ -49,6 +49,10 @@ export function useECharts(
listener: resizeFn,
});
removeResizeFn = removeEvent;
const resizeObserver = new ResizeObserver(resizeFn);
resizeObserver.observe(el);
const { widthRef, screenEnum } = useBreakpoint();
if (unref(widthRef) <= screenEnum.MD || el.offsetHeight === 0) {
useTimeoutFn(() => {
@@ -64,7 +68,7 @@ export function useECharts(
useTimeoutFn(() => {
setOptions(unref(getOptions));
resolve(null);
}, 30);
}, 50);
}
nextTick(() => {
useTimeoutFn(() => {

View File

@@ -0,0 +1,33 @@
<script setup lang="ts">
import { h } from 'vue';
import { Modal } from 'ant-design-vue';
import { useI18n } from '@/hooks/web/useI18n';
const { t } = useI18n();
const localKey = 'vben-v5.0.0-upgrade-prompt';
if (!localStorage.getItem(localKey)) {
Modal.confirm({
title: t('layout.header.upgrade-prompt.title'),
content: h('div', {}, [h('p', t('layout.header.upgrade-prompt.content'))]),
onOk() {
handleClick();
},
okText: t('layout.header.upgrade-prompt.ok-text'),
cancelText: t('common.closeText'),
});
}
localStorage.setItem(localKey, String(Date.now()));
function handleClick() {
window.open('https://www.vben.pro', '_blank');
}
</script>
<template>
<div>
<a-button type="primary" @click="handleClick">{{
t('layout.header.upgrade-prompt.ok-text')
}}</a-button>
</div>
</template>

View File

@@ -33,6 +33,8 @@
<!-- action -->
<div :class="`${prefixCls}-action`">
<UpgradePrompt class="mr-2" />
<AppSearch v-if="getShowSearch" :class="`${prefixCls}-action__item `" />
<ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />
@@ -70,6 +72,7 @@
import { createAsyncComponent } from '@/utils/factory/createAsyncComponent';
import { propTypes } from '@/utils/propTypes';
import UpgradePrompt from './components/UpgradePrompt.vue';
import LayoutMenu from '../menu/index.vue';
import LayoutTrigger from '../trigger/index.vue';
import { ErrorAction, FullScreen, LayoutBreadcrumb, Notify, UserDropDown } from './components';

View File

@@ -15,7 +15,12 @@
"lockScreenPassword": "Lock screen password",
"lockScreen": "Lock screen",
"lockScreenBtn": "Locking",
"home": "Home"
"home": "Home",
"upgrade-prompt": {
"title": "New version released",
"content": "Vben Admin v5.0.0 preview version has been released",
"ok-text": "Go to new version"
}
},
"multipleTab": {
"reload": "Refresh current",

View File

@@ -177,4 +177,4 @@
"resizeParentHeightTable": "resizeParentHeightTable",
"vxeTable": "VxeTable"
}
}
}

View File

@@ -15,7 +15,12 @@
"lockScreenPassword": "锁屏密码",
"lockScreen": "锁定屏幕",
"lockScreenBtn": "锁定",
"home": "首页"
"home": "首页",
"upgrade-prompt": {
"title": "新版本发布",
"content": "Vben Admin v5.0.0 预览版本已发布",
"ok-text": "前往体验新版"
}
},
"multipleTab": {
"reload": "重新加载",

View File

@@ -176,4 +176,4 @@
"resizeParentHeightTable": "继承父元素高度",
"vxeTable": "VxeTable"
}
}
}

View File

@@ -24,7 +24,7 @@ import { Persistent } from '@/utils/cache/persistent';
export function initAppConfigStore() {
const localeStore = useLocaleStore();
const appStore = useAppStore();
let projCfg: ProjectConfig = Persistent.getLocal(PROJ_CFG_KEY) as ProjectConfig;
let projCfg = Persistent.getLocal<ProjectConfig>(PROJ_CFG_KEY);
projCfg = deepMerge(projectSetting, projCfg || {});
const darkMode = appStore.getDarkMode;
const {

View File

@@ -61,10 +61,10 @@ export function createPermissionGuard(router: Router) {
path: LOGIN_PATH,
replace: true,
};
if (to.path) {
if (to.fullPath) {
redirectData.query = {
...redirectData.query,
redirect: to.path,
redirect: to.fullPath,
};
}
next(redirectData);

View File

@@ -1,5 +1,5 @@
import { AppRouteModule } from '@/router/types';
import type { MenuModule, Menu, AppRouteRecordRaw } from '@/router/types';
import type { Menu, AppRouteRecordRaw } from '@/router/types';
import { findPath, treeMap } from '@/utils/helper/treeHelper';
import { cloneDeep } from 'lodash-es';
import { isHttpUrl } from '@/utils/is';
@@ -30,13 +30,12 @@ function joinParentPath(menus: Menu[], parentPath = '') {
}
}
}
// Parsing the menu module
export function transformMenuModule(menuModule: MenuModule): Menu {
const menuList = [menuModule];
joinParentPath(menuList);
return menuList[0];
// 菜单路径处理
export function transformMenuModules(routeModList: Menu[]) {
const cloneMenuModules = cloneDeep(routeModList);
// 路径处理
joinParentPath(cloneMenuModules);
return cloneMenuModules;
}
// 将路由转换成菜单

View File

@@ -3,7 +3,7 @@ import type { RouteRecordNormalized } from 'vue-router';
import { useAppStoreWithOut } from '@/store/modules/app';
import { usePermissionStore } from '@/store/modules/permission';
import { transformMenuModule, getAllParentPath } from '@/router/helper/menuHelper';
import { getAllParentPath } from '@/router/helper/menuHelper';
import { filter } from '@/utils/helper/treeHelper';
import { isHttpUrl } from '@/utils/is';
import { router } from '@/router';
@@ -12,7 +12,7 @@ import { pathToRegexp } from 'path-to-regexp';
const modules = import.meta.glob('../routes/modules/**/*.ts', { eager: true });
const menuModules: MenuModule[] = [];
export const menuModules: MenuModule[] = [];
Object.keys(modules).forEach((key) => {
const mod = (modules as Recordable)[key].default || {};
@@ -40,17 +40,6 @@ const isRoleMode = () => {
return getPermissionMode() === PermissionModeEnum.ROLE;
};
const staticMenus: Menu[] = [];
(() => {
menuModules.sort((a, b) => {
return (a.orderNo || 0) - (b.orderNo || 0);
});
for (const menu of menuModules) {
staticMenus.push(transformMenuModule(menu));
}
})();
async function getAsyncMenus() {
const permissionStore = usePermissionStore();
//递归过滤所有隐藏的菜单
@@ -69,7 +58,7 @@ async function getAsyncMenus() {
if (isRouteMappingMode()) {
return menuFilter(permissionStore.getFrontMenuList);
}
return staticMenus;
return permissionStore.getStaticMenuList;
}
export const getMenus = async (): Promise<Menu[]> => {

View File

@@ -16,6 +16,7 @@ import { Persistent } from '@/utils/cache/persistent';
import { darkMode } from '@/settings/designSetting';
import { resetRouter } from '@/router';
import { deepMerge } from '@/utils';
import setting from '@/settings/projectSetting';
interface AppState {
darkMode?: ThemeEnum;
@@ -40,7 +41,12 @@ export const useAppStore = defineStore({
return state.pageLoading;
},
getDarkMode(state): 'light' | 'dark' | string {
return state.darkMode || localStorage.getItem(APP_DARK_MODE_KEY) || darkMode;
return (
state.darkMode ||
localStorage.getItem(APP_DARK_MODE_KEY) ||
setting.menuSetting.theme ||
darkMode
);
},
getBeforeMiniInfo(state): BeforeMiniState {

View File

@@ -134,7 +134,9 @@ export const useMultipleTabStore = defineStore({
// Existing pages, do not add tabs repeatedly
const tabHasExits = this.tabList.some((tab, index) => {
updateIndex = index;
return decodeURIComponent(tab.fullPath || tab.path) === decodeURIComponent(fullPath || path);
return (
decodeURIComponent(tab.fullPath || tab.path) === decodeURIComponent(fullPath || path)
);
});
// If the tab already exists, perform the update operation
@@ -158,7 +160,7 @@ export const useMultipleTabStore = defineStore({
const realPath = meta?.realPath ?? '';
// 获取到已经打开的动态路由数, 判断是否大于某一个值
if (
this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= dynamicLevel
this.tabList.filter((e) => (e.meta?.realPath ?? '') === realPath).length >= dynamicLevel
) {
// 关闭第一个
const index = this.tabList.findIndex((item) => item.meta.realPath === realPath);

View File

@@ -7,13 +7,14 @@ import { useUserStore } from './user';
import { useAppStoreWithOut } from './app';
import { toRaw } from 'vue';
import { transformObjToRoute, flatMultiLevelRoutes } from '@/router/helper/routeHelper';
import { transformRouteToMenu } from '@/router/helper/menuHelper';
import { transformRouteToMenu, transformMenuModules } from '@/router/helper/menuHelper';
import projectSetting from '@/settings/projectSetting';
import { PermissionModeEnum } from '@/enums/appEnum';
import { asyncRoutes } from '@/router/routes';
import { menuModules } from '@/router/menus';
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic';
import { filter } from '@/utils/helper/treeHelper';
@@ -39,6 +40,7 @@ interface PermissionState {
backMenuList: Menu[];
// 菜单列表
frontMenuList: Menu[];
staticMenuList: Menu[];
}
export const usePermissionStore = defineStore({
@@ -58,6 +60,7 @@ export const usePermissionStore = defineStore({
// menu List
// 菜单列表
frontMenuList: [],
staticMenuList: [],
}),
getters: {
getPermCodeList(state): string[] | number[] {
@@ -69,6 +72,9 @@ export const usePermissionStore = defineStore({
getFrontMenuList(state): Menu[] {
return state.frontMenuList;
},
getStaticMenuList(state): Menu[] {
return state.staticMenuList;
},
getLastBuildMenuTime(state): number {
return state.lastBuildMenuTime;
},
@@ -90,6 +96,10 @@ export const usePermissionStore = defineStore({
this.frontMenuList = list;
},
setStaticMenuList(list: Menu[]) {
this.staticMenuList = list;
},
setLastBuildMenuTime() {
this.lastBuildMenuTime = new Date().getTime();
},
@@ -171,6 +181,12 @@ export const usePermissionStore = defineStore({
switch (permissionMode) {
// 角色权限
case PermissionModeEnum.ROLE:
const staticMenuList = transformMenuModules(menuModules);
staticMenuList.sort((a, b) => {
return (a.orderNo || 0) - (b.orderNo || 0);
});
// 设置菜单列表
this.setStaticMenuList(staticMenuList);
// 对非一级路由进行过滤
routes = filter(asyncRoutes, routeFilter);
// 对一级路由根据角色权限过滤

View File

@@ -16,8 +16,6 @@ export class AxiosRetry {
return Promise.reject(error);
}
config.__retryCount += 1;
//请求返回后config的header不正确造成重试请求失败,删除返回headers采用默认headers
delete config.headers;
return this.delay(waitTime).then(() => axiosInstance(config));
}

View File

@@ -20,14 +20,19 @@ export function getPopupContainer(node?: HTMLElement): HTMLElement {
* @param obj
* @returns {string}
* eg:
* let obj = {a: '3', b: '4'}
* let obj = {a: '3', b: '4', c: ['1','2']}
* setObjToUrlParams('www.baidu.com', obj)
* ==>www.baidu.com?a=3&b=4
* ==>www.baidu.com?a=3&b=4&c=1,2
*/
export function setObjToUrlParams(baseUrl: string, obj: any): string {
let parameters = '';
for (const key in obj) {
parameters += key + '=' + encodeURIComponent(obj[key]) + '&';
const value = obj[key];
if (Array.isArray(value)) {
parameters += `${key}=${encodeURIComponent(value.join(','))}&`;
} else {
parameters += `${key}=${encodeURIComponent(value)}&`;
}
}
parameters = parameters.replace(/&$/, '');
return /\?$/.test(baseUrl) ? baseUrl + parameters : baseUrl.replace(/\/?$/, '?') + parameters;

View File

@@ -1,49 +1,77 @@
<template>
<PageWrapper title="截图示例">
<Row :gutter="24">
<Col :span="3">
<Card title="截图">
<a-button type="primary" @click="screenShot">点击截图</a-button>
<div class="mt-8" v-show="open">
<a-button type="primary" @click="Dele">点击删除</a-button>
</div>
</Card>
</Col>
<Col :span="21">
<Card title="截图内容" v-show="open">
<div ref="picture"></div>
</Card>
</Col>
</Row>
<CollapseContainer title="截图操作">
<a-button type="primary" class="mr-2" @click="handleScreenshot">截取当前body</a-button>
<a-button type="primary" class="mr-2" :disabled="!showPicture" @click="handleDelScreenshot"
>删除截图</a-button
>
<a-button type="primary" class="mr-2" :disabled="!showPicture" @click="handlePrintScreenshot"
>打印截图</a-button
>
<a-button
type="primary"
class="mr-2"
:disabled="!showPicture"
@click="handleDownloadScreenshot"
>下载截图</a-button
>
</CollapseContainer>
<Card title="截图内容" class="mt-4">
<div ref="pictureRef" v-show="showPicture"></div>
</Card>
</PageWrapper>
</template>
<script lang="ts" setup>
import { PageWrapper } from '@/components/Page';
import html2canvas from 'html2canvas';
import { ref } from 'vue';
import { Card, Col, Row } from 'ant-design-vue';
import { Card } from 'ant-design-vue';
import { CollapseContainer } from '@/components/Container';
import printJS from 'print-js';
import { downloadByBase64 } from '@/utils/file/download';
const picture = ref();
const open = ref(false);
function screenShot() {
if (open.value) {
return;
}
const pictureRef = ref();
const showPicture = ref<boolean>(false);
const canvasUrl = ref<string>('');
function handleScreenshot() {
if (showPicture.value) return;
html2canvas(document.body, {
backgroundColor: '#ffffff',
allowTaint: true, //开启跨域
useCORS: true,
scrollY: 0,
scrollX: 0,
}).then(function (canvas) {
canvas.style.width = '100%';
canvas.style.height = '100%';
picture.value.appendChild(canvas);
open.value = true;
})
.then(function (canvas) {
canvas.style.width = '100%';
canvas.style.height = '100%';
pictureRef.value.appendChild(canvas);
showPicture.value = true;
canvasUrl.value = canvas.toDataURL();
})
.catch((err) => {
console.log('绘制失败', err);
});
}
function handleDelScreenshot() {
pictureRef.value.innerHTML = '';
canvasUrl.value = '';
showPicture.value = false;
}
function handlePrintScreenshot() {
if (!canvasUrl.value) return;
printJS({
printable: canvasUrl.value,
type: 'image',
base64: true,
});
}
function Dele() {
picture.value.innerHTML = '';
open.value = false;
function handleDownloadScreenshot() {
downloadByBase64(canvasUrl.value, 'screen_shot.png');
}
</script>

View File

@@ -18,8 +18,8 @@
import { useMessage } from '@/hooks/web/useMessage';
import { PageWrapper } from '@/components/Page';
import { isAccountExist } from '@/api/demo/system';
import dayjs from "dayjs"
import dayjs from 'dayjs';
const schemas: FormSchema[] = [
{
field: 'field1',
@@ -236,7 +236,7 @@
field5: ['1'],
field7: '1',
field33: '2020-12-12',
field3: dayjs('2020-12-12',"YYYY-MM-DD"),
field3: dayjs('2020-12-12', 'YYYY-MM-DD'),
});
}

View File

@@ -57,8 +57,8 @@
</template>
<script lang="ts" setup>
import { type Recordable } from '@vben/types';
import { computed, unref, ref } from 'vue';
import { BasicForm, ApiSelect, FormSchema } from '@/components/Form';
import { computed, ref, unref } from 'vue';
import { ApiSelect, BasicForm, FormSchema } from '@/components/Form';
import { CollapseContainer } from '@/components/Container';
import { useMessage } from '@/hooks/web/useMessage';
import { PageWrapper } from '@/components/Page';
@@ -472,7 +472,7 @@
},
},
{
field: 'field32',
field: 'field32-1',
label: '下拉远程搜索',
helpMessage: ['ApiSelect组件', '将关键词发送到接口进行远程搜索'],
required: true,
@@ -482,6 +482,35 @@
},
defaultValue: '0',
},
{
field: 'field32-2',
label: '下拉远程搜索',
component: 'ApiSelect',
helpMessage: ['ApiSelect组件', '将关键词发送到接口进行远程搜索'],
componentProps: {
api: optionsListApi,
showSearch: true,
apiSearch: {
show: true,
searchName: 'name',
},
resultField: 'list',
labelField: 'name',
valueField: 'id',
immediate: true,
onChange: (e, v) => {
console.log('ApiSelect====>:', e, v);
},
onOptionsChange: (options) => {
console.log('get options', options.length, options);
},
},
required: true,
colProps: {
span: 8,
},
defaultValue: '0',
},
{
field: 'field33',
component: 'ApiTreeSelect',