Browse Source

Merge pull request #768 from colinin/upt-7.0.1

Update front-end components
pull/786/head
yx lin 3 years ago
committed by GitHub
parent
commit
cfa769407d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      apps/vue/build/vite/plugin/styleImport.ts
  2. 9
      apps/vue/package.json
  3. 3
      apps/vue/src/components/Cropper/src/CopperModal.vue
  4. 2
      apps/vue/src/components/Dropdown/src/Dropdown.vue
  5. 7
      apps/vue/src/components/Form/src/BasicForm.vue
  6. 2
      apps/vue/src/components/Form/src/components/ApiCascader.vue
  7. 12
      apps/vue/src/components/Form/src/components/ApiRadioGroup.vue
  8. 4
      apps/vue/src/components/Form/src/components/FormItem.vue
  9. 13
      apps/vue/src/components/Form/src/components/RadioButtonGroup.vue
  10. 2
      apps/vue/src/components/Form/src/hooks/useForm.ts
  11. 48
      apps/vue/src/components/Form/src/hooks/useFormEvents.ts
  12. 4
      apps/vue/src/components/Form/src/props.ts
  13. 2
      apps/vue/src/components/Form/src/types/form.ts
  14. 2
      apps/vue/src/components/Preview/src/Functional.vue
  15. 1
      apps/vue/src/components/Table/src/BasicTable.vue
  16. 19
      apps/vue/src/components/Table/src/components/editable/EditableCell.vue
  17. 64
      apps/vue/src/components/Table/src/hooks/useDataSource.ts
  18. 2
      apps/vue/src/components/Table/src/props.ts
  19. 2
      apps/vue/src/components/Table/src/types/table.ts
  20. 2
      apps/vue/src/components/Upload/src/props.ts
  21. 12
      apps/vue/src/components/VxeTable/index.ts
  22. 108
      apps/vue/src/components/VxeTable/src/VxeBasicTable.tsx
  23. 59
      apps/vue/src/components/VxeTable/src/componentMap.ts
  24. 22
      apps/vue/src/components/VxeTable/src/componentType.ts
  25. 20
      apps/vue/src/components/VxeTable/src/components/AApiSelect.tsx
  26. 16
      apps/vue/src/components/VxeTable/src/components/AAutoComplete.tsx
  27. 120
      apps/vue/src/components/VxeTable/src/components/AButton.tsx
  28. 59
      apps/vue/src/components/VxeTable/src/components/AButtonGroup.tsx
  29. 42
      apps/vue/src/components/VxeTable/src/components/ACascader.tsx
  30. 5
      apps/vue/src/components/VxeTable/src/components/ACheckboxGroup.tsx
  31. 33
      apps/vue/src/components/VxeTable/src/components/ADatePicker.tsx
  32. 27
      apps/vue/src/components/VxeTable/src/components/AEmpty.tsx
  33. 16
      apps/vue/src/components/VxeTable/src/components/AInput.tsx
  34. 16
      apps/vue/src/components/VxeTable/src/components/AInputNumber.tsx
  35. 17
      apps/vue/src/components/VxeTable/src/components/AInputSearch.tsx
  36. 18
      apps/vue/src/components/VxeTable/src/components/AMonthPicker.tsx
  37. 5
      apps/vue/src/components/VxeTable/src/components/ARadioGroup.tsx
  38. 30
      apps/vue/src/components/VxeTable/src/components/ARangePicker.tsx
  39. 15
      apps/vue/src/components/VxeTable/src/components/ARate.tsx
  40. 271
      apps/vue/src/components/VxeTable/src/components/ASelect.tsx
  41. 53
      apps/vue/src/components/VxeTable/src/components/ASwitch.tsx
  42. 18
      apps/vue/src/components/VxeTable/src/components/ATimePicker.tsx
  43. 35
      apps/vue/src/components/VxeTable/src/components/ATreeSelect.tsx
  44. 18
      apps/vue/src/components/VxeTable/src/components/AWeekPicker.tsx
  45. 18
      apps/vue/src/components/VxeTable/src/components/AYearPicker.tsx
  46. 427
      apps/vue/src/components/VxeTable/src/components/common.tsx
  47. 112
      apps/vue/src/components/VxeTable/src/components/index.tsx
  48. 4
      apps/vue/src/components/VxeTable/src/const.ts
  49. 8
      apps/vue/src/components/VxeTable/src/css/common.scss
  50. 105
      apps/vue/src/components/VxeTable/src/css/component.scss
  51. 6
      apps/vue/src/components/VxeTable/src/css/index.scss
  52. 24
      apps/vue/src/components/VxeTable/src/css/scrollbar.scss
  53. 30
      apps/vue/src/components/VxeTable/src/css/toolbar.scss
  54. 6
      apps/vue/src/components/VxeTable/src/css/variable.scss
  55. 17
      apps/vue/src/components/VxeTable/src/emits.ts
  56. 19
      apps/vue/src/components/VxeTable/src/helper.ts
  57. 131
      apps/vue/src/components/VxeTable/src/methods.ts
  58. 52
      apps/vue/src/components/VxeTable/src/props.ts
  59. 4
      apps/vue/src/components/VxeTable/src/setting.ts
  60. 7
      apps/vue/src/components/VxeTable/src/types.ts
  61. 3
      apps/vue/src/components/registerGlobComp.ts
  62. 14
      apps/vue/src/hooks/component/useFormItem.ts
  63. 2
      apps/vue/src/hooks/web/usePermission.ts
  64. 6
      apps/vue/src/layouts/page/index.vue
  65. 1
      apps/vue/src/main.ts
  66. 14
      apps/vue/src/router/menus/index.ts
  67. 46
      apps/vue/src/settings/componentSetting.ts
  68. 2
      apps/vue/src/utils/index.ts
  69. 2
      apps/vue/src/views/identity/user/components/UserTable.vue
  70. 15
      apps/vue/src/views/identity/user/hooks/useUserTable.ts

3
apps/vue/build/vite/plugin/styleImport.ts

@ -2,7 +2,7 @@
* Introduces component library styles on demand.
* https://github.com/anncwb/vite-plugin-style-import
*/
import { createStyleImportPlugin } from 'vite-plugin-style-import';
import { createStyleImportPlugin, VxeTableResolve } from 'vite-plugin-style-import';
export function configStyleImportPlugin(_isBuild: boolean) {
// if (!isBuild) {
@ -77,6 +77,7 @@ export function configStyleImportPlugin(_isBuild: boolean) {
},
},
],
resolves: [VxeTableResolve()],
});
return styleImportPlugin;
}

9
apps/vue/package.json

@ -53,6 +53,7 @@
"czg": "^1.3.9",
"dayjs": "^1.11.1",
"echarts": "^5.3.2",
"exceljs": "^4.3.0",
"intro.js": "^5.1.0",
"lodash-es": "^4.17.21",
"mockjs": "^1.1.0",
@ -67,15 +68,18 @@
"showdown": "^2.1.0",
"simple-uploader.js": "^0.5.6",
"sortablejs": "^1.15.0",
"tinymce": "^5.10.3",
"tinymce": "^5.10.7",
"vditor": "^3.8.13",
"vue": "^3.2.33",
"vue": "^3.2.45",
"vue-cookies": "^1.8.1",
"vue-i18n": "^9.1.9",
"vue-json-pretty": "^2.0.6",
"vue-router": "^4.0.14",
"vue-types": "^4.1.1",
"vue3-colorpicker": "^2.0.4",
"vxe-table": "^4.3.9",
"vxe-table-plugin-export-xlsx": "^3.0.4",
"xe-utils": "^3.5.7",
"xlsx": "^0.18.5"
},
"devDependencies": {
@ -127,6 +131,7 @@
"rimraf": "^3.0.2",
"rollup": "^2.70.2",
"rollup-plugin-visualizer": "^5.6.0",
"sass": "^1.57.1",
"stylelint": "^14.7.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^7.0.0",

3
apps/vue/src/components/Cropper/src/CopperModal.vue

@ -132,9 +132,10 @@
uploadApi: {
type: Function as PropType<(params: apiFunParams) => Promise<any>>,
},
src: { type: String },
});
let filename = '';
const src = ref('');
const src = ref(props.src || '');
const previewSource = ref('');
const cropper = ref<Cropper>();
const fileList = ref<UploadProps['fileList']>([]);

2
apps/vue/src/components/Dropdown/src/Dropdown.vue

@ -57,7 +57,7 @@
* @type string[]
*/
trigger: {
type: [Array] as PropType<('contextmenu' | 'click' | 'hover')[]>,
type: Array as PropType<('contextmenu' | 'click' | 'hover')[]>,
default: () => {
return ['contextmenu'];
},

7
apps/vue/src/components/Form/src/BasicForm.vue

@ -63,6 +63,7 @@
import { basicProps } from './props';
import { useDesign } from '/@/hooks/web/useDesign';
import { isFunction, isArray } from '/@/utils/is';
export default defineComponent({
name: 'BasicForm',
@ -90,6 +91,7 @@
// Get the basic configuration of the form
const getProps = computed((): FormProps => {
// @ts-ignore
return { ...props, ...unref(propsRef) } as FormProps;
});
@ -239,8 +241,11 @@
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
}
function setFormModel(key: string, value: any) {
function setFormModel(key: string, value: any, schema: FormSchema) {
formModel[key] = value;
if (isFunction(schema.dynamicRules) || isArray(schema.rules)) {
return;
}
const { validateTrigger } = unref(getBindValue);
if (!validateTrigger || validateTrigger === 'change') {
validateFields([key]).catch((_) => {});

2
apps/vue/src/components/Form/src/components/ApiCascader.vue

@ -170,7 +170,7 @@
);
function handleChange(keys, args) {
emitData.value = keys;
emitData.value = args;
emit('defaultChange', keys, args);
}

12
apps/vue/src/components/Form/src/components/ApiRadioGroup.vue

@ -2,12 +2,12 @@
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<template>
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid" @change="handleChange">
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
<template v-for="item in getOptions" :key="`${item.value}`">
<RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled">
<RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
{{ item.label }}
</RadioButton>
<Radio v-else :value="item.value" :disabled="item.disabled">
<Radio v-else :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
{{ item.label }}
</Radio>
</template>
@ -62,7 +62,7 @@
const attrs = useAttrs();
const { t } = useI18n();
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props);
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
// Processing options value
const getOptions = computed(() => {
@ -120,11 +120,11 @@
emit('options-change', unref(getOptions));
}
function handleChange(_, ...args) {
function handleClick(...args) {
emitData.value = args;
}
return { state, getOptions, attrs, loading, t, handleChange, props };
return { state, getOptions, attrs, loading, t, handleClick, props };
},
});
</script>

4
apps/vue/src/components/Form/src/components/FormItem.vue

@ -34,7 +34,7 @@
default: () => ({}),
},
setFormModel: {
type: Function as PropType<(key: string, value: any) => void>,
type: Function as PropType<(key: string, value: any, schema: FormSchema) => void>,
default: null,
},
tableAction: {
@ -252,7 +252,7 @@
}
const target = e ? e.target : null;
const value = target ? (isCheck ? target.checked : target.value) : e;
props.setFormModel(field, value);
props.setFormModel(field, value, props.schema);
},
};
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;

13
apps/vue/src/components/Form/src/components/RadioButtonGroup.vue

@ -4,14 +4,14 @@
<template>
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
<template v-for="item in getOptions" :key="`${item.value}`">
<RadioButton :value="item.value" :disabled="item.disabled">
<RadioButton :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
{{ item.label }}
</RadioButton>
</template>
</RadioGroup>
</template>
<script lang="ts">
import { defineComponent, PropType, computed } from 'vue';
import { defineComponent, PropType, computed, ref } from 'vue';
import { Radio } from 'ant-design-vue';
import { isString } from '/@/utils/is';
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
@ -22,6 +22,7 @@
export default defineComponent({
name: 'RadioButtonGroup',
emits: ['change'],
components: {
RadioGroup: Radio.Group,
RadioButton: Radio.Button,
@ -37,8 +38,9 @@
},
setup(props) {
const attrs = useAttrs();
const emitData = ref<any[]>([]);
// Embedded in the form, just use the hook binding to perform form verification
const [state] = useRuleFormItem(props);
const [state] = useRuleFormItem(props, 'value', 'change', emitData);
// Processing options value
const getOptions = computed((): OptionsItem[] => {
@ -51,7 +53,10 @@
return options.map((item) => ({ label: item, value: item })) as OptionsItem[];
});
return { state, getOptions, attrs };
function handleClick(...args) {
emitData.value = args;
}
return { state, getOptions, attrs, handleClick };
},
});
</script>

2
apps/vue/src/components/Form/src/hooks/useForm.ts

@ -94,7 +94,7 @@ export function useForm(props?: Props): UseFormReturnType {
},
appendSchemaByField: async (
schema: FormSchema,
schema: FormSchema | FormSchema[],
prefixField: string | undefined,
first: boolean,
) => {

48
apps/vue/src/components/Form/src/hooks/useFormEvents.ts

@ -60,7 +60,7 @@ export function useFormEvents({
/**
* @description: Set form value
*/
async function setFieldsValue(values: Recordable): Promise<void> {
async function setFieldsValue(values: any): Promise<void> {
const fields = unref(getSchema)
.map((item) => item.field)
.filter(Boolean);
@ -77,6 +77,11 @@ export function useFormEvents({
const hasKey = Reflect.has(values, key);
value = handleInputNumberValue(schema?.component, value);
const { componentProps } = schema || {};
let _props = componentProps as any;
if (typeof componentProps === 'function') {
_props = _props({ formModel: unref(formModel) });
}
// 0| '' is allow
if (hasKey && fields.includes(key)) {
// time type
@ -86,17 +91,20 @@ export function useFormEvents({
for (const ele of value) {
arr.push(ele ? dateUtil(ele) : null);
}
formModel[key] = arr;
unref(formModel)[key] = arr;
} else {
const { componentProps } = schema || {};
let _props = componentProps as any;
if (typeof componentProps === 'function') {
_props = _props({ formModel });
}
formModel[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
unref(formModel)[key] = value ? (_props?.valueFormat ? value : dateUtil(value)) : null;
}
} else {
formModel[key] = value;
unref(formModel)[key] = value;
}
if (_props?.onChange) {
_props?.onChange(value);
}
validKeys.push(key);
} else {
@ -104,14 +112,14 @@ export function useFormEvents({
try {
const value = nestKey.split('.').reduce((out, item) => out[item], values);
if (isDef(value)) {
formModel[nestKey] = value;
unref(formModel)[nestKey] = unref(value);
validKeys.push(nestKey);
}
} catch (e) {
// key not exist
if (isDef(defaultValueRef.value[nestKey])) {
//formModel[nestKey] = defaultValueRef.value[nestKey];
formModel[nestKey] = cloneDeep(defaultValueRef.value[nestKey]);
unref(formModel)[nestKey] = cloneDeep(unref(defaultValueRef.value[nestKey]));
}
}
});
@ -154,19 +162,23 @@ export function useFormEvents({
/**
* @description: Insert after a certain field, if not insert the last
*/
async function appendSchemaByField(schema: FormSchema, prefixField?: string, first = false) {
async function appendSchemaByField(
schema: FormSchema | FormSchema[],
prefixField?: string,
first = false,
) {
const schemaList: FormSchema[] = cloneDeep(unref(getSchema));
const index = schemaList.findIndex((schema) => schema.field === prefixField);
const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[]);
if (!prefixField || index === -1 || first) {
first ? schemaList.unshift(schema) : schemaList.push(schema);
first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList);
schemaRef.value = schemaList;
_setDefaultValue(schema);
return;
}
if (index !== -1) {
schemaList.splice(index + 1, 0, schema);
schemaList.splice(index + 1, 0, ..._schemaList);
}
_setDefaultValue(schema);
@ -215,15 +227,19 @@ export function useFormEvents({
return;
}
const schema: FormSchema[] = [];
updateData.forEach((item) => {
unref(getSchema).forEach((val) => {
unref(getSchema).forEach((val) => {
let _val;
updateData.forEach((item) => {
if (val.field === item.field) {
const newSchema = deepMerge(val, item);
schema.push(newSchema as FormSchema);
} else {
schema.push(val);
_val = item;
}
});
if (_val !== undefined && val.field === _val.field) {
const newSchema = deepMerge(val, _val);
schema.push(newSchema as FormSchema);
} else {
schema.push(val);
}
});
_setDefaultValue(schema);

4
apps/vue/src/components/Form/src/props.ts

@ -23,7 +23,7 @@ export const basicProps = {
compact: propTypes.bool,
// 表单配置规则
schemas: {
type: [Array] as PropType<FormSchema[]>,
type: Array as PropType<FormSchema[]>,
default: () => [],
},
mergeDynamicData: {
@ -120,7 +120,7 @@ export const tabProps = {
compact: propTypes.bool,
// 表单配置规则
schemas: {
type: [Array] as PropType<TabFormSchema[]>,
type: Array as PropType<TabFormSchema[]>,
default: () => [],
},
mergeDynamicData: {

2
apps/vue/src/components/Form/src/types/form.ts

@ -35,7 +35,7 @@ export interface FormActionType {
setProps: (formProps: Partial<FormProps>) => Promise<void>;
removeSchemaByField: (field: string | string[]) => Promise<void>;
appendSchemaByField: (
schema: FormSchema,
schema: FormSchema | FormSchema[],
prefixField: string | undefined,
first?: boolean | undefined,
) => Promise<void>;

2
apps/vue/src/components/Preview/src/Functional.vue

@ -30,7 +30,7 @@
default: false,
},
imageList: {
type: [Array] as PropType<string[]>,
type: Array as PropType<string[]>,
default: null,
},
index: {

1
apps/vue/src/components/Table/src/BasicTable.vue

@ -97,6 +97,7 @@
import { warn } from '/@/utils/log';
export default defineComponent({
name:'BasicTable',
components: {
Table,
BasicForm,

19
apps/vue/src/components/Table/src/components/editable/EditableCell.vue

@ -77,6 +77,11 @@
if (isFunction(compProps)) {
compProps = compProps({ text: val, record, column, index }) ?? {};
}
// onChange handleChange onChange, onChange
compProps.onChangeTemp = compProps.onChange;
delete compProps.onChange;
const component = unref(getComponent);
const apiSelectProps: Recordable = {};
if (component === 'ApiSelect') {
@ -186,7 +191,7 @@
} else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e)) {
currentValueRef.value = e;
}
const onChange = unref(getComponentProps)?.onChange;
const onChange = unref(getComponentProps)?.onChangeTemp;
if (onChange && isFunction(onChange)) onChange(...arguments);
table.emit?.('edit-change', {
@ -194,10 +199,10 @@
value: unref(currentValueRef),
record: toRaw(props.record),
});
handleSubmiRule();
handleSubmitRule();
}
async function handleSubmiRule() {
async function handleSubmitRule() {
const { column, record } = props;
const { editRule } = column;
const currentValue = unref(currentValueRef);
@ -227,7 +232,7 @@
async function handleSubmit(needEmit = true, valid = true) {
if (valid) {
const isPass = await handleSubmiRule();
const isPass = await handleSubmitRule();
if (!isPass) return false;
}
@ -339,7 +344,7 @@
if (props.record) {
initCbs('submitCbs', handleSubmit);
initCbs('validCbs', handleSubmiRule);
initCbs('validCbs', handleSubmitRule);
initCbs('cancelCbs', handleCancel);
if (props.column.dataIndex) {
@ -404,9 +409,7 @@
column: this.column,
index: this.index,
})
: this.getValues
? this.getValues
: '\u00A0'}
: (this.getValues ?? "\u00A0")}
</div>
{!this.column.editRow && <FormOutlined class={`${this.prefixCls}__normal-icon`} />}
</div>

64
apps/vue/src/components/Table/src/hooks/useDataSource.ts

@ -13,7 +13,7 @@ import {
} from 'vue';
import { useTimeoutFn } from '/@/hooks/core/useTimeout';
import { buildUUID } from '/@/utils/uuid';
import { isFunction, isBoolean } from '/@/utils/is';
import { isFunction, isBoolean, isObject } from '/@/utils/is';
import { get, cloneDeep, merge } from 'lodash-es';
import { FETCH_SETTING, ROW_KEY, PAGE_SIZE } from '../const';
@ -165,40 +165,52 @@ export function useDataSource(
const rowKeyName = unref(getRowKey);
if (!rowKeyName) return;
const rowKeys = !Array.isArray(rowKey) ? [rowKey] : rowKey;
for (const key of rowKeys) {
let index: number | undefined = dataSourceRef.value.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === 'function') {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
}
return row[targetKeyName] === key;
});
if (index >= 0) {
dataSourceRef.value.splice(index, 1);
function deleteRow(data?: Recordable<any>, key?: string | number | string[] | number[]) {
const row: { index: number; data: [] } = findRow(data, key);
if (row === null || row.index === -1) {
return;
}
index = unref(propsRef).dataSource?.findIndex((row) => {
let targetKeyName: string;
if (typeof rowKeyName === 'function') {
targetKeyName = rowKeyName(row);
} else {
targetKeyName = rowKeyName as string;
row.data.splice(row.index, 1);
function findRow(data, key) {
if (data === null || data === undefined) {
return null;
}
return row[targetKeyName] === key;
});
if (typeof index !== 'undefined' && index !== -1)
unref(propsRef).dataSource?.splice(index, 1);
for (let i = 0; i < data.length; i++) {
const row = data[i];
let targetKeyName: string = rowKeyName as string;
if (isFunction(rowKeyName)) {
targetKeyName = rowKeyName(row);
}
if (row[targetKeyName] === key) {
return { index: i, data };
}
if (row.children?.length > 0) {
const result = findRow(row.children, key);
if (result != null) {
return result;
}
}
}
return null;
}
}
for (const key of rowKeys) {
deleteRow(dataSourceRef.value, key);
deleteRow(unref(propsRef).dataSource, key);
}
setPagination({
total: unref(propsRef).dataSource?.length,
});
}
function insertTableDataRecord(record: Recordable, index: number): Recordable | undefined {
function insertTableDataRecord(record: Recordable | Recordable[], index: number): Recordable[] | undefined {
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
index = index ?? dataSourceRef.value?.length;
unref(dataSourceRef).splice(index, 0, record);
const _record = isObject(record) ? [record as Recordable] : (record as Recordable[]);
unref(dataSourceRef).splice(index, 0, ..._record);
return unref(dataSourceRef);
}
@ -309,7 +321,7 @@ export function useDataSource(
const isArrayResult = Array.isArray(res);
let resultItems: Recordable[] = isArrayResult ? res : get(res, listField);
const resultTotal: number = isArrayResult ? res.length : get(res, totalField);
const resultTotal: number = isArrayResult ? res.length : Number(get(res, totalField));
// 假如数据变少,导致总页数变少并小于当前选中页码,通过getPaginationRef获取到的页码是不正确的,需获取正确的页码再次执行
if (resultTotal) {

2
apps/vue/src/components/Table/src/props.ts

@ -83,7 +83,7 @@ export const basicProps = {
default: null,
},
columns: {
type: [Array] as PropType<BasicColumn[]>,
type: Array as PropType<BasicColumn[]>,
default: () => [],
},
showIndexColumn: { type: Boolean, default: true },

2
apps/vue/src/components/Table/src/types/table.ts

@ -98,7 +98,7 @@ export interface TableActionType {
setTableData: <T = Recordable>(values: T[]) => void;
updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void;
deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void;
insertTableDataRecord: (record: Recordable, index?: number) => Recordable | void;
insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => Recordable[] | void;
findTableDataRecord: (rowKey: string | number) => Recordable | void;
getColumns: (opt?: GetColumnsParams) => BasicColumn[];
setColumns: (columns: BasicColumn[] | string[]) => void;

2
apps/vue/src/components/Upload/src/props.ts

@ -69,7 +69,7 @@ export const previewProps = {
export const fileListProps = {
columns: {
type: [Array] as PropType<FileBasicColumn[]>,
type: Array as PropType<FileBasicColumn[]>,
default: null,
},
actionColumn: {

12
apps/vue/src/components/VxeTable/index.ts

@ -0,0 +1,12 @@
import { withInstall } from '/@/utils';
import vxeBasicTable from './src/VxeBasicTable';
import { VXETable } from 'vxe-table';
import VXETablePluginAntd from './src/components';
import VXETablePluginExportXLSX from 'vxe-table-plugin-export-xlsx';
import './src/setting';
export const VxeBasicTable = withInstall(vxeBasicTable);
export * from 'vxe-table';
export * from './src/types';
VXETable.use(VXETablePluginAntd).use(VXETablePluginExportXLSX);

108
apps/vue/src/components/VxeTable/src/VxeBasicTable.tsx

@ -0,0 +1,108 @@
import { defineComponent } from 'vue';
import { computed, ref } from 'vue';
import { BasicTableProps } from './types';
import { omit } from 'lodash-es';
import { basicProps } from './props';
import { ignorePropKeys } from './const';
import { basicEmits } from './emits';
import XEUtils from 'xe-utils';
import type { VxeGridInstance, VxeGridEventProps, GridMethods, TableMethods } from 'vxe-table';
import { Grid as VxeGrid } from 'vxe-table';
import { extendSlots } from '/@/utils/helper/tsxHelper';
import { gridComponentMethodKeys } from './methods';
export default defineComponent({
name: 'VxeBasicTable',
props: basicProps,
emits: basicEmits,
setup(props, { emit, attrs }) {
const tableElRef = ref<VxeGridInstance>();
const emitEvents: VxeGridEventProps = {};
const extendTableMethods = (methodKeys) => {
const funcs: any = {};
methodKeys.forEach((name) => {
funcs[name] = (...args: any[]) => {
const $vxegrid: any = tableElRef.value;
if ($vxegrid && $vxegrid[name]) {
return $vxegrid[name](...args);
}
};
});
return funcs;
};
const gridExtendTableMethods = extendTableMethods(gridComponentMethodKeys) as GridMethods &
TableMethods;
basicEmits.forEach((name) => {
const type = XEUtils.camelCase(`on-${name}`) as keyof VxeGridEventProps;
emitEvents[type] = (...args: any[]) => emit(name, ...args);
});
/**
* @description:
* 1.
*/
const getBindValues = computed<BasicTableProps>(() => {
const propsData: BasicTableProps = {
...attrs,
...props,
};
return propsData;
});
/**
* @description: Table
*/
const getBindGridValues = computed(() => {
const omitProps = omit(getBindValues.value, ignorePropKeys);
return {
...omitProps,
...getBindGridEvent,
};
});
/**
* @description: class
*/
const getWrapperClass = computed(() => {
return [attrs.class];
});
/**
* @description: Vxe-table
*/
const getBindGridEvent: VxeGridEventProps = {
...emitEvents,
};
return {
getWrapperClass,
getBindGridValues,
tableElRef,
...gridExtendTableMethods,
};
},
render() {
const { tableClass, tableStyle } = this.$props;
return (
<div class={`h-full flex flex-col bg-white ${this.getWrapperClass}`}>
<VxeGrid
ref="tableElRef"
class={`vxe-grid_scrollbar px-6 py-4 ${tableClass}`}
style={tableStyle}
{...this.getBindGridValues}
>
{extendSlots(this.$slots)}
</VxeGrid>
</div>
);
},
});

59
apps/vue/src/components/VxeTable/src/componentMap.ts

@ -0,0 +1,59 @@
import type { Component } from 'vue';
import type { ComponentType } from './componentType';
import { ApiSelect, ApiTreeSelect } from '/@/components/Form';
import {
Input,
Select,
Radio,
Checkbox,
AutoComplete,
Cascader,
DatePicker,
InputNumber,
Switch,
TimePicker,
TreeSelect,
Rate,
Button,
Empty,
} from 'ant-design-vue';
const componentMap = new Map<ComponentType, Component>();
componentMap.set('AButton', Button);
componentMap.set('AInput', Input);
componentMap.set('AInputSearch', Input.Search);
componentMap.set('AInputNumber', InputNumber);
componentMap.set('AAutoComplete', AutoComplete);
componentMap.set('ASelect', Select);
componentMap.set('ATreeSelect', TreeSelect);
componentMap.set('ASwitch', Switch);
componentMap.set('ARadioGroup', Radio.Group);
componentMap.set('ACheckboxGroup', Checkbox.Group);
componentMap.set('ACascader', Cascader);
componentMap.set('ARate', Rate);
componentMap.set('ADatePicker', DatePicker);
componentMap.set('AMonthPicker', DatePicker.MonthPicker);
componentMap.set('ARangePicker', DatePicker.RangePicker);
componentMap.set('AWeekPicker', DatePicker.WeekPicker);
componentMap.set('AYearPicker', DatePicker.YearPicker);
componentMap.set('ATimePicker', TimePicker);
componentMap.set('AApiSelect', ApiSelect);
componentMap.set('AApiTreeSelect', ApiTreeSelect);
componentMap.set('AEmpty', Empty);
export function add(compName: ComponentType, component: Component) {
componentMap.set(compName, component);
}
export function del(compName: ComponentType) {
componentMap.delete(compName);
}
export { componentMap };

22
apps/vue/src/components/VxeTable/src/componentType.ts

@ -0,0 +1,22 @@
export type ComponentType =
| 'AInput'
| 'AInputNumber'
| 'ASelect'
| 'AApiSelect'
| 'ATreeSelect'
| 'AApiTreeSelect'
| 'ARadioGroup'
| 'ACheckboxGroup'
| 'AAutoComplete'
| 'ACascader'
| 'ADatePicker'
| 'AMonthPicker'
| 'ARangePicker'
| 'AWeekPicker'
| 'ATimePicker'
| 'AYearPicker'
| 'ASwitch'
| 'ARate'
| 'AInputSearch'
| 'AButton'
| 'AEmpty';

20
apps/vue/src/components/VxeTable/src/components/AApiSelect.tsx

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

16
apps/vue/src/components/VxeTable/src/components/AAutoComplete.tsx

@ -0,0 +1,16 @@
import {
createEditRender,
createDefaultRender,
createFilterRender,
createDefaultFilterRender,
createFormItemRender,
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};

120
apps/vue/src/components/VxeTable/src/components/AButton.tsx

@ -0,0 +1,120 @@
import { h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeGlobalRendererHandles,
} from 'vxe-table';
import XEUtils from 'xe-utils';
import { cellText, createEvents, createProps, getComponent } from './common';
const COMPONENT_NAME = 'AButton';
export function createEditRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
return [
h(Component, {
...attrs,
...createProps(renderOpts, null),
...createEvents(renderOpts, params),
}),
];
};
}
export function createDefaultRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
) {
const { attrs } = renderOpts;
const Component = getComponent(COMPONENT_NAME);
return [
h(
Component,
{
...attrs,
...createProps(renderOpts, null),
...createEvents(renderOpts, params),
},
cellText(renderOpts.content),
),
];
};
}
export function createFormItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
const { attrs, content } = renderOpts;
const { property, $form, data } = params;
const props = createProps(renderOpts, null);
const Component = getComponent(COMPONENT_NAME);
return [
h(
Component,
{
...attrs,
...props,
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
XEUtils.set(data, property, value);
},
() => {
// 处理 change 事件相关逻辑
$form.updateStatus({
...params,
field: property,
});
},
),
},
{
default: () => cellText(content || props.content),
},
),
];
};
}
function createToolbarButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderToolOptions,
params: VxeGlobalRendererHandles.RenderButtonParams,
) {
const { attrs } = renderOpts;
const { button } = params;
const props = createProps(renderOpts, null);
const Component = getComponent(COMPONENT_NAME);
return [
h(
Component,
{
...attrs,
...props,
...createEvents(renderOpts, params),
},
{
default: () => cellText(button?.content || props.content),
},
),
];
};
}
export default {
renderEdit: createEditRender(),
renderDefault: createDefaultRender(),
renderItemContent: createFormItemRender(),
renderToolbarButton: createToolbarButtonRender(),
};

59
apps/vue/src/components/VxeTable/src/components/AButtonGroup.tsx

@ -0,0 +1,59 @@
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeGlobalRendererHandles,
} from 'vxe-table';
import { createDefaultRender, createEditRender, createFormItemRender } from './AButton';
function createEditButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
) {
const buttonEditRender = createEditRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: VxeGlobalRendererHandles.RenderEditOptions) =>
buttonEditRender(childRenderOpts, params)[0],
);
}
return [];
};
}
function createDefaultButtonRender() {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
) {
const buttonDefaultRender = createDefaultRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: VxeGlobalRendererHandles.RenderDefaultOptions) =>
buttonDefaultRender(childRenderOpts, params)[0],
);
}
return [];
};
}
function createButtonItemRender() {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
const buttonItemRender = createFormItemRender();
const { children } = renderOpts;
if (children) {
return children.map(
(childRenderOpts: FormItemRenderOptions) => buttonItemRender(childRenderOpts, params)[0],
);
}
return [];
};
}
export default {
renderEdit: createEditButtonRender(),
renderDefault: createDefaultButtonRender(),
renderItemContent: createButtonItemRender(),
};

42
apps/vue/src/components/VxeTable/src/components/ACascader.tsx

@ -0,0 +1,42 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
createCellRender,
createFormItemRender,
createExportMethod,
} from './common';
function matchCascaderData(index: number, list: any[], values: any[], labels: any[]) {
const val = values[index];
if (list && values.length > index) {
XEUtils.each(list, (item) => {
if (item.value === val) {
labels.push(item.label);
matchCascaderData(++index, item.children, values, labels);
}
});
}
}
function getCascaderCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
const cellValue = XEUtils.get(row, column.field as string);
const values = cellValue || [];
const labels: Array<any> = [];
matchCascaderData(0, props.options, values, labels);
return (
props.showAllLevels === false ? labels.slice(labels.length - 1, labels.length) : labels
).join(` ${props.separator || '/'} `);
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getCascaderCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getCascaderCellValue),
};

5
apps/vue/src/components/VxeTable/src/components/ACheckboxGroup.tsx

@ -0,0 +1,5 @@
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};

33
apps/vue/src/components/VxeTable/src/components/ADatePicker.tsx

@ -0,0 +1,33 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
createEditRender,
createExportMethod,
createFormItemRender,
} from './common';
export function getDatePickerCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
defaultFormat: string,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
let cellValue = XEUtils.get(row, column.field as string);
if (cellValue) {
cellValue = cellValue.format(props.format || defaultFormat);
}
return cellValue;
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM-DD'];
}),
};

27
apps/vue/src/components/VxeTable/src/components/AEmpty.tsx

@ -0,0 +1,27 @@
import { h } from 'vue';
import { VxeGlobalRendererHandles } from 'vxe-table';
import { getComponent } from './common';
function createEmptyRender() {
return function (renderOpts: VxeGlobalRendererHandles.RenderEmptyOptions) {
const { name, attrs, props } = renderOpts;
const Component = getComponent(name);
return [
h(
'div',
{
class: 'flex items-center justify-center',
},
h(Component, {
...attrs,
...props,
}),
),
];
};
}
export default {
renderEmpty: createEmptyRender(),
};

16
apps/vue/src/components/VxeTable/src/components/AInput.tsx

@ -0,0 +1,16 @@
import {
createEditRender,
createDefaultRender,
createFilterRender,
createDefaultFilterRender,
createFormItemRender,
} from './common';
export default {
autofocus: 'input.ant-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};

16
apps/vue/src/components/VxeTable/src/components/AInputNumber.tsx

@ -0,0 +1,16 @@
import {
createEditRender,
createFilterRender,
createFormItemRender,
createDefaultFilterRender,
createDefaultRender,
} from './common';
export default {
autofocus: 'input.ant-input-number-input',
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};

17
apps/vue/src/components/VxeTable/src/components/AInputSearch.tsx

@ -0,0 +1,17 @@
import {
createEditRender,
createDefaultRender,
createFilterRender,
createDefaultFilterRender,
createFormItemRender,
createToolbarToolRender,
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
renderToolbarTool: createToolbarToolRender(),
};

18
apps/vue/src/components/VxeTable/src/components/AMonthPicker.tsx

@ -0,0 +1,18 @@
import { getDatePickerCellValue } from './ADatePicker';
import {
createCellRender,
createEditRender,
createExportMethod,
createFormItemRender,
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-MM'];
}),
};

5
apps/vue/src/components/VxeTable/src/components/ARadioGroup.tsx

@ -0,0 +1,5 @@
import { createFormItemRender } from './common';
export default {
renderItemContent: createFormItemRender(),
};

30
apps/vue/src/components/VxeTable/src/components/ARangePicker.tsx

@ -0,0 +1,30 @@
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createCellRender,
createEditRender,
createExportMethod,
createFormItemRender,
} from './common';
function getRangePickerCellValue(
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { row, column } = params;
let cellValue = XEUtils.get(row, column.field as string);
if (cellValue) {
cellValue = XEUtils.map(cellValue, (date: any) =>
date.format(props.format || 'YYYY-MM-DD'),
).join(' ~ ');
}
return cellValue;
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getRangePickerCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getRangePickerCellValue),
};

15
apps/vue/src/components/VxeTable/src/components/ARate.tsx

@ -0,0 +1,15 @@
import {
createEditRender,
createDefaultRender,
createFilterRender,
createDefaultFilterRender,
createFormItemRender,
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter: createFilterRender(),
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};

271
apps/vue/src/components/VxeTable/src/components/ASelect.tsx

@ -0,0 +1,271 @@
import { ComponentOptions, h, resolveComponent } from 'vue';
import { VxeColumnPropTypes, VxeGlobalRendererHandles } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
cellText,
createCellRender,
createEvents,
createProps,
isEmptyValue,
createExportMethod,
createFormItemRender,
} from './common';
function renderOptions(options: any[], optionProps: VxeGlobalRendererHandles.RenderOptionProps) {
const labelProp = optionProps.label || 'label';
const valueProp = optionProps.value || 'value';
return XEUtils.map(options, (item, oIndex) => {
return h(
resolveComponent('a-select-option') as ComponentOptions,
{
key: oIndex,
value: item[valueProp],
disabled: item.disabled,
},
{
default: () => cellText(item[labelProp]),
},
);
});
}
function createEditRender() {
return function (
renderOpts: VxeColumnPropTypes.EditRender,
params: VxeGlobalRendererHandles.RenderEditParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const { row, column, $table } = params;
const { attrs } = renderOpts;
const cellValue = XEUtils.get(row, column.field as string);
const props = createProps(renderOpts, cellValue);
const ons = createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
XEUtils.set(row, column.field as string, value);
},
() => {
// 处理 change 事件相关逻辑
$table.updateStatus(params);
},
);
if (optionGroups) {
const groupOptions = optionGroupProps.options || 'options';
const groupLabel = optionGroupProps.label || 'label';
return [
h(
resolveComponent('a-select') as ComponentOptions,
{
...attrs,
...props,
...ons,
},
{
default: () => {
return XEUtils.map(optionGroups, (group, gIndex) => {
return h(
resolveComponent('a-select-opt-group') as ComponentOptions,
{
key: gIndex,
},
{
label: () => {
return h('span', {}, group[groupLabel]);
},
default: () => renderOptions(group[groupOptions], optionProps),
},
);
});
},
},
),
];
}
return [
h(
resolveComponent('a-select') as ComponentOptions,
{
...props,
...attrs,
...ons,
},
{
default: () => renderOptions(options, optionProps),
},
),
];
};
}
function getSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
) {
const {
options = [],
optionGroups,
props = {},
optionProps = {},
optionGroupProps = {},
} = renderOpts;
const { row, column } = params;
const labelProp = optionProps.label || 'label';
const valueProp = optionProps.value || 'value';
const groupOptions = optionGroupProps.options || 'options';
const cellValue = XEUtils.get(row, column.field as string);
if (!isEmptyValue(cellValue)) {
return XEUtils.map(
props.mode === 'multiple' ? cellValue : [cellValue],
optionGroups
? (value) => {
let selectItem;
for (let index = 0; index < optionGroups.length; index++) {
selectItem = XEUtils.find(
optionGroups[index][groupOptions],
(item) => item[valueProp] === value,
);
if (selectItem) {
break;
}
}
return selectItem ? selectItem[labelProp] : value;
}
: (value) => {
const selectItem = XEUtils.find(options, (item) => item[valueProp] === value);
return selectItem ? selectItem[labelProp] : value;
},
).join(', ');
}
return '';
}
function createFilterRender() {
return function (
renderOpts: VxeColumnPropTypes.FilterRender,
params: VxeGlobalRendererHandles.RenderFilterParams,
) {
const { options = [], optionGroups, optionProps = {}, optionGroupProps = {} } = renderOpts;
const groupOptions = optionGroupProps.options || 'options';
const groupLabel = optionGroupProps.label || 'label';
const { column } = params;
const { attrs } = renderOpts;
return [
h(
'div',
{
class: 'vxe-table--filter-antd-wrapper',
},
optionGroups
? column.filters.map((option, oIndex) => {
const optionValue = option.data;
const props = createProps(renderOpts, optionValue);
return h(
resolveComponent('a-select') as ComponentOptions,
{
key: oIndex,
...attrs,
...props,
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
option.data = value;
},
() => {
// 处理 change 事件相关逻辑
const { $panel } = params;
$panel.changeOption(
null,
props.mode === 'multiple'
? option.data && option.data.length > 0
: !XEUtils.eqNull(option.data),
option,
);
},
),
},
{
default: () => {
return XEUtils.map(optionGroups, (group, gIndex) => {
return h(
resolveComponent('a-select-opt-group') as ComponentOptions,
{
key: gIndex,
},
{
label: () => {
return h('span', {}, group[groupLabel]);
},
default: () => renderOptions(group[groupOptions], optionProps),
},
);
});
},
},
);
})
: column.filters.map((option, oIndex) => {
const optionValue = option.data;
const props = createProps(renderOpts, optionValue);
return h(
resolveComponent('a-select') as ComponentOptions,
{
key: oIndex,
...attrs,
...props,
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
option.data = value;
},
() => {
// 处理 change 事件相关逻辑
const { $panel } = params;
$panel.changeOption(
null,
props.mode === 'multiple'
? option.data && option.data.length > 0
: !XEUtils.eqNull(option.data),
option,
);
},
),
},
{
default: () => renderOptions(options, optionProps),
},
);
}),
),
];
};
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getSelectCellValue),
renderFilter: createFilterRender(),
defaultFilterMethod(params) {
const { option, row, column } = params;
const { data } = option;
const { field, filterRender: renderOpts } = column;
const { props = {} } = renderOpts;
const cellValue = XEUtils.get(row, field);
if (props.mode === 'multiple') {
if (XEUtils.isArray(cellValue)) {
return XEUtils.includeArrays(cellValue, data);
}
return data.indexOf(cellValue) > -1;
}
return cellValue == data;
},
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getSelectCellValue),
};

53
apps/vue/src/components/VxeTable/src/components/ASwitch.tsx

@ -0,0 +1,53 @@
import { h } from 'vue';
import XEUtils from 'xe-utils';
import {
createEditRender,
createDefaultRender,
createProps,
createEvents,
createDefaultFilterRender,
createFormItemRender,
getComponent,
} from './common';
export default {
renderDefault: createDefaultRender(),
renderEdit: createEditRender(),
renderFilter(renderOpts, params) {
const { column } = params;
const { name, attrs } = renderOpts;
const Component = getComponent(name);
return [
h(
'div',
{
class: 'vxe-table--filter-antd-wrapper',
},
column.filters.map((option, oIndex) => {
const optionValue = option.data;
return h(Component, {
key: oIndex,
...attrs,
...createProps(renderOpts, optionValue),
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
option.data = value;
},
() => {
// 处理 change 事件相关逻辑
const { $panel } = params;
$panel.changeOption(null, XEUtils.isBoolean(option.data), option);
},
),
});
}),
),
];
},
defaultFilterMethod: createDefaultFilterRender(),
renderItemContent: createFormItemRender(),
};

18
apps/vue/src/components/VxeTable/src/components/ATimePicker.tsx

@ -0,0 +1,18 @@
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
createCellRender,
createFormItemRender,
createExportMethod,
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['HH:mm:ss'];
}),
};

35
apps/vue/src/components/VxeTable/src/components/ATreeSelect.tsx

@ -0,0 +1,35 @@
import { VxeGlobalRendererHandles } from 'vxe-table';
import XEUtils from 'xe-utils';
import {
createEditRender,
createCellRender,
isEmptyValue,
createFormItemRender,
createExportMethod,
} from './common';
function getTreeSelectCellValue(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderCellParams | VxeGlobalRendererHandles.ExportMethodParams,
) {
const { props = {} } = renderOpts;
const { treeData, treeCheckable } = props;
const { row, column } = params;
const cellValue = XEUtils.get(row, column.field as string);
if (!isEmptyValue(cellValue)) {
return XEUtils.map(treeCheckable ? cellValue : [cellValue], (value) => {
const matchObj = XEUtils.findTree(treeData, (item: any) => item.value === value, {
children: 'children',
});
return matchObj ? matchObj.item.title : value;
}).join(', ');
}
return cellValue;
}
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getTreeSelectCellValue),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getTreeSelectCellValue),
};

18
apps/vue/src/components/VxeTable/src/components/AWeekPicker.tsx

@ -0,0 +1,18 @@
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
createCellRender,
createFormItemRender,
createExportMethod,
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY-WW周'];
}),
};

18
apps/vue/src/components/VxeTable/src/components/AYearPicker.tsx

@ -0,0 +1,18 @@
import { getDatePickerCellValue } from './ADatePicker';
import {
createEditRender,
createCellRender,
createFormItemRender,
createExportMethod,
} from './common';
export default {
renderEdit: createEditRender(),
renderCell: createCellRender(getDatePickerCellValue, () => {
return ['YYYY'];
}),
renderItemContent: createFormItemRender(),
exportMethod: createExportMethod(getDatePickerCellValue, () => {
return ['YYYY'];
}),
};

427
apps/vue/src/components/VxeTable/src/components/common.tsx

@ -0,0 +1,427 @@
import { ComponentOptions, h } from 'vue';
import {
FormItemContentRenderParams,
FormItemRenderOptions,
VxeGlobalRendererHandles,
} from 'vxe-table';
import XEUtils from 'xe-utils';
import { componentMap } from '../componentMap';
import { ComponentType } from '../componentType';
import { createPlaceholderMessage } from '../helper';
/**
* @description:
*/
export function getComponent(componentName) {
const Component = componentMap.get(componentName as ComponentType);
if (!Component) throw `您还没注册此组件 ${componentName}`;
return Component as ComponentOptions;
}
export function isEmptyValue(cellValue: any) {
return cellValue === null || cellValue === undefined || cellValue === '';
}
export function formatText(cellValue: any) {
return '' + (isEmptyValue(cellValue) ? '' : cellValue);
}
export function cellText(cellValue: any): string[] {
return [formatText(cellValue)];
}
/**
* @description:
*/
export function getOnName(type: string) {
return 'on' + type.substring(0, 1).toLocaleUpperCase() + type.substring(1);
}
/**
* @description:
*/
function getModelKey(renderOpts: VxeGlobalRendererHandles.RenderOptions) {
let prop = 'value';
switch (renderOpts.name) {
case 'ASwitch':
prop = 'checked';
break;
}
return prop;
}
/**
* @description:
*/
function getModelEvent(renderOpts: VxeGlobalRendererHandles.RenderOptions) {
let type = 'update:value';
switch (renderOpts.name) {
case 'ASwitch':
type = 'update:checked';
break;
}
return type;
}
/**
* @description: chang值改变方法
* @param {}
* @return {*}
* @author: *
*/
function getChangeEvent() {
return 'change';
}
function getClickEvent() {
return 'click';
}
/**
* @description:
* @param {}
* @return {*}
* @author: *
*/
export function createEvents(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
params: VxeGlobalRendererHandles.RenderParams,
inputFunc?: Function,
changeFunc?: Function,
clickFunc?: Function,
) {
const { events } = renderOpts;
const modelEvent = getModelEvent(renderOpts);
const changeEvent = getChangeEvent();
const clickEvent = getClickEvent();
const isSameEvent = changeEvent === modelEvent;
const ons: { [type: string]: Function } = {};
XEUtils.objectEach(events, (func: Function, key: string) => {
ons[getOnName(key)] = function (...args: any[]) {
func(params, ...args);
};
});
if (inputFunc) {
ons[getOnName(modelEvent)] = function (targetEvnt: any) {
inputFunc(targetEvnt);
if (events && events[modelEvent]) {
events[modelEvent](params, targetEvnt);
}
if (isSameEvent && changeFunc) {
changeFunc(targetEvnt);
}
};
}
if (!isSameEvent && changeFunc) {
ons[getOnName(changeEvent)] = function (...args: any[]) {
changeFunc(...args);
if (events && events[changeEvent]) {
events[changeEvent](params, ...args);
}
};
}
if (clickFunc) {
ons[getOnName(clickEvent)] = function (...args: any[]) {
clickFunc(...args);
if (events && events[clickEvent]) {
events[clickEvent](params, ...args);
}
};
}
return ons;
}
/**
* @description:
*/
export function createProps(
renderOpts: VxeGlobalRendererHandles.RenderOptions,
value: any,
defaultProps?: { [prop: string]: any },
) {
const name = renderOpts.name as ComponentType;
return XEUtils.assign(
{
placeholder: createPlaceholderMessage(name),
allowClear: true,
},
defaultProps,
renderOpts.props,
{
[getModelKey(renderOpts)]: value,
},
);
}
/**
* @description:
*/
export function createDefaultRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderDefaultOptions,
params: VxeGlobalRendererHandles.RenderDefaultParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
const cellValue = XEUtils.get(row, column.field as string);
const args = (callBack && callBack(renderOpts, params)) ?? {};
const Component = getComponent(name);
return [
h(Component, {
...attrs,
...createProps(renderOpts, cellValue, defaultProps),
...args,
...createEvents(
renderOpts,
params,
(value: any) => XEUtils.set(row, column.field as string, value),
() => $table.updateStatus(params),
),
}),
];
};
}
/**
* @description:
*/
export function createEditRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderEditOptions,
params: VxeGlobalRendererHandles.RenderEditParams,
) {
const { row, column, $table } = params;
const { name, attrs } = renderOpts;
const cellValue = XEUtils.get(row, column.field as string);
const args = (callBack && callBack(renderOpts, params)) ?? {};
const Component = getComponent(name);
return [
h(Component, {
...attrs,
...createProps(renderOpts, cellValue, defaultProps),
...args,
...createEvents(
renderOpts,
params,
(value: any) => XEUtils.set(row, column.field as string, value),
() => $table.updateStatus(params),
),
}),
];
};
}
/**
* @description:
*/
export function createFilterRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderFilterOptions,
params: VxeGlobalRendererHandles.RenderFilterParams,
) {
const { column } = params;
const { name, attrs } = renderOpts;
const args = (callBack && callBack(renderOpts, params)) ?? {};
const Component = getComponent(name);
return [
h(
'div',
{
class: 'vxe-table--filter-antd-wrapper',
},
column.filters.map((option, oIndex) => {
const optionValue = option.data;
const checked = !!option.data;
return h(Component, {
key: oIndex,
...attrs,
...createProps(renderOpts, optionValue, defaultProps),
...args,
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
option.data = value;
},
() => {
// 处理 change 事件相关逻辑
const { $panel } = params;
$panel.changeOption(null, checked, option);
},
),
});
}),
),
];
};
}
/**
* @description:
* @param {}
* @return {*}
* @author: *
*/
export function createDefaultFilterRender() {
return function (params: VxeGlobalRendererHandles.FilterMethodParams) {
const { option, row, column } = params;
const { data } = option;
const cellValue = XEUtils.get(row, column.field as string);
return cellValue === data;
};
}
/**
* @description: form表单渲染
*/
export function createFormItemRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: FormItemRenderOptions,
params: FormItemContentRenderParams,
) => Record<string, any>,
) {
return function (renderOpts: FormItemRenderOptions, params: FormItemContentRenderParams) {
const args = (callBack && callBack(renderOpts, params)) ?? {};
const { data, property, $form } = params;
const { name } = renderOpts;
const { attrs } = renderOpts;
const itemValue = XEUtils.get(data, property);
const Component = getComponent(name);
return [
h(Component, {
...attrs,
...createProps(renderOpts, itemValue, defaultProps),
...args,
...createEvents(
renderOpts,
params,
(value: any) => {
// 处理 model 值双向绑定
XEUtils.set(data, property, value);
},
() => {
// 处理 change 事件相关逻辑
$form.updateStatus({
...params,
field: property,
});
},
),
}),
];
};
}
/**
* @description: cell渲染
*/
export function createCellRender(
getSelectCellValue: Function,
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
) => Array<any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderCellOptions,
params: VxeGlobalRendererHandles.RenderCellParams,
) {
const args = (callBack && callBack(renderOpts, params)) ?? [];
const cellLabel = getSelectCellValue && getSelectCellValue(renderOpts, params, ...args);
const { placeholder } = renderOpts;
return [
h(
'span',
{
class: 'vxe-cell--label',
},
placeholder && isEmptyValue(cellLabel)
? [
h(
'span',
{
class: 'vxe-cell--placeholder',
},
formatText(placeholder),
),
]
: formatText(cellLabel),
),
];
};
}
/**
* @description:
* @param {}
* @return {*}
* @author: *
*/
export function createExportMethod(
getExportCellValue: Function,
callBack?: (params: VxeGlobalRendererHandles.ExportMethodParams) => Array<any>,
) {
return function (params: VxeGlobalRendererHandles.ExportMethodParams) {
const { row, column, options } = params;
const args = (callBack && callBack(params)) ?? [];
return options && options.original
? XEUtils.get(row, column.field as string)
: getExportCellValue(column.editRender || column.cellRender, params, ...args);
};
}
/**
* @description:
*/
export function createToolbarToolRender(
defaultProps?: { [key: string]: any },
callBack?: (
renderOpts: VxeGlobalRendererHandles.RenderToolOptions,
params: VxeGlobalRendererHandles.RenderToolParams,
) => Record<string, any>,
) {
return function (
renderOpts: VxeGlobalRendererHandles.RenderToolOptions,
params: VxeGlobalRendererHandles.RenderToolParams,
) {
const { name, attrs } = renderOpts;
const args = (callBack && callBack(renderOpts, params)) ?? {};
const Component = getComponent(name);
return [
h(Component, {
...attrs,
...createProps(renderOpts, null, defaultProps),
...args,
...createEvents(renderOpts, params),
}),
];
};
}

112
apps/vue/src/components/VxeTable/src/components/index.tsx

@ -0,0 +1,112 @@
import { VXETableCore, VxeGlobalInterceptorHandles } from 'vxe-table';
import AAutoComplete from './AAutoComplete';
import AInput from './AInput';
import AInputNumber from './AInputNumber';
import ASelect from './ASelect';
import ACascader from './ACascader';
import ADatePicker from './ADatePicker';
import AMonthPicker from './AMonthPicker';
import ARangePicker from './ARangePicker';
import AWeekPicker from './AWeekPicker';
import ATreeSelect from './ATreeSelect';
import ATimePicker from './ATimePicker';
import ARate from './ARate';
import ASwitch from './ASwitch';
import ARadioGroup from './ARadioGroup';
import ACheckboxGroup from './ACheckboxGroup';
import AButton from './AButton';
import AButtonGroup from './AButtonGroup';
import AApiSelect from './AApiSelect';
import AEmpty from './AEmpty';
import AInputSearch from './AInputSearch';
import AYearPicker from './AYearPicker';
/**
*
*/
function getEventTargetNode(evnt: any, container: HTMLElement, className: string) {
let targetElem;
let target = evnt.target;
while (target && target.nodeType && target !== document) {
if (
className &&
target.className &&
target.className.split &&
target.className.split(' ').indexOf(className) > -1
) {
targetElem = target;
} else if (target === container) {
return { flag: className ? !!targetElem : true, container, targetElem: targetElem };
}
target = target.parentNode;
}
return { flag: false };
}
/**
*
*/
function handleClearEvent(
params:
| VxeGlobalInterceptorHandles.InterceptorClearFilterParams
| VxeGlobalInterceptorHandles.InterceptorClearActivedParams
| VxeGlobalInterceptorHandles.InterceptorClearAreasParams,
) {
const { $event } = params;
const bodyElem = document.body;
if (
// 下拉框
getEventTargetNode($event, bodyElem, 'ant-select-dropdown').flag ||
// 级联
getEventTargetNode($event, bodyElem, 'ant-cascader-menus').flag ||
// 日期
getEventTargetNode($event, bodyElem, 'ant-calendar-picker-container').flag ||
// 时间选择
getEventTargetNode($event, bodyElem, 'ant-time-picker-panel').flag
) {
return false;
}
}
/**
* vxe-table ant-design-vue
*/
export const VXETablePluginAntd = {
install(vxetablecore: VXETableCore) {
const { interceptor, renderer } = vxetablecore;
renderer.mixin({
AAutoComplete,
AInput,
AInputNumber,
ASelect,
ACascader,
ADatePicker,
AMonthPicker,
ARangePicker,
AWeekPicker,
ATimePicker,
ATreeSelect,
ARate,
ASwitch,
ARadioGroup,
ACheckboxGroup,
AButton,
AButtonGroup,
AApiSelect,
AEmpty,
AInputSearch,
AYearPicker,
});
interceptor.add('event.clearFilter', handleClearEvent);
interceptor.add('event.clearActived', handleClearEvent);
interceptor.add('event.clearAreas', handleClearEvent);
},
};
if (typeof window !== 'undefined' && window.VXETable && window.VXETable.use) {
window.VXETable.use(VXETablePluginAntd);
}
export default VXETablePluginAntd;

4
apps/vue/src/components/VxeTable/src/const.ts

@ -0,0 +1,4 @@
/**
* @description: vxe-table prop
*/
export const ignorePropKeys = ['tableClass', 'tableStyle'];

8
apps/vue/src/components/VxeTable/src/css/common.scss

@ -0,0 +1,8 @@
*,
::before,
::after {
box-sizing: border-box;
border-width: 0;
border-style: solid;
border-color: initial;
}

105
apps/vue/src/components/VxeTable/src/css/component.scss

@ -0,0 +1,105 @@
%ResetBorder {
border: 0;
box-shadow: none;
}
%CompWidth {
& > .ant-input,
& > .ant-input-number,
& > .ant-select,
& > .ant-cascader-picker,
& > .ant-calendar-picker,
& > .ant-time-picker {
width: 100%;
}
}
.vxe-form {
.vxe-form--item-content {
@extend %CompWidth;
}
}
.vxe-table--filter-antd-wrapper {
& > .ant-input,
& > .ant-input-number,
& > .ant-select,
& > .ant-rate {
width: 180px;
}
}
.vxe-cell,
.vxe-tree-cell {
@extend %CompWidth;
& > .ant-rate {
vertical-align: bottom;
.anticon-star {
display: block;
}
}
}
.col--valid-error {
& > .vxe-cell,
& > .vxe-tree-cell {
& > .ant-input,
& > .ant-select .ant-input,
& > .ant-select .ant-select-selection,
& > .ant-input-number,
& > .ant-cascader-picker .ant-cascader-input,
& > .ant-calendar-picker .ant-calendar-picker-input {
// border-color: $vxe-table-validate-error-color;
box-shadow: none;
}
}
}
.vxe-table.cell--highlight {
.vxe-cell,
.vxe-tree-cell {
& > .ant-input,
& > .ant-input-number {
padding: 0;
@extend %ResetBorder;
}
& > .ant-select {
.ant-input {
padding: 0;
@extend %ResetBorder;
}
}
& > .ant-input-number {
.ant-input-number-input {
padding: 0;
}
.ant-input-number-handler-wrap,
.ant-input-number-handler-down {
@extend %ResetBorder;
}
}
& > .ant-select {
.ant-select-selection {
@extend %ResetBorder;
.ant-select-selection__rendered {
margin: 0;
}
}
}
& > .ant-cascader-picker {
.ant-input {
@extend %ResetBorder;
}
.ant-cascader-picker-label {
padding: 0;
}
}
& > .ant-calendar-picker {
.ant-calendar-picker-input {
padding: 0;
@extend %ResetBorder;
}
}
& > .ant-time-picker {
.ant-time-picker-input {
padding: 0;
@extend %ResetBorder;
}
}
}
}

6
apps/vue/src/components/VxeTable/src/css/index.scss

@ -0,0 +1,6 @@
@import './common.scss';
@import './variable.scss';
@import './scrollbar.scss';
@import './toolbar.scss';
@import './component.scss';
@import 'vxe-table/styles/index.scss';

24
apps/vue/src/components/VxeTable/src/css/scrollbar.scss

@ -0,0 +1,24 @@
.vxe-grid_scrollbar {
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background-color: #ffffff;
}
::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.1);
border-radius: 5px;
border: 1px solid #f1f1f1;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}
::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
::-webkit-scrollbar-thumb:active {
background-color: #a8a8a8;
}
::-webkit-scrollbar-corner {
background-color: #ffffff;
}
}

30
apps/vue/src/components/VxeTable/src/css/toolbar.scss

@ -0,0 +1,30 @@
.vxe-toolbar .vxe-custom--option-wrapper .vxe-custom--footer {
display: flex;
}
.vxe-toolbar .vxe-tools--wrapper,
.vxe-toolbar .vxe-tools--operate button:first-child {
margin: 0;
}
.vxe-toolbar .vxe-tools--wrapper,
.vxe-toolbar .vxe-tools--operate .vxe-button {
margin-left: 1px;
border-radius: 0 !important;
}
.vxe-toolbar .vxe-tools--wrapper,
.vxe-toolbar .vxe-tools--operate button:first-child {
margin-left: 10px;
}
.vxe-toolbar .vxe-tools--wrapper,
.vxe-toolbar .vxe-tools--operate .vxe-custom--wrapper {
margin-left: 1px;
border-radius: 0 !important;
}
.vxe-toolbar .vxe-tools--wrapper,
.vxe-toolbar .vxe-tools--operate .vxe-custom--wrapper .vxe-button {
margin-left: 1px;
}

6
apps/vue/src/components/VxeTable/src/css/variable.scss

@ -0,0 +1,6 @@
$vxe-primary-color: rgb(9, 96, 189) !default;
$vxe-table-row-current-background-color: rgba(9, 96, 189, 0.3);
$vxe-table-row-hover-current-background-color: rgba(9, 96, 189, 0.2);
$vxe-table-column-hover-background-color: rgba(9, 96, 189, 0.3);
$vxe-table-column-current-background-color: rgba(9, 96, 189, 0.2);
$vxe-table-validate-error-color: #f56c6c;

17
apps/vue/src/components/VxeTable/src/emits.ts

@ -0,0 +1,17 @@
import tableEmits from 'vxe-table/es/table/src/emits';
export const basicEmits = [
...tableEmits,
'page-change',
'form-submit',
'form-submit-invalid',
'form-reset',
'form-collapse',
'form-toggle-collapse',
'toolbar-button-click',
'toolbar-tool-click',
'zoom',
//... 如有缺少在此处追加
// xxx
];

19
apps/vue/src/components/VxeTable/src/helper.ts

@ -0,0 +1,19 @@
import { ComponentType } from './componentType';
import { useI18n } from '/@/hooks/web/useI18n';
const { t } = useI18n();
/**
* @description: placeholder
*/
export function createPlaceholderMessage(component: ComponentType) {
if (!component) return;
if (component.includes('RangePicker')) {
return [t('common.chooseText'), t('common.chooseText')];
}
if (component.includes('Input') || component.includes('Complete') || component.includes('Rate')) {
return t('common.inputText');
} else {
return t('common.chooseText');
}
}

131
apps/vue/src/components/VxeTable/src/methods.ts

@ -0,0 +1,131 @@
import { GridMethods, TableMethods } from 'vxe-table';
export const gridComponentMethodKeys: (keyof GridMethods | keyof TableMethods)[] = [
// vxe-grid 部分
'dispatchEvent',
'commitProxy',
'getFormItems',
'getPendingRecords',
'zoom',
'isMaximized',
'maximize',
'revert',
'getProxyInfo',
// vxe-table和vxe-grid公共部分
'clearAll',
'syncData',
'updateData',
'loadData',
'reloadData',
'reloadRow',
'loadColumn',
'reloadColumn',
'getRowNode',
'getColumnNode',
'getRowIndex',
'getVTRowIndex',
'getVMRowIndex',
'getColumnIndex',
'getVTColumnIndex',
'getVMColumnIndex',
'createData',
'createRow',
'revertData',
'clearData',
'isInsertByRow',
'isUpdateByRow',
'getColumns',
'getColumnById',
'getColumnByField',
'getTableColumn',
'getData',
'getCheckboxRecords',
'getParentRow',
'getRowSeq',
'getRowById',
'getRowid',
'getTableData',
'hideColumn',
'showColumn',
'resetColumn',
'refreshColumn',
'refreshScroll',
'recalculate',
'closeTooltip',
'isAllCheckboxChecked',
'isAllCheckboxIndeterminate',
'getCheckboxIndeterminateRecords',
'setCheckboxRow',
'isCheckedByCheckboxRow',
'isIndeterminateByCheckboxRow',
'toggleCheckboxRow',
'setAllCheckboxRow',
'getRadioReserveRecord',
'clearRadioReserve',
'getCheckboxReserveRecords',
'clearCheckboxReserve',
'toggleAllCheckboxRow',
'clearCheckboxRow',
'setCurrentRow',
'isCheckedByRadioRow',
'setRadioRow',
'clearCurrentRow',
'clearRadioRow',
'getCurrentRecord',
'getRadioRecord',
'getCurrentColumn',
'setCurrentColumn',
'clearCurrentColumn',
'sort',
'clearSort',
'isSort',
'getSortColumns',
'closeFilter',
'isFilter',
'isRowExpandLoaded',
'clearRowExpandLoaded',
'reloadRowExpand',
'reloadRowExpand',
'toggleRowExpand',
'setAllRowExpand',
'setRowExpand',
'isExpandByRow',
'clearRowExpand',
'clearRowExpandReserve',
'getRowExpandRecords',
'getTreeExpandRecords',
'isTreeExpandLoaded',
'clearTreeExpandLoaded',
'reloadTreeExpand',
'reloadTreeChilds',
'toggleTreeExpand',
'setAllTreeExpand',
'setTreeExpand',
'isTreeExpandByRow',
'clearTreeExpand',
'clearTreeExpandReserve',
'getScroll',
'scrollTo',
'scrollToRow',
'scrollToColumn',
'clearScroll',
'updateFooter',
'updateStatus',
'setMergeCells',
'removeInsertRow',
'removeMergeCells',
'getMergeCells',
'clearMergeCells',
'setMergeFooterItems',
'removeMergeFooterItems',
'getMergeFooterItems',
'clearMergeFooterItems',
'openTooltip',
'focus',
'blur',
'connect',
//... 如有缺少在此处追加
// xxx
];

52
apps/vue/src/components/VxeTable/src/props.ts

@ -0,0 +1,52 @@
import { VxeGridPropTypes, VxeTablePropTypes } from 'vxe-table';
import tableProps from 'vxe-table/es/table/src/props';
import { CSSProperties } from 'vue';
/**
* @description: table二次开发需要后prop属性
*/
export const basicProps = {
...tableProps,
columns: Array as PropType<VxeGridPropTypes.Columns>,
pagerConfig: {
type: Object as PropType<VxeGridPropTypes.PagerConfig>,
default: () => ({}),
},
proxyConfig: {
type: Object as PropType<VxeGridPropTypes.ProxyConfig>,
default: () => ({}),
},
toolbarConfig: {
type: Object as PropType<VxeGridPropTypes.ToolbarConfig>,
default: () => ({}),
},
formConfig: {
type: Object as PropType<VxeGridPropTypes.FormConfig>,
default: () => ({}),
},
zoomConfig: {
type: Object as PropType<VxeGridPropTypes.ZoomConfig>,
default: () => ({}),
},
printConfig: {
type: Object as PropType<VxeTablePropTypes.PrintConfig>,
default: () => ({}),
},
exportConfig: {
type: Object as PropType<VxeTablePropTypes.ExportConfig>,
default: () => ({}),
},
importConfig: {
type: Object as PropType<VxeTablePropTypes.ImportConfig>,
default: () => ({}),
},
size: String as PropType<VxeGridPropTypes.Size>,
tableClass: {
type: String,
default: '',
},
tableStyle: {
type: Object as PropType<CSSProperties>,
default: () => ({}),
},
};

4
apps/vue/src/components/VxeTable/src/setting.ts

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

7
apps/vue/src/components/VxeTable/src/types.ts

@ -0,0 +1,7 @@
import { CSSProperties } from 'vue';
import { VxeGridProps } from 'vxe-table';
export type BasicTableProps = VxeGridProps & {
tableClass?: string;
tableStyle?: CSSProperties;
};

3
apps/vue/src/components/registerGlobComp.ts

@ -56,6 +56,7 @@ import {
Input as AInput,
InputNumber as AInputNumber,
} from 'ant-design-vue';
import VXETable from 'vxe-table';
const compList = [
Affix,
@ -157,5 +158,5 @@ export function registerGlobComp(app: App) {
app.component(comp.name || comp.displayName, comp);
});
app.use(Input).use(Button).use(Layout);
app.use(Input).use(Button).use(Layout).use(VXETable);
}

14
apps/vue/src/hooks/component/useFormItem.ts

@ -1,13 +1,5 @@
import type { UnwrapRef, Ref, WritableComputedRef, DeepReadonly } from 'vue';
import {
reactive,
readonly,
computed,
getCurrentInstance,
watchEffect,
unref,
toRaw,
} from 'vue';
import { reactive, readonly, computed, getCurrentInstance, watchEffect, unref, toRaw } from 'vue';
import { isEqual } from 'lodash-es';
@ -49,7 +41,9 @@ export function useRuleFormItem<T extends Recordable>(
if (isEqual(value, defaultState.value)) return;
innerState.value = value as T[keyof T];
emit?.(changeEvent, value, ...(toRaw(unref(emitData)) || []));
setTimeout(() => {
emit?.(changeEvent, value, ...(toRaw(unref(emitData)) || []));
});
},
});

2
apps/vue/src/hooks/web/usePermission.ts

@ -30,7 +30,7 @@ export function usePermission() {
async function togglePermissionMode() {
appStore.setProjectConfig({
permissionMode:
projectSetting.permissionMode === PermissionModeEnum.BACK
appStore.projectConfig?.permissionMode === PermissionModeEnum.BACK
? PermissionModeEnum.ROUTE_MAPPING
: PermissionModeEnum.BACK,
});

6
apps/vue/src/layouts/page/index.vue

@ -15,9 +15,11 @@
appear
>
<keep-alive v-if="openCache" :include="getCaches">
<component :is="Component" :key="route.fullPath" />
<div :key="route.name!">
<component :is="Component" :key="route.fullPath" />
</div>
</keep-alive>
<div v-else :key="route.name">
<div v-else :key="route.name!">
<component :is="Component" :key="route.fullPath" />
</div>
</transition>

1
apps/vue/src/main.ts

@ -1,6 +1,7 @@
import 'virtual:windi-base.css';
import 'virtual:windi-components.css';
import '/@/design/index.less';
import '/@/components/VxeTable/src/css/index.scss';
import 'virtual:windi-utilities.css';
// Register icon sprite
import 'virtual:svg-icons-register';

14
apps/vue/src/router/menus/index.ts

@ -53,11 +53,21 @@ const staticMenus: Menu[] = [];
async function getAsyncMenus() {
const permissionStore = usePermissionStore();
//递归过滤所有隐藏的菜单
const menuFilter = (items) => {
return items.filter((item) => {
const show = !item.meta?.hideMenu && !item.hideMenu;
if (show && item.children) {
item.children = menuFilter(item.children);
}
return show;
});
};
if (isBackMode()) {
return permissionStore.getBackMenuList.filter((item) => !item.meta?.hideMenu && !item.hideMenu);
return menuFilter(permissionStore.getBackMenuList);
}
if (isRouteMappingMode()) {
return permissionStore.getFrontMenuList.filter((item) => !item.hideMenu);
return menuFilter(permissionStore.getFrontMenuList);
}
return staticMenus;
}

46
apps/vue/src/settings/componentSetting.ts

@ -52,6 +52,52 @@ export default {
return data;
},
},
vxeTable: {
table: {
border: true,
stripe: true,
columnConfig: {
resizable: true,
isCurrent: true,
isHover: true,
},
rowConfig: {
isCurrent: true,
isHover: true,
},
emptyRender: {
name: 'AEmpty',
},
printConfig: {},
exportConfig: {},
customConfig: {
storage: true,
},
},
grid: {
toolbarConfig: {
enabled: true,
export: true,
zoom: true,
print: true,
refresh: true,
custom: true,
},
pagerConfig: {
pageSizes: [20, 50, 100, 500],
pageSize: 20,
autoHidden: true,
},
proxyConfig: {
form: true,
props: {
result: 'items',
total: 'total',
},
},
zoomConfig: {},
},
},
// scrollbar setting
scrollbar: {
// Whether to use native scroll bar

2
apps/vue/src/utils/index.ts

@ -35,7 +35,7 @@ export function setObjToUrlParams(baseUrl: string, obj: any): string {
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
let key: string;
const res: any = cloneDeep(src)
const res: any = cloneDeep(src);
for (key in target) {
res[key] = isObject(res[key]) ? deepMerge(res[key], target[key]) : (res[key] = target[key]);
}

2
apps/vue/src/views/identity/user/components/UserTable.vue

@ -12,7 +12,7 @@
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'userName'">
<span>{{ record.userName }}</span>
<Tag v-if="!lockEnable(record)" style="margin-left: 5px" color="orange">{{ L('Lockout') }}</Tag>
<Tag v-if="lockEnable(record)" style="margin-left: 5px" color="orange">{{ L('Lockout') }}</Tag>
<Tag v-if="!record.isActive" style="margin-left: 5px" color="red">{{ L('UnActived') }}</Tag>
</template>
<template v-if="column.key === 'phoneNumber'">

15
apps/vue/src/views/identity/user/hooks/useUserTable.ts

@ -36,18 +36,15 @@ export function useUserTable() {
const lockEnable = computed(() => {
return (record) => {
// 未启用锁定不显示
if (!record.lockoutEnabled) {
return false;
}
if (record.lockoutEnd) {
// 锁定时间高于当前时间不显示
if (record.lockoutEnabled === true) {
const lockTime = new Date(record.lockoutEnd);
const nowTime = new Date();
if (lockTime > nowTime) {
return false;
if (lockTime) {
// 锁定时间高于当前时间不显示
const nowTime = new Date();
return lockTime > nowTime;
}
}
return true;
return false;
};
});

Loading…
Cancel
Save