chore: marge main
parent
73a580af70
commit
84a4db58a9
|
|
@ -21,7 +21,7 @@ const inputRef = ref<Nullable<HTMLElement>>(null)
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { prefixCls } = useDesign('app-search-modal')
|
const { prefixCls } = useDesign('app-search-modal')
|
||||||
const [refs, setRefs] = useRefs()
|
const { refs, setRefs } = useRefs()
|
||||||
const { getIsMobile } = useAppInject()
|
const { getIsMobile } = useAppInject()
|
||||||
|
|
||||||
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } = useMenuSearch(refs, scrollWrap, emit)
|
const { handleSearch, searchResult, keyword, activeIndex, handleEnter, handleMouseenter } = useMenuSearch(refs, scrollWrap, emit)
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,17 @@ import FormItem from './components/FormItem.vue'
|
||||||
import FormAction from './components/FormAction.vue'
|
import FormAction from './components/FormAction.vue'
|
||||||
|
|
||||||
import { dateItemType } from './helper'
|
import { dateItemType } from './helper'
|
||||||
|
|
||||||
import { useFormValues } from './hooks/useFormValues'
|
import { useFormValues } from './hooks/useFormValues'
|
||||||
import useAdvanced from './hooks/useAdvanced'
|
import useAdvanced from './hooks/useAdvanced'
|
||||||
import { useFormEvents } from './hooks/useFormEvents'
|
import { useFormEvents } from './hooks/useFormEvents'
|
||||||
import { createFormContext } from './hooks/useFormContext'
|
import { createFormContext } from './hooks/useFormContext'
|
||||||
import { useAutoFocus } from './hooks/useAutoFocus'
|
import { useAutoFocus } from './hooks/useAutoFocus'
|
||||||
import { basicProps } from './props'
|
import { basicProps } from './props'
|
||||||
import { dateUtil } from '@/utils/dateUtil'
|
|
||||||
|
|
||||||
import { deepMerge } from '@/utils'
|
|
||||||
|
|
||||||
import { useModalContext } from '@/components/Modal'
|
import { useModalContext } from '@/components/Modal'
|
||||||
|
|
||||||
|
import { deepMerge } from '@/utils'
|
||||||
|
import { dateUtil } from '@/utils/dateUtil'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
defineOptions({ name: 'BasicForm' })
|
defineOptions({ name: 'BasicForm' })
|
||||||
|
|
@ -30,7 +29,7 @@ defineOptions({ name: 'BasicForm' })
|
||||||
const props = defineProps(basicProps)
|
const props = defineProps(basicProps)
|
||||||
const emit = defineEmits(['advanced-change', 'reset', 'submit', 'register', 'field-value-change'])
|
const emit = defineEmits(['advanced-change', 'reset', 'submit', 'register', 'field-value-change'])
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
const formModel = reactive<Recordable>({})
|
const formModel = reactive({})
|
||||||
const modalFn = useModalContext()
|
const modalFn = useModalContext()
|
||||||
|
|
||||||
const advanceState = reactive<AdvanceState>({
|
const advanceState = reactive<AdvanceState>({
|
||||||
|
|
@ -40,11 +39,11 @@ const advanceState = reactive<AdvanceState>({
|
||||||
actionSpan: 6,
|
actionSpan: 6,
|
||||||
})
|
})
|
||||||
|
|
||||||
const defaultValueRef = ref<Recordable>({})
|
const defaultValueRef = ref({})
|
||||||
const isInitedDefaultRef = ref(false)
|
const isInitedDefaultRef = ref(false)
|
||||||
const propsRef = ref<Partial<FormProps>>()
|
const propsRef = ref<Partial<FormProps>>()
|
||||||
const schemaRef = ref<Nullable<FormSchema[]>>(null)
|
const schemaRef = ref<FormSchema[] | null>(null)
|
||||||
const formElRef = ref<Nullable<FormActionType>>(null)
|
const formElRef = ref<FormActionType | null>(null)
|
||||||
|
|
||||||
const { prefixCls } = useDesign('basic-form')
|
const { prefixCls } = useDesign('basic-form')
|
||||||
|
|
||||||
|
|
@ -63,7 +62,7 @@ const getFormClass = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get uniform row style and Row configuration for the entire form
|
// Get uniform row style and Row configuration for the entire form
|
||||||
const getRow = computed((): Recordable => {
|
const getRow = computed(() => {
|
||||||
const { baseRowStyle = {}, rowProps } = unref(getProps)
|
const { baseRowStyle = {}, rowProps } = unref(getProps)
|
||||||
return {
|
return {
|
||||||
style: baseRowStyle,
|
style: baseRowStyle,
|
||||||
|
|
@ -85,10 +84,14 @@ const getSchema = computed((): FormSchema[] => {
|
||||||
isHandleDateDefaultValue = true,
|
isHandleDateDefaultValue = true,
|
||||||
} = schema
|
} = schema
|
||||||
|
|
||||||
// eslint-disable-next-line dot-notation
|
const valueFormat = componentProps ? componentProps.valueFormat : null
|
||||||
const valueFormat = componentProps ? componentProps['valueFormat'] : null
|
|
||||||
// handle date type
|
// handle date type
|
||||||
if (isHandleDateDefaultValue && defaultValue && component && dateItemType.includes(component)) {
|
if (
|
||||||
|
isHandleDateDefaultValue
|
||||||
|
&& defaultValue
|
||||||
|
&& component
|
||||||
|
&& dateItemType.includes(component)
|
||||||
|
) {
|
||||||
if (!Array.isArray(defaultValue)) {
|
if (!Array.isArray(defaultValue)) {
|
||||||
schema.defaultValue = valueFormat
|
schema.defaultValue = valueFormat
|
||||||
? dateUtil(defaultValue).format(valueFormat)
|
? dateUtil(defaultValue).format(valueFormat)
|
||||||
|
|
@ -97,16 +100,20 @@ const getSchema = computed((): FormSchema[] => {
|
||||||
else {
|
else {
|
||||||
const def: any[] = []
|
const def: any[] = []
|
||||||
defaultValue.forEach((item) => {
|
defaultValue.forEach((item) => {
|
||||||
def.push(dateUtil(item))
|
def.push(valueFormat ? dateUtil(item).format(valueFormat) : dateUtil(item))
|
||||||
})
|
})
|
||||||
schema.defaultValue = def
|
schema.defaultValue = def
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (unref(getProps).showAdvancedButton)
|
if (unref(getProps).showAdvancedButton) {
|
||||||
return cloneDeep(schemas.filter(schema => schema.component !== 'Divider') as FormSchema[])
|
return cloneDeep(
|
||||||
else
|
schemas.filter(schema => schema.component !== 'Divider') as FormSchema[],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
return cloneDeep(schemas as FormSchema[])
|
return cloneDeep(schemas as FormSchema[])
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
|
const { handleToggleAdvanced, fieldsIsAdvancedMap } = useAdvanced({
|
||||||
|
|
@ -215,7 +222,7 @@ function setFormModel(key: string, value: any, schema: FormSchema) {
|
||||||
emit('field-value-change', key, value)
|
emit('field-value-change', key, value)
|
||||||
// TODO 优化验证,这里如果是autoLink=false手动关联的情况下才会再次触发此函数
|
// TODO 优化验证,这里如果是autoLink=false手动关联的情况下才会再次触发此函数
|
||||||
if (schema && schema.itemProps && !schema.itemProps.autoLink)
|
if (schema && schema.itemProps && !schema.itemProps.autoLink)
|
||||||
validateFields([key]).catch((_) => { })
|
validateFields([key]).catch((_) => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleEnterPress(e: KeyboardEvent) {
|
function handleEnterPress(e: KeyboardEvent) {
|
||||||
|
|
@ -254,14 +261,25 @@ const getFormActionBindProps = computed(() => ({ ...getProps.value, ...advanceSt
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Form v-bind="getBindValue" ref="formElRef" :class="getFormClass" :model="formModel" @keypress.enter="handleEnterPress">
|
<Form
|
||||||
|
v-bind="getBindValue"
|
||||||
|
ref="formElRef"
|
||||||
|
:class="getFormClass"
|
||||||
|
:model="formModel"
|
||||||
|
@keypress.enter="handleEnterPress"
|
||||||
|
>
|
||||||
<Row v-bind="getRow">
|
<Row v-bind="getRow">
|
||||||
<slot name="formHeader" />
|
<slot name="formHeader" />
|
||||||
<template v-for="schema in getSchema" :key="schema.field">
|
<template v-for="schema in getSchema" :key="schema.field">
|
||||||
<FormItem
|
<FormItem
|
||||||
:is-advanced="fieldsIsAdvancedMap[schema.field]" :table-action="tableAction"
|
:is-advanced="fieldsIsAdvancedMap[schema.field]"
|
||||||
:form-action-type="formActionType as any" :schema="schema" :form-props="getProps"
|
:table-action="tableAction"
|
||||||
:all-default-values="defaultValueRef" :form-model="formModel" :set-form-model="setFormModel"
|
:form-action-type="formActionType"
|
||||||
|
:schema="schema"
|
||||||
|
:form-props="getProps"
|
||||||
|
:all-default-values="defaultValueRef"
|
||||||
|
:form-model="formModel"
|
||||||
|
:set-form-model="setFormModel"
|
||||||
>
|
>
|
||||||
<template v-for="item in Object.keys($slots)" #[item]="data">
|
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
|
|
@ -270,7 +288,10 @@ const getFormActionBindProps = computed(() => ({ ...getProps.value, ...advanceSt
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
|
<FormAction v-bind="getFormActionBindProps" @toggle-advanced="handleToggleAdvanced">
|
||||||
<template v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']" #[item]="data">
|
<template
|
||||||
|
v-for="item in ['resetBefore', 'submitBefore', 'advanceBefore', 'advanceAfter']"
|
||||||
|
#[item]="data"
|
||||||
|
>
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
</template>
|
</template>
|
||||||
</FormAction>
|
</FormAction>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { ref, unref, watch, watchEffect } from 'vue'
|
import { ref, unref, watch, watchEffect } from 'vue'
|
||||||
import { Cascader } from 'ant-design-vue'
|
import { Cascader } from 'ant-design-vue'
|
||||||
import { get, omit } from 'lodash-es'
|
import { get, omit } from 'lodash-es'
|
||||||
|
|
@ -8,12 +9,22 @@ import { isFunction } from '@/utils/is'
|
||||||
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
loading?: boolean
|
||||||
|
isLeaf?: boolean
|
||||||
|
children?: Option[]
|
||||||
|
}
|
||||||
|
|
||||||
defineOptions({ name: 'ApiCascader' })
|
defineOptions({ name: 'ApiCascader' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: propTypes.array.def([]),
|
value: {
|
||||||
|
type: Array,
|
||||||
|
},
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(arg?: Recordable) => Promise<Option[]>>,
|
type: Function as PropType<(arg?: Recordable<any>) => Promise<Option[]>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
numberToString: propTypes.bool.def(false),
|
numberToString: propTypes.bool.def(false),
|
||||||
|
|
@ -25,38 +36,28 @@ const props = defineProps({
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
// init fetch params
|
// init fetch params
|
||||||
initFetchParams: {
|
initFetchParams: {
|
||||||
type: Object as PropType<Recordable>,
|
type: Object as PropType<Recordable<any>>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
// 是否有下级,默认是
|
// 是否有下级,默认是
|
||||||
isLeaf: {
|
isLeaf: {
|
||||||
type: Function as PropType<(arg: Recordable) => boolean>,
|
type: Function as PropType<(arg: Recordable<any>) => boolean>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
displayRenderArray: {
|
displayRenderArray: {
|
||||||
type: Array,
|
type: Array,
|
||||||
},
|
},
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['change', 'defaultChange'])
|
const emit = defineEmits(['change', 'defaultChange'])
|
||||||
|
|
||||||
interface Option {
|
|
||||||
value: string
|
|
||||||
label: string
|
|
||||||
loading?: boolean
|
|
||||||
isLeaf?: boolean
|
|
||||||
children?: Option[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiData = ref<any[]>([])
|
const apiData = ref<any[]>([])
|
||||||
const options = ref<Option[]>([])
|
const options = ref<Option[]>([])
|
||||||
const loading = ref<boolean>(false)
|
const loading = ref<boolean>(false)
|
||||||
const emitData = ref<any[]>([])
|
const emitData = ref<any[]>([])
|
||||||
const isFirstLoad = ref(false)
|
const isFirstLoad = ref(true)
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// Embedded in the form, just use the hook binding to perform form verification
|
||||||
const [state]: any = useRuleFormItem(props, 'value', 'change', emitData)
|
const [state]: any[] = useRuleFormItem(props, 'value', 'change', emitData)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
apiData,
|
apiData,
|
||||||
|
|
@ -69,7 +70,7 @@ watch(
|
||||||
|
|
||||||
function generatorOptions(options: any[]): Option[] {
|
function generatorOptions(options: any[]): Option[] {
|
||||||
const { labelField, valueField, numberToString, childrenField, isLeaf } = props
|
const { labelField, valueField, numberToString, childrenField, isLeaf } = props
|
||||||
return options.reduce((prev, next: Recordable) => {
|
return options.reduce((prev, next: Recordable<any>) => {
|
||||||
if (next) {
|
if (next) {
|
||||||
const value = next[valueField]
|
const value = next[valueField]
|
||||||
const item = {
|
const item = {
|
||||||
|
|
@ -147,17 +148,13 @@ watchEffect(() => {
|
||||||
watch(
|
watch(
|
||||||
() => props.initFetchParams,
|
() => props.initFetchParams,
|
||||||
() => {
|
() => {
|
||||||
if (props.alwaysLoad)
|
!unref(isFirstLoad) && initialFetch()
|
||||||
initialFetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
!unref(isFirstLoad) && initialFetch()
|
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
function handleChange(keys, args) {
|
function handleChange(keys, args) {
|
||||||
emitData.value = keys
|
emitData.value = args
|
||||||
emit('defaultChange', keys, args)
|
emit('defaultChange', keys, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,8 +171,12 @@ function handleRenderDisplay({ labels, selectedOptions }) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Cascader
|
<Cascader
|
||||||
v-model:value="state" :options="options" :load-data="loadData" change-on-select
|
v-model:value="state"
|
||||||
:display-render="handleRenderDisplay" @change="handleChange"
|
:options="options"
|
||||||
|
:load-data="loadData"
|
||||||
|
change-on-select
|
||||||
|
:display-render="handleRenderDisplay"
|
||||||
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<template v-if="loading" #suffixIcon>
|
<template v-if="loading" #suffixIcon>
|
||||||
<LoadingOutlined spin />
|
<LoadingOutlined spin />
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
|
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
|
||||||
-->
|
-->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, ref, unref, watch, watchEffect } from 'vue'
|
import { computed, ref, unref, watch, watchEffect } from 'vue'
|
||||||
import { Radio } from 'ant-design-vue'
|
import { Radio } from 'ant-design-vue'
|
||||||
import { get, omit } from 'lodash-es'
|
import { get, omit } from 'lodash-es'
|
||||||
|
|
@ -10,47 +11,49 @@ import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
||||||
import { useAttrs } from '@/hooks/core/useAttrs'
|
import { useAttrs } from '@/hooks/core/useAttrs'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
interface OptionsItem { label: string; value: string | number | boolean; disabled?: boolean }
|
||||||
|
|
||||||
defineOptions({ name: 'ApiRadioGroup' })
|
defineOptions({ name: 'ApiRadioGroup' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(arg?: Recordable | string) => Promise<OptionsItem[]>>,
|
type: Function as PropType<(arg?: any | string) => Promise<OptionsItem[]>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
type: [Object, String] as PropType<Recordable | string>,
|
type: [Object, String] as PropType<any | string>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: [String, Number, Boolean] as PropType<string | number | boolean>,
|
type: [String, Number, Boolean] as PropType<string | number | boolean>,
|
||||||
},
|
},
|
||||||
isBtn: propTypes.bool.def(false),
|
isBtn: {
|
||||||
|
type: [Boolean] as PropType<boolean>,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
numberToString: propTypes.bool,
|
numberToString: propTypes.bool,
|
||||||
resultField: propTypes.string.def(''),
|
resultField: propTypes.string.def(''),
|
||||||
labelField: propTypes.string.def('label'),
|
labelField: propTypes.string.def('label'),
|
||||||
valueField: propTypes.string.def('value'),
|
valueField: propTypes.string.def('value'),
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['optionsChange', 'change'])
|
const emit = defineEmits(['options-change', 'change'])
|
||||||
const RadioButton = Radio.Button
|
const RadioButton = Radio.Button
|
||||||
const RadioGroup = Radio.Group
|
const RadioGroup = Radio.Group
|
||||||
|
|
||||||
interface OptionsItem { label: string; value: string | number | boolean; disabled?: boolean }
|
|
||||||
|
|
||||||
const options = ref<OptionsItem[]>([])
|
const options = ref<OptionsItem[]>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const isFirstLoad = ref(true)
|
const isFirstLoad = ref(true)
|
||||||
const emitData = ref<any[]>([])
|
const emitData = ref<any[]>([])
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// 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
|
// Processing options value
|
||||||
const getOptions = computed(() => {
|
const getOptions = computed(() => {
|
||||||
const { labelField, valueField, numberToString } = props
|
const { labelField, valueField, numberToString } = props
|
||||||
|
|
||||||
return unref(options).reduce((prev, next: Recordable) => {
|
return unref(options).reduce((prev, next: any) => {
|
||||||
if (next) {
|
if (next) {
|
||||||
const value = next[valueField]
|
const value = next[valueField]
|
||||||
prev.push({
|
prev.push({
|
||||||
|
|
@ -70,11 +73,7 @@ watchEffect(() => {
|
||||||
watch(
|
watch(
|
||||||
() => props.params,
|
() => props.params,
|
||||||
() => {
|
() => {
|
||||||
if (props.alwaysLoad)
|
!unref(isFirstLoad) && fetch()
|
||||||
fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
!unref(isFirstLoad) && fetch()
|
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
@ -106,21 +105,26 @@ async function fetch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitChange() {
|
function emitChange() {
|
||||||
emit('optionsChange', unref(getOptions))
|
emit('options-change', unref(getOptions))
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(args) {
|
function handleClick(...args) {
|
||||||
emitData.value = args
|
emitData.value = args
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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}`">
|
<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 }}
|
{{ item.label }}
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
<Radio v-else :value="item.value" :disabled="item.disabled">
|
<Radio v-else :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</Radio>
|
</Radio>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,46 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, ref, unref, watch } from 'vue'
|
import { computed, ref, unref, watch } from 'vue'
|
||||||
import { Select } from 'ant-design-vue'
|
import { Select } from 'ant-design-vue'
|
||||||
|
import type { SelectValue } from 'ant-design-vue/es/select'
|
||||||
import { get, omit } from 'lodash-es'
|
import { get, omit } from 'lodash-es'
|
||||||
import { LoadingOutlined } from '@ant-design/icons-vue'
|
import { LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
import type { SelectValue } from 'ant-design-vue/lib/select'
|
|
||||||
import { isFunction } from '@/utils/is'
|
import { isFunction } from '@/utils/is'
|
||||||
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
interface OptionsItem { label: string; value: string; disabled?: boolean }
|
||||||
|
|
||||||
defineOptions({ name: 'ApiSelect', inheritAttrs: false })
|
defineOptions({ name: 'ApiSelect', inheritAttrs: false })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
|
value: { type: [Array, Object, String, Number] as PropType<SelectValue> },
|
||||||
numberToString: propTypes.bool,
|
numberToString: propTypes.bool,
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(arg?: Recordable) => Promise<OptionsItem[]>>,
|
type: Function as PropType<(arg?: any) => Promise<OptionsItem[]>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
// api params
|
// api params
|
||||||
params: {
|
params: propTypes.any.def({}),
|
||||||
type: Object as PropType<Recordable>,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
// support xxx.xxx.xx
|
// support xxx.xxx.xx
|
||||||
resultField: propTypes.string.def(''),
|
resultField: propTypes.string.def(''),
|
||||||
labelField: propTypes.string.def('label'),
|
labelField: propTypes.string.def('label'),
|
||||||
valueField: propTypes.string.def('value'),
|
valueField: propTypes.string.def('value'),
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
alwaysLoad: propTypes.bool.def(false),
|
||||||
options: {
|
options: {
|
||||||
type: Array<OptionsItem>,
|
type: Array<OptionsItem>,
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const emit = defineEmits(['options-change', 'change', 'update:value'])
|
||||||
const emit = defineEmits(['optionsChange', 'change', 'update:value'])
|
|
||||||
|
|
||||||
interface OptionsItem { label: string; value: string; disabled?: boolean }
|
|
||||||
|
|
||||||
const options = ref<OptionsItem[]>([])
|
const options = ref<OptionsItem[]>([])
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 首次是否加载过了
|
// 首次是否加载过了
|
||||||
const isFirstLoaded = ref(false)
|
const isFirstLoaded = ref(false)
|
||||||
const emitData = ref<OptionsItem[]>([])
|
const emitData = ref<OptionsItem[]>([])
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// Embedded in the form, just use the hook binding to perform form verification
|
||||||
|
|
@ -52,7 +49,7 @@ const [state] = useRuleFormItem(props, 'value', 'change', emitData)
|
||||||
const getOptions = computed(() => {
|
const getOptions = computed(() => {
|
||||||
const { labelField, valueField, numberToString } = props
|
const { labelField, valueField, numberToString } = props
|
||||||
|
|
||||||
return unref(options).reduce((prev, next: Recordable) => {
|
const data = unref(options).reduce((prev, next: any) => {
|
||||||
if (next) {
|
if (next) {
|
||||||
const value = get(next, valueField)
|
const value = get(next, valueField)
|
||||||
prev.push({
|
prev.push({
|
||||||
|
|
@ -63,6 +60,7 @@ const getOptions = computed(() => {
|
||||||
}
|
}
|
||||||
return prev
|
return prev
|
||||||
}, [] as OptionsItem[])
|
}, [] as OptionsItem[])
|
||||||
|
return data.length > 0 ? data : props.options
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
@ -75,11 +73,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
() => props.params,
|
() => props.params,
|
||||||
() => {
|
() => {
|
||||||
if (props.alwaysLoad)
|
!unref(isFirstLoaded) && fetch()
|
||||||
fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
!unref(isFirstLoaded) && fetch()
|
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: props.immediate },
|
{ deep: true, immediate: props.immediate },
|
||||||
)
|
)
|
||||||
|
|
@ -113,18 +107,15 @@ async function fetch() {
|
||||||
|
|
||||||
async function handleFetch(open: boolean) {
|
async function handleFetch(open: boolean) {
|
||||||
if (open) {
|
if (open) {
|
||||||
if (props.alwaysLoad) {
|
if (props.alwaysLoad)
|
||||||
await fetch()
|
await fetch()
|
||||||
}
|
else if (!props.immediate && !unref(isFirstLoaded))
|
||||||
else if (!props.immediate && !unref(isFirstLoaded)) {
|
|
||||||
await fetch()
|
await fetch()
|
||||||
isFirstLoaded.value = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitChange() {
|
function emitChange() {
|
||||||
emit('optionsChange', unref(getOptions))
|
emit('options-change', unref(getOptions))
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleChange(_, ...args) {
|
function handleChange(_, ...args) {
|
||||||
|
|
@ -134,7 +125,10 @@ function handleChange(_, ...args) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Select
|
<Select
|
||||||
v-bind="$attrs" v-model:value="state" :options="getOptions" @dropdown-visible-change="handleFetch"
|
v-bind="$attrs"
|
||||||
|
v-model:value="state"
|
||||||
|
:options="getOptions"
|
||||||
|
@dropdown-visible-change="handleFetch"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
>
|
>
|
||||||
<template v-for="item in Object.keys($slots)" #[item]="data">
|
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, unref, useAttrs, watch, watchEffect } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
|
import { computed, ref, unref, watch, watchEffect } from 'vue'
|
||||||
import { Transfer } from 'ant-design-vue'
|
import { Transfer } from 'ant-design-vue'
|
||||||
import { get, omit } from 'lodash-es'
|
import { get, omit } from 'lodash-es'
|
||||||
import type { TransferDirection, TransferItem } from 'ant-design-vue/lib/transfer'
|
import type { TransferDirection, TransferItem } from 'ant-design-vue/lib/transfer'
|
||||||
|
|
@ -9,16 +10,16 @@ import { propTypes } from '@/utils/propTypes'
|
||||||
defineOptions({ name: 'ApiTransfer' })
|
defineOptions({ name: 'ApiTransfer' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: { type: Array as PropType<Array<any>> },
|
value: { type: Array as PropType<Array<string>> },
|
||||||
api: {
|
api: {
|
||||||
type: Function as PropType<(arg?: Recordable) => Promise<TransferItem[]>>,
|
type: Function as PropType<(arg) => Promise<TransferItem[]>>,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
params: { type: Object },
|
params: { type: Object },
|
||||||
dataSource: { type: Array as PropType<Array<TransferItem>> },
|
dataSource: { type: Array as PropType<Array<TransferItem>> },
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
alwaysLoad: propTypes.bool.def(false),
|
||||||
afterFetch: { type: Function as PropType<Fn> },
|
afterFetch: { type: Function },
|
||||||
resultField: propTypes.string.def(''),
|
resultField: propTypes.string.def(''),
|
||||||
labelField: propTypes.string.def('title'),
|
labelField: propTypes.string.def('title'),
|
||||||
valueField: propTypes.string.def('key'),
|
valueField: propTypes.string.def('key'),
|
||||||
|
|
@ -31,20 +32,22 @@ const props = defineProps({
|
||||||
showSelectAll: { type: Boolean, default: true },
|
showSelectAll: { type: Boolean, default: true },
|
||||||
targetKeys: { type: Array as PropType<Array<string>> },
|
targetKeys: { type: Array as PropType<Array<string>> },
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['optionsChange', 'change'])
|
const emit = defineEmits(['options-change', 'change'])
|
||||||
const attrs = useAttrs()
|
// const attrs = useAttrs()
|
||||||
|
|
||||||
const _dataSource = ref<TransferItem[]>([])
|
const _dataSource = ref<TransferItem[]>([])
|
||||||
const _targetKeys = ref<string[]>([])
|
const _targetKeys = ref<string[]>([])
|
||||||
const getAttrs = computed(() => {
|
|
||||||
return {
|
// const getAttrs = computed(() => {
|
||||||
...(!props.api ? { dataSource: unref(_dataSource) } : {}),
|
// return {
|
||||||
...attrs,
|
// ...(!props.api ? { dataSource: unref(_dataSource) } : {}),
|
||||||
}
|
// ...attrs,
|
||||||
})
|
// }
|
||||||
|
// })
|
||||||
const getdataSource = computed(() => {
|
const getdataSource = computed(() => {
|
||||||
const { labelField, valueField } = props
|
const { labelField, valueField } = props
|
||||||
return unref(_dataSource).reduce((prev, next: Recordable) => {
|
|
||||||
|
return unref(_dataSource).reduce((prev, next) => {
|
||||||
if (next) {
|
if (next) {
|
||||||
prev.push({
|
prev.push({
|
||||||
...omit(next, [labelField, valueField]),
|
...omit(next, [labelField, valueField]),
|
||||||
|
|
@ -56,9 +59,9 @@ const getdataSource = computed(() => {
|
||||||
}, [] as TransferItem[])
|
}, [] as TransferItem[])
|
||||||
})
|
})
|
||||||
const getTargetKeys = computed<string[]>(() => {
|
const getTargetKeys = computed<string[]>(() => {
|
||||||
// if (unref(_targetKeys).length > 0)
|
/* if (unref(_targetKeys).length > 0) {
|
||||||
// return unref(_targetKeys)
|
return unref(_targetKeys);
|
||||||
|
} */
|
||||||
if (Array.isArray(props.value))
|
if (Array.isArray(props.value))
|
||||||
return props.value
|
return props.value
|
||||||
|
|
||||||
|
|
@ -67,15 +70,18 @@ const getTargetKeys = computed<string[]>(() => {
|
||||||
|
|
||||||
return []
|
return []
|
||||||
})
|
})
|
||||||
|
|
||||||
function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {
|
function handleChange(keys: string[], direction: TransferDirection, moveKeys: string[]) {
|
||||||
_targetKeys.value = keys
|
_targetKeys.value = keys
|
||||||
console.log(direction)
|
console.log(direction)
|
||||||
console.log(moveKeys)
|
console.log(moveKeys)
|
||||||
emit('change', keys)
|
emit('change', keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
props.immediate && !props.alwaysLoad && fetch()
|
props.immediate && !props.alwaysLoad && fetch()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.params,
|
() => props.params,
|
||||||
() => {
|
() => {
|
||||||
|
|
@ -83,6 +89,7 @@ watch(
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
const api = props.api
|
const api = props.api
|
||||||
if (!api || !isFunction(api)) {
|
if (!api || !isFunction(api)) {
|
||||||
|
|
@ -109,13 +116,12 @@ async function fetch() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function emitChange() {
|
function emitChange() {
|
||||||
emit('optionsChange', unref(getdataSource))
|
emit('options-change', unref(getdataSource))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Transfer
|
<Transfer
|
||||||
v-bind="getAttrs"
|
|
||||||
:data-source="getdataSource"
|
:data-source="getdataSource"
|
||||||
:filter-option="filterOption"
|
:filter-option="filterOption"
|
||||||
:render="(item) => item.title"
|
:render="(item) => item.title"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, ref, unref, useAttrs, useSlots, watch } from 'vue'
|
import { computed, onMounted, ref, unref, useAttrs, watch } from 'vue'
|
||||||
import type { TreeProps } from 'ant-design-vue'
|
import type { TreeProps } from 'ant-design-vue'
|
||||||
import { Tree } from 'ant-design-vue'
|
import { Tree } from 'ant-design-vue'
|
||||||
import { get } from 'lodash-es'
|
import { get } from 'lodash-es'
|
||||||
|
|
@ -7,30 +7,30 @@ import type { DataNode } from 'ant-design-vue/es/tree'
|
||||||
import { isArray, isFunction } from '@/utils/is'
|
import { isArray, isFunction } from '@/utils/is'
|
||||||
import { handleTree as handleTreeFn } from '@/utils/tree'
|
import { handleTree as handleTreeFn } from '@/utils/tree'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import type { AnyFunction, Recordable } from '@/utils/types'
|
||||||
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
||||||
|
|
||||||
defineOptions({ name: 'ApiTree' })
|
defineOptions({ name: 'ApiTree' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
|
||||||
params: { type: Object },
|
params: { type: Object },
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
resultField: propTypes.string.def(''),
|
resultField: propTypes.string.def(''),
|
||||||
afterFetch: { type: Function as PropType<Fn> },
|
afterFetch: { type: Function as PropType<AnyFunction> },
|
||||||
handleTree: propTypes.string.def(''),
|
handleTree: propTypes.string.def(''),
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
alwaysLoad: propTypes.bool.def(true),
|
||||||
value: {
|
value: {
|
||||||
type: Array as PropType<TreeProps['selectedKeys']>,
|
type: Array as PropType<TreeProps['selectedKeys']>,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['optionsChange', 'change', 'update:value'])
|
const emit = defineEmits(['options-change', 'change', 'update:value'])
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
const slots = useSlots()
|
|
||||||
|
|
||||||
const treeData = ref<DataNode[]>([])
|
const treeData = ref<DataNode[]>([])
|
||||||
const isFirstLoaded = ref<boolean>(false)
|
const isFirstLoaded = ref<boolean>(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const emitData = ref<any[]>([])
|
const emitData = ref<any[]>([])
|
||||||
|
|
||||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData)
|
const [state] = useRuleFormItem(props, 'value', 'change', emitData)
|
||||||
|
|
||||||
const getAttrs = computed(() => {
|
const getAttrs = computed(() => {
|
||||||
|
|
@ -50,11 +50,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
() => props.params,
|
() => props.params,
|
||||||
() => {
|
() => {
|
||||||
if (props.alwaysLoad)
|
!unref(isFirstLoaded) && fetch()
|
||||||
fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
!unref(isFirstLoaded) && fetch()
|
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
@ -62,11 +58,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
() => props.immediate,
|
() => props.immediate,
|
||||||
(v) => {
|
(v) => {
|
||||||
if (props.alwaysLoad)
|
v && !isFirstLoaded.value && fetch()
|
||||||
v && fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
v && !isFirstLoaded.value && fetch()
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -101,13 +93,13 @@ async function fetch() {
|
||||||
|
|
||||||
treeData.value = (result as (Recordable & { key: string | number })[]) || []
|
treeData.value = (result as (Recordable & { key: string | number })[]) || []
|
||||||
isFirstLoaded.value = true
|
isFirstLoaded.value = true
|
||||||
emit('optionsChange', treeData.value)
|
emit('options-change', treeData.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Tree v-bind="getAttrs" v-model:selected-keys="state">
|
<Tree v-bind="getAttrs" v-model:selectedKeys="state">
|
||||||
<template v-for="item in Object.keys(slots)" #[item]="data">
|
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
</template>
|
</template>
|
||||||
</Tree>
|
</Tree>
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@ import { get, set } from 'lodash-es'
|
||||||
import { LoadingOutlined } from '@ant-design/icons-vue'
|
import { LoadingOutlined } from '@ant-design/icons-vue'
|
||||||
import { isArray, isFunction } from '@/utils/is'
|
import { isArray, isFunction } from '@/utils/is'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import type { Recordable } from '@/utils/types'
|
||||||
import { handleTree as handleTreeFn } from '@/utils/tree'
|
import { handleTree as handleTreeFn } from '@/utils/tree'
|
||||||
|
|
||||||
defineOptions({ name: 'ApiTreeSelect' })
|
defineOptions({ name: 'ApiTreeSelect' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
api: { type: Function as PropType<(arg?: Recordable) => Promise<Recordable>> },
|
api: { type: Function as PropType<(arg?: Recordable<any>) => Promise<Recordable<any>>> },
|
||||||
params: { type: Object },
|
params: { type: Object },
|
||||||
immediate: propTypes.bool.def(true),
|
immediate: propTypes.bool.def(true),
|
||||||
async: propTypes.bool.def(false),
|
async: propTypes.bool.def(false),
|
||||||
|
|
@ -19,12 +20,13 @@ const props = defineProps({
|
||||||
parentId: propTypes.number.def(0),
|
parentId: propTypes.number.def(0),
|
||||||
parentLabel: propTypes.string.def(''),
|
parentLabel: propTypes.string.def(''),
|
||||||
parentFiled: propTypes.string.def('name'),
|
parentFiled: propTypes.string.def('name'),
|
||||||
alwaysLoad: propTypes.bool.def(true),
|
labelField: propTypes.string.def('name'),
|
||||||
|
valueField: propTypes.string.def('id'),
|
||||||
|
childrenField: propTypes.string.def('children'),
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['optionsChange', 'change', 'load-data'])
|
const emit = defineEmits(['options-change', 'change', 'load-data'])
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
const treeData = ref<Recordable<any>[]>([])
|
||||||
const treeData = ref<Recordable[]>([])
|
|
||||||
const isFirstLoaded = ref<boolean>(false)
|
const isFirstLoaded = ref<boolean>(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const getAttrs = computed(() => {
|
const getAttrs = computed(() => {
|
||||||
|
|
@ -33,6 +35,11 @@ const getAttrs = computed(() => {
|
||||||
...attrs,
|
...attrs,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const fieldNames = {
|
||||||
|
children: props.childrenField,
|
||||||
|
value: props.valueField,
|
||||||
|
label: props.labelField,
|
||||||
|
}
|
||||||
|
|
||||||
function handleChange(...args) {
|
function handleChange(...args) {
|
||||||
emit('change', ...args)
|
emit('change', ...args)
|
||||||
|
|
@ -41,11 +48,7 @@ function handleChange(...args) {
|
||||||
watch(
|
watch(
|
||||||
() => props.params,
|
() => props.params,
|
||||||
() => {
|
() => {
|
||||||
if (props.alwaysLoad)
|
!unref(isFirstLoaded) && fetch()
|
||||||
fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
!unref(isFirstLoaded) && fetch()
|
|
||||||
},
|
},
|
||||||
{ deep: true },
|
{ deep: true },
|
||||||
)
|
)
|
||||||
|
|
@ -53,11 +56,7 @@ watch(
|
||||||
watch(
|
watch(
|
||||||
() => props.immediate,
|
() => props.immediate,
|
||||||
(v) => {
|
(v) => {
|
||||||
if (props.alwaysLoad)
|
v && !isFirstLoaded.value && fetch()
|
||||||
v && fetch()
|
|
||||||
|
|
||||||
else
|
|
||||||
v && !isFirstLoaded.value && fetch()
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -77,7 +76,7 @@ function onLoadData(treeNode) {
|
||||||
|
|
||||||
async function fetch() {
|
async function fetch() {
|
||||||
const { api } = props
|
const { api } = props
|
||||||
if (!api || !isFunction(api))
|
if (!api || !isFunction(api) || loading.value)
|
||||||
return
|
return
|
||||||
loading.value = true
|
loading.value = true
|
||||||
treeData.value = []
|
treeData.value = []
|
||||||
|
|
@ -106,14 +105,18 @@ async function fetch() {
|
||||||
else {
|
else {
|
||||||
treeData.value = (result as Recordable[]) || []
|
treeData.value = (result as Recordable[]) || []
|
||||||
}
|
}
|
||||||
|
|
||||||
isFirstLoaded.value = true
|
isFirstLoaded.value = true
|
||||||
emit('optionsChange', treeData.value)
|
emit('options-change', treeData.value)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<TreeSelect v-bind="getAttrs" :load-data="async ? onLoadData : undefined" @change="handleChange">
|
<TreeSelect
|
||||||
|
v-bind="getAttrs"
|
||||||
|
:field-names="fieldNames"
|
||||||
|
:load-data="async ? onLoadData : undefined"
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
<template v-for="item in Object.keys($slots)" #[item]="data">
|
<template v-for="item in Object.keys($slots)" #[item]="data">
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { Col, Form } from 'ant-design-vue'
|
import { Col, Form } from 'ant-design-vue'
|
||||||
import type { ColEx } from '../types'
|
import type { ColEx } from '../types'
|
||||||
|
|
||||||
import { useFormContext } from '../hooks/useFormContext'
|
import { useFormContext } from '../hooks/useFormContext'
|
||||||
import type { ButtonProps } from '@/components/Button'
|
import type { ButtonProps } from '@/components/Button'
|
||||||
import { Button } from '@/components/Button'
|
import { Button } from '@/components/Button'
|
||||||
|
|
@ -10,6 +10,8 @@ import { BasicArrow } from '@/components/Basic'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
type ButtonOptions = Partial<ButtonProps> & { text: string }
|
||||||
|
|
||||||
defineOptions({ name: 'BasicFormAction' })
|
defineOptions({ name: 'BasicFormAction' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
@ -34,12 +36,11 @@ const props = defineProps({
|
||||||
hideAdvanceBtn: propTypes.bool,
|
hideAdvanceBtn: propTypes.bool,
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['toggleAdvanced'])
|
const emit = defineEmits(['toggle-advanced'])
|
||||||
|
|
||||||
|
const { resetAction, submitAction } = useFormContext()
|
||||||
|
|
||||||
const FormItem = Form.Item
|
const FormItem = Form.Item
|
||||||
|
|
||||||
type ButtonOptions = Partial<ButtonProps> & { text: string }
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const actionColOpt = computed(() => {
|
const actionColOpt = computed(() => {
|
||||||
|
|
@ -74,10 +75,8 @@ const getSubmitBtnOptions = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
function toggleAdvanced() {
|
function toggleAdvanced() {
|
||||||
emit('toggleAdvanced')
|
emit('toggle-advanced')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { resetAction, submitAction } = useFormContext()
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -85,17 +84,34 @@ const { resetAction, submitAction } = useFormContext()
|
||||||
<div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
|
<div style="width: 100%" :style="{ textAlign: actionColOpt.style.textAlign }">
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<slot name="resetBefore" />
|
<slot name="resetBefore" />
|
||||||
<Button v-if="showResetButton" type="default" class="mr-2" v-bind="getResetBtnOptions" @click="resetAction">
|
<Button
|
||||||
|
v-if="showResetButton"
|
||||||
|
type="default"
|
||||||
|
class="mr-2"
|
||||||
|
v-bind="getResetBtnOptions"
|
||||||
|
@click="resetAction"
|
||||||
|
>
|
||||||
{{ getResetBtnOptions.text }}
|
{{ getResetBtnOptions.text }}
|
||||||
</Button>
|
</Button>
|
||||||
<slot name="submitBefore" />
|
<slot name="submitBefore" />
|
||||||
|
|
||||||
<Button v-if="showSubmitButton" type="primary" class="mr-2" v-bind="getSubmitBtnOptions" @click="submitAction">
|
<Button
|
||||||
|
v-if="showSubmitButton"
|
||||||
|
type="primary"
|
||||||
|
class="mr-2"
|
||||||
|
v-bind="getSubmitBtnOptions"
|
||||||
|
@click="submitAction"
|
||||||
|
>
|
||||||
{{ getSubmitBtnOptions.text }}
|
{{ getSubmitBtnOptions.text }}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<slot name="advanceBefore" />
|
<slot name="advanceBefore" />
|
||||||
<Button v-if="showAdvancedButton && !hideAdvanceBtn" type="link" size="small" @click="toggleAdvanced">
|
<Button
|
||||||
|
v-if="showAdvancedButton && !hideAdvanceBtn"
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
@click="toggleAdvanced"
|
||||||
|
>
|
||||||
{{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}
|
{{ isAdvanced ? t('component.form.putAway') : t('component.form.unfold') }}
|
||||||
<BasicArrow class="ml-1" :expand="!isAdvanced" up />
|
<BasicArrow class="ml-1" :expand="!isAdvanced" up />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import type { Ref } from 'vue'
|
import type { PropType, Ref } from 'vue'
|
||||||
import { computed, defineComponent, toRefs, unref } from 'vue'
|
import { computed, defineComponent, toRefs, unref } from 'vue'
|
||||||
import type { Rule } from 'ant-design-vue/lib/form'
|
import type { Rule as ValidationRule } from 'ant-design-vue/lib/form'
|
||||||
import { Col, Divider, Form } from 'ant-design-vue'
|
import { Col, Divider, Form } from 'ant-design-vue'
|
||||||
import { cloneDeep, upperFirst } from 'lodash-es'
|
import { cloneDeep, upperFirst } from 'lodash-es'
|
||||||
import type { FormActionType, FormProps, FormSchemaInner as FormSchema } from '../types/form'
|
import type { FormActionType, FormProps, FormSchemaInner as FormSchema } from '../types/form'
|
||||||
|
|
@ -13,6 +13,7 @@ import type { TableActionType } from '@/components/Table'
|
||||||
import { BasicHelp } from '@/components/Basic'
|
import { BasicHelp } from '@/components/Basic'
|
||||||
import { isBoolean, isFunction, isNull } from '@/utils/is'
|
import { isBoolean, isFunction, isNull } from '@/utils/is'
|
||||||
import { getSlot } from '@/utils/helper/tsxHelper'
|
import { getSlot } from '@/utils/helper/tsxHelper'
|
||||||
|
import type { Nullable, Recordable } from '@/utils/types'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
|
@ -28,11 +29,11 @@ export default defineComponent({
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
allDefaultValues: {
|
allDefaultValues: {
|
||||||
type: Object as PropType<Recordable>,
|
type: Object as PropType<Recordable<any>>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
formModel: {
|
formModel: {
|
||||||
type: Object as PropType<Recordable>,
|
type: Object as PropType<Recordable<any>>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
setFormModel: {
|
setFormModel: {
|
||||||
|
|
@ -69,7 +70,7 @@ export default defineComponent({
|
||||||
...mergeDynamicData,
|
...mergeDynamicData,
|
||||||
...allDefaultValues,
|
...allDefaultValues,
|
||||||
...formModel,
|
...formModel,
|
||||||
} as Recordable,
|
} as Recordable<any>,
|
||||||
schema,
|
schema,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -90,7 +91,7 @@ export default defineComponent({
|
||||||
componentProps,
|
componentProps,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return componentProps as Recordable
|
return componentProps as Recordable<any>
|
||||||
})
|
})
|
||||||
|
|
||||||
const getDisable = computed(() => {
|
const getDisable = computed(() => {
|
||||||
|
|
@ -110,7 +111,11 @@ export default defineComponent({
|
||||||
function getShow(): { isShow: boolean; isIfShow: boolean } {
|
function getShow(): { isShow: boolean; isIfShow: boolean } {
|
||||||
const { show, ifShow } = props.schema
|
const { show, ifShow } = props.schema
|
||||||
const { showAdvancedButton } = props.formProps
|
const { showAdvancedButton } = props.formProps
|
||||||
const itemIsAdvanced = showAdvancedButton ? (isBoolean(props.isAdvanced) ? props.isAdvanced : true) : true
|
const itemIsAdvanced = showAdvancedButton
|
||||||
|
? isBoolean(props.isAdvanced)
|
||||||
|
? props.isAdvanced
|
||||||
|
: true
|
||||||
|
: true
|
||||||
|
|
||||||
let isShow = true
|
let isShow = true
|
||||||
let isIfShow = true
|
let isIfShow = true
|
||||||
|
|
@ -131,18 +136,29 @@ export default defineComponent({
|
||||||
return { isShow, isIfShow }
|
return { isShow, isIfShow }
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRules(): Rule[] {
|
function handleRules(): ValidationRule[] {
|
||||||
const { rules: defRules = [], component, rulesMessageJoinLabel, label, dynamicRules, required } = props.schema
|
const {
|
||||||
|
rules: defRules = [],
|
||||||
|
component,
|
||||||
|
rulesMessageJoinLabel,
|
||||||
|
label,
|
||||||
|
dynamicRules,
|
||||||
|
required,
|
||||||
|
} = props.schema
|
||||||
|
|
||||||
if (isFunction(dynamicRules))
|
if (isFunction(dynamicRules))
|
||||||
return dynamicRules(unref(getValues)) as Rule[]
|
return dynamicRules(unref(getValues)) as ValidationRule[]
|
||||||
|
|
||||||
let rules: Rule[] = cloneDeep(defRules) as Rule[]
|
let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[]
|
||||||
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps
|
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps
|
||||||
|
|
||||||
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel') ? rulesMessageJoinLabel : globalRulesMessageJoinLabel
|
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
|
||||||
|
? rulesMessageJoinLabel
|
||||||
|
: globalRulesMessageJoinLabel
|
||||||
const assertLabel = joinLabel ? label : ''
|
const assertLabel = joinLabel ? label : ''
|
||||||
const defaultMsg = component ? createPlaceholderMessage(component) + assertLabel : assertLabel
|
const defaultMsg = component
|
||||||
|
? createPlaceholderMessage(component) + assertLabel
|
||||||
|
: assertLabel
|
||||||
|
|
||||||
function validator(rule: any, value: any) {
|
function validator(rule: any, value: any) {
|
||||||
const msg = rule.message || defaultMsg
|
const msg = rule.message || defaultMsg
|
||||||
|
|
@ -192,7 +208,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const requiredRuleIndex: number = rules.findIndex(rule => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'))
|
const requiredRuleIndex: number = rules.findIndex(
|
||||||
|
rule => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'),
|
||||||
|
)
|
||||||
|
|
||||||
if (requiredRuleIndex !== -1) {
|
if (requiredRuleIndex !== -1) {
|
||||||
const rule = rules[requiredRuleIndex]
|
const rule = rules[requiredRuleIndex]
|
||||||
|
|
@ -213,9 +231,11 @@ export default defineComponent({
|
||||||
|
|
||||||
// Maximum input length rule check
|
// Maximum input length rule check
|
||||||
const characterInx = rules.findIndex(val => val.max)
|
const characterInx = rules.findIndex(val => val.max)
|
||||||
if (characterInx !== -1 && !rules[characterInx].validator)
|
if (characterInx !== -1 && !rules[characterInx].validator) {
|
||||||
rules[characterInx].message = rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max] as Recordable)
|
rules[characterInx].message
|
||||||
|
= rules[characterInx].message
|
||||||
|
|| t('component.form.maxTip', [rules[characterInx].max] as Recordable<any>)
|
||||||
|
}
|
||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,24 +243,29 @@ export default defineComponent({
|
||||||
if (!isComponentFormSchema(props.schema))
|
if (!isComponentFormSchema(props.schema))
|
||||||
return null
|
return null
|
||||||
|
|
||||||
const { renderComponentContent, component, field, changeEvent = 'change', valueField } = props.schema
|
const {
|
||||||
|
renderComponentContent,
|
||||||
|
component,
|
||||||
|
field,
|
||||||
|
changeEvent = 'change',
|
||||||
|
valueField,
|
||||||
|
} = props.schema
|
||||||
|
|
||||||
const isCheck = component && ['Switch', 'Checkbox'].includes(component)
|
const isCheck = component && ['Switch', 'Checkbox'].includes(component)
|
||||||
|
|
||||||
const eventKey = `on${upperFirst(changeEvent)}`
|
const eventKey = `on${upperFirst(changeEvent)}`
|
||||||
|
|
||||||
const { autoSetPlaceHolder, size } = props.formProps
|
const { autoSetPlaceHolder, size } = props.formProps
|
||||||
|
const propsData: Recordable<any> = {
|
||||||
const propsData: Recordable = {
|
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
getPopupContainer: (trigger: Element) => trigger.parentNode!.parentNode,
|
getPopupContainer: (trigger: Element) => trigger.parentNode,
|
||||||
size,
|
size,
|
||||||
...unref(getComponentsProps),
|
...unref(getComponentsProps),
|
||||||
disabled: unref(getDisable),
|
disabled: unref(getDisable),
|
||||||
}
|
}
|
||||||
|
|
||||||
const on = {
|
const on = {
|
||||||
[eventKey]: (...args: Nullable<Recordable>[]) => {
|
[eventKey]: (...args: Nullable<Recordable<any>>[]) => {
|
||||||
const [e] = args
|
const [e] = args
|
||||||
if (propsData[eventKey])
|
if (propsData[eventKey])
|
||||||
propsData[eventKey](...args)
|
propsData[eventKey](...args)
|
||||||
|
|
@ -254,17 +279,18 @@ export default defineComponent({
|
||||||
|
|
||||||
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder
|
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder
|
||||||
// RangePicker place is an array
|
// RangePicker place is an array
|
||||||
if (isCreatePlaceholder && component !== 'RangePicker' && component)
|
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
|
||||||
propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component)
|
propsData.placeholder
|
||||||
|
= unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component)
|
||||||
|
}
|
||||||
propsData.codeField = field
|
propsData.codeField = field
|
||||||
propsData.formValues = unref(getValues)
|
propsData.formValues = unref(getValues)
|
||||||
|
|
||||||
const bindValue: Recordable = {
|
const bindValue: Recordable<any> = {
|
||||||
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
|
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
|
||||||
}
|
}
|
||||||
|
|
||||||
const compAttr: Recordable = {
|
const compAttr: Recordable<any> = {
|
||||||
...propsData,
|
...propsData,
|
||||||
...on,
|
...on,
|
||||||
...bindValue,
|
...bindValue,
|
||||||
|
|
@ -294,7 +320,9 @@ export default defineComponent({
|
||||||
: (
|
: (
|
||||||
label
|
label
|
||||||
)
|
)
|
||||||
const getHelpMessage = isFunction(helpMessage) ? helpMessage(unref(getValues)) : helpMessage
|
const getHelpMessage = isFunction(helpMessage)
|
||||||
|
? helpMessage(unref(getValues))
|
||||||
|
: helpMessage
|
||||||
if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0))
|
if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0))
|
||||||
return renderLabel
|
return renderLabel
|
||||||
|
|
||||||
|
|
@ -310,9 +338,7 @@ export default defineComponent({
|
||||||
const { itemProps, slot, render, field, suffix, component } = props.schema
|
const { itemProps, slot, render, field, suffix, component } = props.schema
|
||||||
const { labelCol, wrapperCol } = unref(itemLabelWidthProp)
|
const { labelCol, wrapperCol } = unref(itemLabelWidthProp)
|
||||||
const { colon } = props.formProps
|
const { colon } = props.formProps
|
||||||
|
|
||||||
const opts = { disabled: unref(getDisable) }
|
const opts = { disabled: unref(getDisable) }
|
||||||
|
|
||||||
if (component === 'Divider') {
|
if (component === 'Divider') {
|
||||||
return (
|
return (
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
|
|
@ -322,7 +348,11 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const getContent = () => {
|
const getContent = () => {
|
||||||
return slot ? getSlot(slots, slot, unref(getValues), opts) : render ? render(unref(getValues), opts) : renderComponent()
|
return slot
|
||||||
|
? getSlot(slots, slot, unref(getValues), opts)
|
||||||
|
: render
|
||||||
|
? render(unref(getValues), opts)
|
||||||
|
: renderComponent()
|
||||||
}
|
}
|
||||||
|
|
||||||
const showSuffix = !!suffix
|
const showSuffix = !!suffix
|
||||||
|
|
@ -342,7 +372,7 @@ export default defineComponent({
|
||||||
name={field}
|
name={field}
|
||||||
colon={colon}
|
colon={colon}
|
||||||
class={{ 'suffix-item': showSuffix }}
|
class={{ 'suffix-item': showSuffix }}
|
||||||
{...(itemProps as Recordable)}
|
{...(itemProps as Recordable<any>)}
|
||||||
label={renderLabelHelpMessage()}
|
label={renderLabelHelpMessage()}
|
||||||
rules={handleRules()}
|
rules={handleRules()}
|
||||||
labelCol={labelCol}
|
labelCol={labelCol}
|
||||||
|
|
@ -369,7 +399,11 @@ export default defineComponent({
|
||||||
const opts = { disabled: unref(getDisable) }
|
const opts = { disabled: unref(getDisable) }
|
||||||
|
|
||||||
const getContent = () => {
|
const getContent = () => {
|
||||||
return colSlot ? getSlot(slots, colSlot, values, opts) : renderColContent ? renderColContent(values, opts) : renderItem()
|
return colSlot
|
||||||
|
? getSlot(slots, colSlot, values, opts)
|
||||||
|
: renderColContent
|
||||||
|
? renderColContent(values, opts)
|
||||||
|
: renderItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,16 @@
|
||||||
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
|
* @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
|
||||||
-->
|
-->
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { Radio } from 'ant-design-vue'
|
import { Radio } from 'ant-design-vue'
|
||||||
import { isString } from '@/utils/is'
|
import { isString } from '@/utils/is'
|
||||||
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
import { useRuleFormItem } from '@/hooks/component/useFormItem'
|
||||||
import { useAttrs } from '@/hooks/core/useAttrs'
|
import { useAttrs } from '@/hooks/core/useAttrs'
|
||||||
|
|
||||||
|
interface OptionsItem { label: string; value: string | number | boolean; disabled?: boolean }
|
||||||
|
type RadioItem = string | OptionsItem
|
||||||
|
|
||||||
defineOptions({ name: 'RadioButtonGroup' })
|
defineOptions({ name: 'RadioButtonGroup' })
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
value: {
|
||||||
|
|
@ -18,15 +22,12 @@ const props = defineProps({
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const emits = defineEmits(['change'])
|
|
||||||
|
// const emits = defineEmits(['change'])
|
||||||
|
|
||||||
const RadioButton = Radio.Button
|
const RadioButton = Radio.Button
|
||||||
const RadioGroup = Radio.Group
|
const RadioGroup = Radio.Group
|
||||||
|
|
||||||
interface OptionsItem { label: string; value: string | number | boolean; disabled?: boolean }
|
|
||||||
type RadioItem = string | OptionsItem
|
|
||||||
|
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
|
||||||
const emitData = ref<any[]>([])
|
const emitData = ref<any[]>([])
|
||||||
// Embedded in the form, just use the hook binding to perform form verification
|
// Embedded in the form, just use the hook binding to perform form verification
|
||||||
const [state] = useRuleFormItem(props, 'value', 'change', emitData)
|
const [state] = useRuleFormItem(props, 'value', 'change', emitData)
|
||||||
|
|
@ -44,16 +45,15 @@ const getOptions = computed((): OptionsItem[] => {
|
||||||
return options.map(item => ({ label: item, value: item })) as OptionsItem[]
|
return options.map(item => ({ label: item, value: item })) as OptionsItem[]
|
||||||
})
|
})
|
||||||
|
|
||||||
function handleClick(args) {
|
function handleClick(...args) {
|
||||||
emitData.value = args
|
emitData.value = args
|
||||||
emits('change', emitData.value)
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
|
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
|
||||||
<template v-for="item in getOptions" :key="`${item.value}`">
|
<template v-for="item in getOptions" :key="`${item.value}`">
|
||||||
<RadioButton :value="item.value" :disabled="item.disabled" @click="handleClick(item.value)">
|
<RadioButton :value="item.value" :disabled="item.disabled" @click="handleClick(item)">
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Rule } from 'ant-design-vue/lib/form'
|
import type { Rule as ValidationRule } from 'ant-design-vue/lib/form'
|
||||||
import type { ComponentType } from './types'
|
import type { ComponentType } from './types'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { dateUtil } from '@/utils/dateUtil'
|
import { dateUtil } from '@/utils/dateUtil'
|
||||||
|
|
@ -35,14 +35,20 @@ function genType() {
|
||||||
return [...DATE_TYPE, 'RangePicker']
|
return [...DATE_TYPE, 'RangePicker']
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setComponentRuleType(rule: Rule, component: ComponentType, valueFormat: string) {
|
export function setComponentRuleType(
|
||||||
|
rule: ValidationRule,
|
||||||
|
component: ComponentType,
|
||||||
|
valueFormat: string,
|
||||||
|
) {
|
||||||
if (Reflect.has(rule, 'type'))
|
if (Reflect.has(rule, 'type'))
|
||||||
return
|
return
|
||||||
|
|
||||||
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component))
|
if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component))
|
||||||
rule.type = valueFormat ? 'string' : 'object'
|
rule.type = valueFormat ? 'string' : 'object'
|
||||||
|
|
||||||
else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component))
|
else if (['RangePicker', 'Upload', 'CheckboxGroup', 'TimePicker'].includes(component))
|
||||||
rule.type = 'array'
|
rule.type = 'array'
|
||||||
|
|
||||||
else if (['InputNumber'].includes(component))
|
else if (['InputNumber'].includes(component))
|
||||||
rule.type = 'number'
|
rule.type = 'number'
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +57,7 @@ export function processDateValue(attr: Recordable, component: string) {
|
||||||
const { valueFormat, value } = attr
|
const { valueFormat, value } = attr
|
||||||
if (valueFormat)
|
if (valueFormat)
|
||||||
attr.value = isObject(value) ? dateUtil(value as unknown as Date).format(valueFormat) : value
|
attr.value = isObject(value) ? dateUtil(value as unknown as Date).format(valueFormat) : value
|
||||||
|
|
||||||
else if (DATE_TYPE.includes(component) && value)
|
else if (DATE_TYPE.includes(component) && value)
|
||||||
attr.value = dateUtil(attr.value)
|
attr.value = dateUtil(attr.value)
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +81,6 @@ export const defaultValueComponents = ['Input', 'InputPassword', 'InputSearch',
|
||||||
// TODO 自定义组件封装会出现验证问题,因此这里目前改成手动触发验证
|
// TODO 自定义组件封装会出现验证问题,因此这里目前改成手动触发验证
|
||||||
export const NO_AUTO_LINK_COMPONENTS: ComponentType[] = [
|
export const NO_AUTO_LINK_COMPONENTS: ComponentType[] = [
|
||||||
'Upload',
|
'Upload',
|
||||||
'ApiSelect',
|
|
||||||
'ApiTransfer',
|
'ApiTransfer',
|
||||||
'ApiTree',
|
'ApiTree',
|
||||||
'ApiTreeSelect',
|
'ApiTreeSelect',
|
||||||
|
|
@ -82,4 +88,6 @@ export const NO_AUTO_LINK_COMPONENTS: ComponentType[] = [
|
||||||
'ApiCascader',
|
'ApiCascader',
|
||||||
'AutoComplete',
|
'AutoComplete',
|
||||||
'RadioButtonGroup',
|
'RadioButtonGroup',
|
||||||
|
'ImageUpload',
|
||||||
|
'ApiSelect',
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,13 @@ export default function ({ advanceState, emit, getProps, getSchema, formModel, d
|
||||||
const xxlWidth = Number.parseInt(itemCol.xxl as string) || xlWidth
|
const xxlWidth = Number.parseInt(itemCol.xxl as string) || xlWidth
|
||||||
if (width <= screenEnum.LG)
|
if (width <= screenEnum.LG)
|
||||||
itemColSum += mdWidth
|
itemColSum += mdWidth
|
||||||
|
|
||||||
else if (width < screenEnum.XL)
|
else if (width < screenEnum.XL)
|
||||||
itemColSum += lgWidth
|
itemColSum += lgWidth
|
||||||
|
|
||||||
else if (width < screenEnum.XXL)
|
else if (width < screenEnum.XXL)
|
||||||
itemColSum += xlWidth
|
itemColSum += xlWidth
|
||||||
|
|
||||||
else
|
else
|
||||||
itemColSum += xxlWidth
|
itemColSum += xxlWidth
|
||||||
|
|
||||||
|
|
@ -84,7 +87,10 @@ export default function ({ advanceState, emit, getProps, getSchema, formModel, d
|
||||||
advanceState.hideAdvanceBtn = true
|
advanceState.hideAdvanceBtn = true
|
||||||
advanceState.isAdvanced = true
|
advanceState.isAdvanced = true
|
||||||
}
|
}
|
||||||
else if (itemColSum > BASIC_COL_LEN * 2 && itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)) {
|
else if (
|
||||||
|
itemColSum > BASIC_COL_LEN * 2
|
||||||
|
&& itemColSum <= BASIC_COL_LEN * (unref(getProps).autoAdvancedLine || 3)
|
||||||
|
) {
|
||||||
advanceState.hideAdvanceBtn = false
|
advanceState.hideAdvanceBtn = false
|
||||||
|
|
||||||
// More than 3 lines collapsed by default
|
// More than 3 lines collapsed by default
|
||||||
|
|
@ -131,7 +137,10 @@ export default function ({ advanceState, emit, getProps, getSchema, formModel, d
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isShow && (colProps || baseColProps)) {
|
if (isShow && (colProps || baseColProps)) {
|
||||||
const { itemColSum: sum, isAdvanced } = getAdvanced({ ...baseColProps, ...colProps }, itemColSum)
|
const { itemColSum: sum, isAdvanced } = getAdvanced(
|
||||||
|
{ ...baseColProps, ...colProps },
|
||||||
|
itemColSum,
|
||||||
|
)
|
||||||
|
|
||||||
itemColSum = sum || 0
|
itemColSum = sum || 0
|
||||||
if (isAdvanced)
|
if (isAdvanced)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,12 @@ interface UseAutoFocusContext {
|
||||||
isInitedDefault: Ref<boolean>
|
isInitedDefault: Ref<boolean>
|
||||||
formElRef: Ref<FormActionType>
|
formElRef: Ref<FormActionType>
|
||||||
}
|
}
|
||||||
export function useAutoFocus({ getSchema, getProps, formElRef, isInitedDefault }: UseAutoFocusContext) {
|
export async function useAutoFocus({
|
||||||
|
getSchema,
|
||||||
|
getProps,
|
||||||
|
formElRef,
|
||||||
|
isInitedDefault,
|
||||||
|
}: UseAutoFocusContext) {
|
||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
if (unref(isInitedDefault) || !unref(getProps).autoFocusFirstItem)
|
if (unref(isInitedDefault) || !unref(getProps).autoFocusFirstItem)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,16 @@ export function useForm(props?: Props): UseFormReturnType {
|
||||||
return unref(formRef)?.getFieldsValue() as T
|
return unref(formRef)?.getFieldsValue() as T
|
||||||
},
|
},
|
||||||
|
|
||||||
setFieldsValue: async (values: Recordable) => {
|
setFieldsValue: async <T extends Recordable<any>>(values: T) => {
|
||||||
const form = await getForm()
|
const form = await getForm()
|
||||||
form.setFieldsValue(values)
|
form.setFieldsValue(values)
|
||||||
},
|
},
|
||||||
|
|
||||||
appendSchemaByField: async (schema: FormSchema | FormSchema[], prefixField: string | undefined, first?: boolean) => {
|
appendSchemaByField: async (
|
||||||
|
schema: FormSchema | FormSchema[],
|
||||||
|
prefixField: string | undefined,
|
||||||
|
first?: boolean,
|
||||||
|
) => {
|
||||||
const form = await getForm()
|
const form = await getForm()
|
||||||
form.appendSchemaByField(schema, prefixField, first)
|
form.appendSchemaByField(schema, prefixField, first)
|
||||||
},
|
},
|
||||||
|
|
@ -101,7 +105,7 @@ export function useForm(props?: Props): UseFormReturnType {
|
||||||
return form.submit()
|
return form.submit()
|
||||||
},
|
},
|
||||||
|
|
||||||
validate: async <T = any>(nameList?: NamePath[] | false): Promise<T> => {
|
validate: async <T = Recordable>(nameList?: NamePath[] | false): Promise<T> => {
|
||||||
const form = await getForm()
|
const form = await getForm()
|
||||||
return form.validate(nameList)
|
return form.validate(nameList)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ export function useFormEvents({
|
||||||
if (fieldKeys.length) {
|
if (fieldKeys.length) {
|
||||||
// eslint-disable-next-line array-callback-return
|
// eslint-disable-next-line array-callback-return
|
||||||
fieldKeys.map((field) => {
|
fieldKeys.map((field) => {
|
||||||
formModel[field] = defaultValueObj[field]
|
formModel[field] = defaultValueObj![field]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
formModel[key] = getDefaultValue(schema, defaultValueRef, key)
|
formModel[key] = getDefaultValue(schema, defaultValueRef, key)
|
||||||
|
|
@ -127,7 +127,7 @@ export function useFormEvents({
|
||||||
|
|
||||||
value = handleInputNumberValue(schema?.component, value)
|
value = handleInputNumberValue(schema?.component, value)
|
||||||
const { componentProps } = schema || {}
|
const { componentProps } = schema || {}
|
||||||
let _props = componentProps
|
let _props = componentProps as any
|
||||||
if (typeof componentProps === 'function')
|
if (typeof componentProps === 'function')
|
||||||
_props = _props({ formModel: unref(formModel) })
|
_props = _props({ formModel: unref(formModel) })
|
||||||
|
|
||||||
|
|
@ -230,18 +230,14 @@ export function useFormEvents({
|
||||||
}
|
}
|
||||||
const index = schemaList.findIndex(schema => schema.field === prefixField)
|
const index = schemaList.findIndex(schema => schema.field === prefixField)
|
||||||
const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[])
|
const _schemaList = isObject(schema) ? [schema as FormSchema] : (schema as FormSchema[])
|
||||||
if (!prefixField || index === -1 || first) {
|
if (!prefixField || index === -1 || first)
|
||||||
first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList)
|
first ? schemaList.unshift(..._schemaList) : schemaList.push(..._schemaList)
|
||||||
schemaRef.value = schemaList
|
|
||||||
_setDefaultValue(schema)
|
else if (index !== -1)
|
||||||
return
|
|
||||||
}
|
|
||||||
if (index !== -1)
|
|
||||||
schemaList.splice(index + 1, 0, ..._schemaList)
|
schemaList.splice(index + 1, 0, ..._schemaList)
|
||||||
|
|
||||||
_setDefaultValue(schema)
|
|
||||||
|
|
||||||
schemaRef.value = schemaList
|
schemaRef.value = schemaList
|
||||||
|
_setDefaultValue(schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
async function resetSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||||
|
|
@ -262,7 +258,7 @@ export function useFormEvents({
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
schemaRef.value = updateData
|
schemaRef.value = updateData as FormSchema[]
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
async function updateSchema(data: Partial<FormSchema> | Partial<FormSchema>[]) {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,12 @@ function tryDeconstructObject(key: string, value: any, target: Recordable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useFormValues({ defaultValueRef, getSchema, formModel, getProps }: UseFormValuesContext) {
|
export function useFormValues({
|
||||||
|
defaultValueRef,
|
||||||
|
getSchema,
|
||||||
|
formModel,
|
||||||
|
getProps,
|
||||||
|
}: UseFormValuesContext) {
|
||||||
// Processing form values
|
// Processing form values
|
||||||
function handleFormValues(values: Recordable) {
|
function handleFormValues(values: Recordable) {
|
||||||
if (!isObject(values))
|
if (!isObject(values))
|
||||||
|
|
@ -73,6 +78,7 @@ export function useFormValues({ defaultValueRef, getSchema, formModel, getProps
|
||||||
// remove params from URL
|
// remove params from URL
|
||||||
if (value === '')
|
if (value === '')
|
||||||
value = undefined
|
value = undefined
|
||||||
|
|
||||||
else
|
else
|
||||||
value = value.trim()
|
value = value.trim()
|
||||||
}
|
}
|
||||||
|
|
@ -138,9 +144,9 @@ export function useFormValues({ defaultValueRef, getSchema, formModel, getProps
|
||||||
if (fieldKeys.length) {
|
if (fieldKeys.length) {
|
||||||
// eslint-disable-next-line array-callback-return
|
// eslint-disable-next-line array-callback-return
|
||||||
fieldKeys.map((field) => {
|
fieldKeys.map((field) => {
|
||||||
obj[field] = defaultValueObj[field]
|
obj[field] = defaultValueObj![field]
|
||||||
if (formModel[field] === undefined)
|
if (formModel[field] === undefined)
|
||||||
formModel[field] = defaultValueObj[field]
|
formModel[field] = defaultValueObj![field]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (!isNullOrUnDef(defaultValue)) {
|
if (!isNullOrUnDef(defaultValue)) {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,12 @@ export function useItemLabelWidth(schemaItemRef: Ref<FormSchema>, propsRef: Ref<
|
||||||
const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {}
|
const { labelCol = {}, wrapperCol = {} } = schemaItem.itemProps || {}
|
||||||
const { labelWidth, disabledLabelWidth } = schemaItem
|
const { labelWidth, disabledLabelWidth } = schemaItem
|
||||||
|
|
||||||
const { labelWidth: globalLabelWidth, labelCol: globalLabelCol, wrapperCol: globWrapperCol, layout } = unref(propsRef)
|
const {
|
||||||
|
labelWidth: globalLabelWidth,
|
||||||
|
labelCol: globalLabelCol,
|
||||||
|
wrapperCol: globWrapperCol,
|
||||||
|
layout,
|
||||||
|
} = unref(propsRef)
|
||||||
|
|
||||||
// If labelWidth is set globally, all items setting
|
// If labelWidth is set globally, all items setting
|
||||||
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
|
if ((!globalLabelWidth && !labelWidth && !globalLabelCol) || disabledLabelWidth) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties, PropType } from 'vue'
|
||||||
import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'
|
import type { ButtonProps } from 'ant-design-vue/es/button/buttonTypes'
|
||||||
import type { RowProps } from 'ant-design-vue/lib/grid/Row'
|
import type { RowProps } from 'ant-design-vue/lib/grid/Row'
|
||||||
import type { FieldMapToTime, FormSchema } from './types/form'
|
import type { FieldMapToTime, FormSchema } from './types/form'
|
||||||
|
|
@ -41,7 +41,7 @@ export const basicProps = {
|
||||||
autoSubmitOnEnter: propTypes.bool.def(false),
|
autoSubmitOnEnter: propTypes.bool.def(false),
|
||||||
submitOnReset: propTypes.bool,
|
submitOnReset: propTypes.bool,
|
||||||
submitOnChange: propTypes.bool,
|
submitOnChange: propTypes.bool,
|
||||||
size: propTypes.oneOf(['default', 'small', 'large']),
|
size: propTypes.oneOf(['default', 'small', 'large']).def('default'),
|
||||||
// 禁用表单
|
// 禁用表单
|
||||||
disabled: propTypes.bool,
|
disabled: propTypes.bool,
|
||||||
emptySpan: {
|
emptySpan: {
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,13 @@ export interface FormActionType {
|
||||||
resetSchema: (data: Partial<FormSchemaInner> | Partial<FormSchemaInner>[]) => Promise<void>
|
resetSchema: (data: Partial<FormSchemaInner> | Partial<FormSchemaInner>[]) => Promise<void>
|
||||||
setProps: (formProps: Partial<FormProps>) => Promise<void>
|
setProps: (formProps: Partial<FormProps>) => Promise<void>
|
||||||
removeSchemaByField: (field: string | string[]) => Promise<void>
|
removeSchemaByField: (field: string | string[]) => Promise<void>
|
||||||
appendSchemaByField: (schema: FormSchema | FormSchema[], prefixField: string | undefined, first?: boolean | undefined) => Promise<void>
|
appendSchemaByField: (
|
||||||
|
schema: FormSchemaInner | FormSchemaInner[],
|
||||||
|
prefixField: string | undefined,
|
||||||
|
first?: boolean | undefined,
|
||||||
|
) => Promise<void>
|
||||||
validateFields: (nameList?: NamePath[]) => Promise<any>
|
validateFields: (nameList?: NamePath[]) => Promise<any>
|
||||||
validate: <T = any>(nameList?: NamePath[] | false) => Promise<T>
|
validate: <T = Recordable>(nameList?: NamePath[] | false) => Promise<T>
|
||||||
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>
|
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,13 +143,25 @@ interface BaseFormSchema {
|
||||||
// Auxiliary text
|
// Auxiliary text
|
||||||
subLabel?: string
|
subLabel?: string
|
||||||
// Help text on the right side of the text
|
// Help text on the right side of the text
|
||||||
helpMessage?: string | string[] | ((renderCallbackParams: RenderCallbackParams) => string | string[])
|
helpMessage?:
|
||||||
|
| string
|
||||||
|
| string[]
|
||||||
|
| ((renderCallbackParams: RenderCallbackParams) => string | string[])
|
||||||
// BaseHelp component props
|
// BaseHelp component props
|
||||||
helpComponentProps?: Partial<HelpComponentProps>
|
helpComponentProps?: Partial<HelpComponentProps>
|
||||||
// Label width, if it is passed, the labelCol and WrapperCol configured by itemProps will be invalid
|
// Label width, if it is passed, the labelCol and WrapperCol configured by itemProps will be invalid
|
||||||
labelWidth?: string | number
|
labelWidth?: string | number
|
||||||
// Disable the adjustment of labelWidth with global settings of formModel, and manually set labelCol and wrapperCol by yourself
|
// Disable the adjustment of labelWidth with global settings of formModel, and manually set labelCol and wrapperCol by yourself
|
||||||
disabledLabelWidth?: boolean
|
disabledLabelWidth?: boolean
|
||||||
|
// Component parameters
|
||||||
|
componentProps?:
|
||||||
|
| ((opt: {
|
||||||
|
schema: FormSchema
|
||||||
|
tableAction: TableActionType
|
||||||
|
formActionType: FormActionType
|
||||||
|
formModel: Recordable
|
||||||
|
}) => Recordable)
|
||||||
|
| object
|
||||||
// Required
|
// Required
|
||||||
required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean)
|
required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean)
|
||||||
|
|
||||||
|
|
@ -192,7 +208,11 @@ interface BaseFormSchema {
|
||||||
opts: RenderOpts,
|
opts: RenderOpts,
|
||||||
) => VNode | VNode[] | string
|
) => VNode | VNode[] | string
|
||||||
|
|
||||||
renderComponentContent?: ((renderCallbackParams: RenderCallbackParams, opts: RenderOpts) => any) | VNode | VNode[] | string
|
renderComponentContent?:
|
||||||
|
| ((renderCallbackParams: RenderCallbackParams, opts: RenderOpts) => any)
|
||||||
|
| VNode
|
||||||
|
| VNode[]
|
||||||
|
| string
|
||||||
|
|
||||||
// Custom slot, similar to renderColContent
|
// Custom slot, similar to renderColContent
|
||||||
colSlot?: string
|
colSlot?: string
|
||||||
|
|
@ -201,24 +221,14 @@ interface BaseFormSchema {
|
||||||
|
|
||||||
dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[]
|
dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[]
|
||||||
}
|
}
|
||||||
|
export interface ComponentFormSchema extends BaseFormSchema {
|
||||||
interface ComponentFormSchema extends BaseFormSchema {
|
|
||||||
// render component
|
// render component
|
||||||
component: ComponentType
|
component: ComponentType
|
||||||
// Component parameters
|
|
||||||
componentProps?:
|
|
||||||
| ((opt: {
|
|
||||||
schema: FormSchema
|
|
||||||
tableAction: TableActionType
|
|
||||||
formActionType: FormActionType
|
|
||||||
formModel: Recordable
|
|
||||||
}) => Recordable)
|
|
||||||
| object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SlotFormSchema extends BaseFormSchema {
|
export interface SlotFormSchema extends BaseFormSchema {
|
||||||
// Custom slot, in from-item
|
// Custom slot, in from-item
|
||||||
slot?: string
|
slot: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormSchema = ComponentFormSchema | SlotFormSchema
|
export type FormSchema = ComponentFormSchema | SlotFormSchema
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { omit } from 'lodash-es'
|
||||||
import type { BasicTableProps, ColumnChangeParam, InnerHandlers, SizeType, TableActionType } from './types/table'
|
import type { BasicTableProps, ColumnChangeParam, InnerHandlers, SizeType, TableActionType } from './types/table'
|
||||||
import HeaderCell from './components/HeaderCell.vue'
|
import HeaderCell from './components/HeaderCell.vue'
|
||||||
import { usePagination } from './hooks/usePagination'
|
import { usePagination } from './hooks/usePagination'
|
||||||
|
|
||||||
import { useColumns } from './hooks/useColumns'
|
import { useColumns } from './hooks/useColumns'
|
||||||
import { useDataSource } from './hooks/useDataSource'
|
import { useDataSource } from './hooks/useDataSource'
|
||||||
import { useLoading } from './hooks/useLoading'
|
import { useLoading } from './hooks/useLoading'
|
||||||
|
|
@ -21,14 +22,16 @@ import { useTableFooter } from './hooks/useTableFooter'
|
||||||
import { useTableForm } from './hooks/useTableForm'
|
import { useTableForm } from './hooks/useTableForm'
|
||||||
import { basicProps } from './props'
|
import { basicProps } from './props'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { BasicForm, useForm } from '@/components/Form'
|
|
||||||
import { PageWrapperFixedHeightKey } from '@/enums/pageEnum'
|
import { PageWrapperFixedHeightKey } from '@/enums/pageEnum'
|
||||||
|
import { BasicForm, useForm } from '@/components/Form'
|
||||||
import { isFunction } from '@/utils/is'
|
import { isFunction } from '@/utils/is'
|
||||||
import { warn } from '@/utils/log'
|
import { warn } from '@/utils/log'
|
||||||
|
|
||||||
defineOptions({ name: 'BasicTable' })
|
defineOptions({ name: 'BasicTable' })
|
||||||
|
|
||||||
const props = defineProps(basicProps)
|
const props = defineProps(basicProps)
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'fetch-success',
|
'fetch-success',
|
||||||
'fetch-error',
|
'fetch-error',
|
||||||
|
|
@ -47,11 +50,11 @@ const emit = defineEmits([
|
||||||
'change',
|
'change',
|
||||||
'columns-change',
|
'columns-change',
|
||||||
])
|
])
|
||||||
|
|
||||||
const slots = useSlots()
|
const slots = useSlots()
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
|
||||||
const tableElRef = ref(null)
|
const tableElRef = ref(null)
|
||||||
const tableData = ref<Recordable[]>([])
|
const tableData = ref([])
|
||||||
|
|
||||||
const wrapRef = ref(null)
|
const wrapRef = ref(null)
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
|
|
@ -72,7 +75,13 @@ watchEffect(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const { getLoading, setLoading } = useLoading(getProps)
|
const { getLoading, setLoading } = useLoading(getProps)
|
||||||
const { getPaginationInfo, getPagination, setPagination, setShowPagination, getShowPagination } = usePagination(getProps)
|
const {
|
||||||
|
getPaginationInfo,
|
||||||
|
getPagination,
|
||||||
|
setPagination,
|
||||||
|
setShowPagination,
|
||||||
|
getShowPagination,
|
||||||
|
} = usePagination(getProps)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
getRowSelection,
|
getRowSelection,
|
||||||
|
|
@ -121,10 +130,16 @@ function handleTableChange(pagination: any, filters: any, sorter: any, extra: an
|
||||||
onChange && isFunction(onChange) && onChange(pagination, filters, sorter, extra)
|
onChange && isFunction(onChange) && onChange(pagination, filters, sorter, extra)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { getViewColumns, getColumns, setCacheColumnsByField, setCacheColumns, setColumns, getColumnsRef, getCacheColumns } = useColumns(
|
const {
|
||||||
getProps,
|
getViewColumns,
|
||||||
getPaginationInfo,
|
getColumns,
|
||||||
)
|
setCacheColumnsByField,
|
||||||
|
setCacheColumns,
|
||||||
|
setColumnWidth,
|
||||||
|
setColumns,
|
||||||
|
getColumnsRef,
|
||||||
|
getCacheColumns,
|
||||||
|
} = useColumns(getProps, getPaginationInfo)
|
||||||
|
|
||||||
const { getScrollRef, redoHeight } = useTableScroll(
|
const { getScrollRef, redoHeight } = useTableScroll(
|
||||||
getProps,
|
getProps,
|
||||||
|
|
@ -148,7 +163,11 @@ const { customRow } = useCustomRow(getProps, {
|
||||||
|
|
||||||
const { getRowClassName } = useTableStyle(getProps, prefixCls)
|
const { getRowClassName } = useTableStyle(getProps, prefixCls)
|
||||||
|
|
||||||
const { getExpandOption, expandAll, expandRows, collapseAll } = useTableExpand(getProps, tableData, emit)
|
const { getExpandOption, expandAll, expandRows, collapseAll } = useTableExpand(
|
||||||
|
getProps,
|
||||||
|
tableData,
|
||||||
|
emit,
|
||||||
|
)
|
||||||
|
|
||||||
const handlers: InnerHandlers = {
|
const handlers: InnerHandlers = {
|
||||||
onColumnsChange: (data: ColumnChangeParam[]) => {
|
onColumnsChange: (data: ColumnChangeParam[]) => {
|
||||||
|
|
@ -160,18 +179,19 @@ const handlers: InnerHandlers = {
|
||||||
|
|
||||||
const { getHeaderProps } = useTableHeader(getProps, slots, handlers)
|
const { getHeaderProps } = useTableHeader(getProps, slots, handlers)
|
||||||
|
|
||||||
const { getFooterProps } = useTableFooter(getProps, getScrollRef, tableElRef, getDataSourceRef)
|
const { getFooterProps } = useTableFooter(
|
||||||
|
|
||||||
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange, getShowForm, setShowForm } = useTableForm(
|
|
||||||
getProps,
|
getProps,
|
||||||
slots,
|
getScrollRef,
|
||||||
fetch,
|
tableElRef,
|
||||||
getLoading,
|
getDataSourceRef,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange, getShowForm, setShowForm }
|
||||||
|
= useTableForm(getProps, slots, fetch, getLoading)
|
||||||
|
|
||||||
const getBindValues = computed(() => {
|
const getBindValues = computed(() => {
|
||||||
const dataSource = unref(getDataSourceRef)
|
const dataSource = unref(getDataSourceRef)
|
||||||
let propsData: Recordable = {
|
let propsData: any = {
|
||||||
...attrs,
|
...attrs,
|
||||||
customRow,
|
customRow,
|
||||||
...unref(getProps),
|
...unref(getProps),
|
||||||
|
|
@ -219,10 +239,6 @@ function setProps(props: Partial<BasicTableProps>) {
|
||||||
innerPropsRef.value = { ...unref(innerPropsRef), ...props }
|
innerPropsRef.value = { ...unref(innerPropsRef), ...props }
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleResizeColumn(w, col) {
|
|
||||||
col.width = w
|
|
||||||
}
|
|
||||||
|
|
||||||
const tableAction: TableActionType = {
|
const tableAction: TableActionType = {
|
||||||
reload,
|
reload,
|
||||||
getSelectRows,
|
getSelectRows,
|
||||||
|
|
@ -265,7 +281,7 @@ const tableAction: TableActionType = {
|
||||||
}
|
}
|
||||||
createTableContext({ ...tableAction, wrapRef, getBindValues })
|
createTableContext({ ...tableAction, wrapRef, getBindValues })
|
||||||
|
|
||||||
defineExpose({ tableAction })
|
defineExpose(tableAction)
|
||||||
|
|
||||||
emit('register', tableAction, formActions)
|
emit('register', tableAction, formActions)
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -293,7 +309,7 @@ emit('register', tableAction, formActions)
|
||||||
v-bind="getBindValues"
|
v-bind="getBindValues"
|
||||||
:row-class-name="getRowClassName"
|
:row-class-name="getRowClassName"
|
||||||
@change="handleTableChange"
|
@change="handleTableChange"
|
||||||
@resize-column="handleResizeColumn"
|
@resize-column="setColumnWidth"
|
||||||
>
|
>
|
||||||
<template v-for="item in Object.keys($slots)" #[item]="data" :key="item">
|
<template v-for="item in Object.keys($slots)" #[item]="data" :key="item">
|
||||||
<slot :name="item" v-bind="data || {}" />
|
<slot :name="item" v-bind="data || {}" />
|
||||||
|
|
@ -315,9 +331,10 @@ emit('register', tableAction, formActions)
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
|
@border-color: #cecece4d;
|
||||||
@prefix-cls: ~'@{namespace}-basic-table';
|
@prefix-cls: ~'@{namespace}-basic-table';
|
||||||
|
|
||||||
html[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
|
.ant-table-tbody > tr:hover.ant-table-row-selected > td,
|
||||||
.ant-table-tbody > tr.ant-table-row-selected td {
|
.ant-table-tbody > tr.ant-table-row-selected td {
|
||||||
background-color: #262626;
|
background-color: #262626;
|
||||||
|
|
@ -378,7 +395,7 @@ html[data-theme='dark'] {
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-pagination {
|
.ant-table-wrapper .ant-pagination {
|
||||||
margin: 10px 0 0;
|
margin: 10px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, toRaw, unref } from 'vue'
|
import { computed, toRaw, unref } from 'vue'
|
||||||
import { DownOutlined } from '@ant-design/icons-vue'
|
import { DownOutlined } from '@ant-design/icons-vue'
|
||||||
import type { TooltipProps } from 'ant-design-vue'
|
import type { TooltipProps } from 'ant-design-vue'
|
||||||
|
|
@ -60,7 +61,7 @@ const getActions = computed(() => {
|
||||||
.map((action) => {
|
.map((action) => {
|
||||||
const { popConfirm } = action
|
const { popConfirm } = action
|
||||||
return {
|
return {
|
||||||
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
|
getPopupContainer: () => unref((table as any)?.wrapRef) ?? document.body,
|
||||||
type: 'link',
|
type: 'link',
|
||||||
...action,
|
...action,
|
||||||
...(popConfirm || {}),
|
...(popConfirm || {}),
|
||||||
|
|
@ -96,7 +97,7 @@ const getAlign = computed(() => {
|
||||||
|
|
||||||
function getTooltip(data: string | TooltipProps): TooltipProps {
|
function getTooltip(data: string | TooltipProps): TooltipProps {
|
||||||
return {
|
return {
|
||||||
getPopupContainer: () => unref((table as any)?.wrapRef.value) ?? document.body,
|
getPopupContainer: () => unref((table as any)?.wrapRef) ?? document.body,
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
...(isString(data) ? { title: data } : data),
|
...(isString(data) ? { title: data } : data),
|
||||||
}
|
}
|
||||||
|
|
@ -130,9 +131,18 @@ function onCellClick(e: MouseEvent) {
|
||||||
{{ action.label }}
|
{{ action.label }}
|
||||||
</template>
|
</template>
|
||||||
</PopConfirmButton>
|
</PopConfirmButton>
|
||||||
<Divider v-if="divider && index < getActions.length - 1" type="vertical" class="action-divider" />
|
<Divider
|
||||||
|
v-if="divider && index < getActions.length - 1"
|
||||||
|
type="vertical"
|
||||||
|
class="action-divider"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<Dropdown v-if="dropDownActions && getDropdownList.length > 0" :trigger="['hover']" :drop-menu-list="getDropdownList" popconfirm>
|
<Dropdown
|
||||||
|
v-if="dropDownActions && getDropdownList.length > 0"
|
||||||
|
:trigger="['hover']"
|
||||||
|
:drop-menu-list="getDropdownList"
|
||||||
|
popconfirm
|
||||||
|
>
|
||||||
<slot name="more" />
|
<slot name="more" />
|
||||||
<a-button v-if="!$slots.more" type="link">
|
<a-button v-if="!$slots.more" type="link">
|
||||||
{{ t('action.more') }} <DownOutlined class="icon-more" />
|
{{ t('action.more') }} <DownOutlined class="icon-more" />
|
||||||
|
|
@ -191,6 +201,7 @@ function onCellClick(e: MouseEvent) {
|
||||||
|
|
||||||
.icon-more {
|
.icon-more {
|
||||||
margin-left: 0.25rem;
|
margin-left: 0.25rem;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, toRaw, unref } from 'vue'
|
import { computed, toRaw, unref } from 'vue'
|
||||||
import { Table } from 'ant-design-vue'
|
import { Table } from 'ant-design-vue'
|
||||||
import { cloneDeep } from 'lodash-es'
|
import { cloneDeep } from 'lodash-es'
|
||||||
|
|
@ -10,6 +11,7 @@ import { propTypes } from '@/utils/propTypes'
|
||||||
import { isFunction } from '@/utils/is'
|
import { isFunction } from '@/utils/is'
|
||||||
|
|
||||||
defineOptions({ name: 'BasicTableFooter' })
|
defineOptions({ name: 'BasicTableFooter' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
summaryFunc: {
|
summaryFunc: {
|
||||||
type: Function as PropType<Fn>,
|
type: Function as PropType<Fn>,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { Divider } from 'ant-design-vue'
|
import { Divider } from 'ant-design-vue'
|
||||||
import type { ColumnChangeParam, TableSetting } from '../types/table'
|
import type { ColumnChangeParam, TableSetting } from '../types/table'
|
||||||
import TableSettingComponent from './settings/index.vue'
|
import TableSettingComponent from './settings/index.vue'
|
||||||
|
|
@ -9,7 +10,7 @@ defineOptions({ name: 'BasicTableHeader' })
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: [Function, String] as PropType<string | ((data: Recordable) => string)>,
|
type: [Function, String] as PropType<string | ((data) => string)>,
|
||||||
},
|
},
|
||||||
tableSetting: {
|
tableSetting: {
|
||||||
type: Object as PropType<TableSetting>,
|
type: Object as PropType<TableSetting>,
|
||||||
|
|
@ -37,11 +38,19 @@ function handleColumnChange(data: ColumnChangeParam[]) {
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<slot v-if="$slots.tableTitle" name="tableTitle" />
|
<slot v-if="$slots.tableTitle" name="tableTitle" />
|
||||||
<TableTitle v-if="!$slots.tableTitle && title" :help-message="titleHelpMessage" :title="title" />
|
<TableTitle
|
||||||
|
v-if="!$slots.tableTitle && title"
|
||||||
|
:help-message="titleHelpMessage"
|
||||||
|
:title="title"
|
||||||
|
/>
|
||||||
<div :class="`${prefixCls}__toolbar`">
|
<div :class="`${prefixCls}__toolbar`">
|
||||||
<slot name="toolbar" />
|
<slot name="toolbar" />
|
||||||
<Divider v-if="$slots.toolbar && showTableSetting" type="vertical" />
|
<Divider v-if="$slots.toolbar && showTableSetting" type="vertical" />
|
||||||
<TableSettingComponent v-if="showTableSetting" :setting="tableSetting" @columns-change="handleColumnChange" />
|
<TableSettingComponent
|
||||||
|
v-if="showTableSetting"
|
||||||
|
:setting="tableSetting"
|
||||||
|
@columns-change="handleColumnChange"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties } from 'vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { Badge, Image, ImagePreviewGroup } from 'ant-design-vue'
|
import { Badge, Image } from 'ant-design-vue'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { propTypes } from '@/utils/propTypes'
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
|
||||||
|
|
@ -20,11 +20,12 @@ const props = defineProps({
|
||||||
srcPrefix: propTypes.string.def(''),
|
srcPrefix: propTypes.string.def(''),
|
||||||
// fallback,加载失败显示图像占位符。
|
// fallback,加载失败显示图像占位符。
|
||||||
fallback: propTypes.string.def(
|
fallback: propTypes.string.def(
|
||||||
|
|
||||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==',
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg==',
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const PreviewGroup = Image.PreviewGroup
|
||||||
|
|
||||||
const getWrapStyle = computed((): CSSProperties => {
|
const getWrapStyle = computed((): CSSProperties => {
|
||||||
const { size } = props
|
const { size } = props
|
||||||
const s = `${size}px`
|
const s = `${size}px`
|
||||||
|
|
@ -35,10 +36,15 @@ const { prefixCls } = useDesign('basic-table-img')
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="imgList && imgList.length" :class="prefixCls" class="mx-auto flex items-center" :style="getWrapStyle">
|
<div
|
||||||
|
v-if="imgList && imgList.length"
|
||||||
|
:class="prefixCls"
|
||||||
|
class="mx-auto flex items-center"
|
||||||
|
:style="getWrapStyle"
|
||||||
|
>
|
||||||
<Badge v-if="simpleShow" :count="!showBadge || imgList.length === 1 ? 0 : imgList.length">
|
<Badge v-if="simpleShow" :count="!showBadge || imgList.length === 1 ? 0 : imgList.length">
|
||||||
<div class="img-div">
|
<div class="img-div">
|
||||||
<ImagePreviewGroup>
|
<PreviewGroup>
|
||||||
<template v-for="(img, index) in imgList" :key="img">
|
<template v-for="(img, index) in imgList" :key="img">
|
||||||
<Image
|
<Image
|
||||||
:width="size"
|
:width="size"
|
||||||
|
|
@ -49,14 +55,19 @@ const { prefixCls } = useDesign('basic-table-img')
|
||||||
:fallback="fallback"
|
:fallback="fallback"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</ImagePreviewGroup>
|
</PreviewGroup>
|
||||||
</div>
|
</div>
|
||||||
</Badge>
|
</Badge>
|
||||||
<ImagePreviewGroup v-else>
|
<PreviewGroup v-else>
|
||||||
<template v-for="(img, index) in imgList" :key="img">
|
<template v-for="(img, index) in imgList" :key="img">
|
||||||
<Image :width="size" :style="{ marginLeft: index === 0 ? 0 : `${margin}px` }" :src="srcPrefix + img" :fallback="fallback" />
|
<Image
|
||||||
|
:width="size"
|
||||||
|
:style="{ marginLeft: index === 0 ? 0 : `${margin}px` }"
|
||||||
|
:src="srcPrefix + img"
|
||||||
|
:fallback="fallback"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</ImagePreviewGroup>
|
</PreviewGroup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { BasicTitle } from '@/components/Basic'
|
import { BasicTitle } from '@/components/Basic'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
@ -8,10 +9,10 @@ defineOptions({ name: 'BasicTableTitle' })
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: [Function, String] as PropType<string | ((data: Recordable) => string)>,
|
type: [Function, String] as PropType<string | ((data) => string)>,
|
||||||
},
|
},
|
||||||
getSelectRows: {
|
getSelectRows: {
|
||||||
type: Function as PropType<() => Recordable[]>,
|
type: Function as PropType<() => any[]>,
|
||||||
},
|
},
|
||||||
helpMessage: {
|
helpMessage: {
|
||||||
type: [String, Array] as PropType<string | string[]>,
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<!-- eslint-disable vue/no-mutating-props -->
|
<!-- eslint-disable vue/no-mutating-props -->
|
||||||
<script lang="tsx">
|
<script lang="tsx">
|
||||||
import type { CSSProperties } from 'vue'
|
import type { CSSProperties, PropType } from 'vue'
|
||||||
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue'
|
import { computed, defineComponent, nextTick, ref, toRaw, unref, watchEffect } from 'vue'
|
||||||
import { CheckOutlined, CloseOutlined, FormOutlined } from '@ant-design/icons-vue'
|
import { CheckOutlined, CloseOutlined, FormOutlined } from '@ant-design/icons-vue'
|
||||||
import { pick, set } from 'lodash-es'
|
import { pick, set } from 'lodash-es'
|
||||||
|
|
@ -8,9 +8,8 @@ import { Spin } from 'ant-design-vue'
|
||||||
import type { BasicColumn } from '../../types/table'
|
import type { BasicColumn } from '../../types/table'
|
||||||
import { useTableContext } from '../../hooks/useTableContext'
|
import { useTableContext } from '../../hooks/useTableContext'
|
||||||
import { CellComponent } from './CellComponent'
|
import { CellComponent } from './CellComponent'
|
||||||
import { createPlaceholderMessage } from './helper'
|
|
||||||
import type { EditRecordRow } from './index'
|
|
||||||
|
|
||||||
|
import { createPlaceholderMessage } from './helper'
|
||||||
import { useDesign } from '@/hooks/web/useDesign'
|
import { useDesign } from '@/hooks/web/useDesign'
|
||||||
|
|
||||||
import clickOutside from '@/directives/clickOutside'
|
import clickOutside from '@/directives/clickOutside'
|
||||||
|
|
@ -27,11 +26,13 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: [String, Number, Boolean, Object] as PropType<string | number | boolean | Recordable>,
|
type: [String, Number, Boolean, Object] as PropType<
|
||||||
|
string | number | boolean | Record<string, any>
|
||||||
|
>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
record: {
|
record: {
|
||||||
type: Object as PropType<EditRecordRow>,
|
type: Object as any,
|
||||||
},
|
},
|
||||||
column: {
|
column: {
|
||||||
type: Object as PropType<BasicColumn>,
|
type: Object as PropType<BasicColumn>,
|
||||||
|
|
@ -45,7 +46,7 @@ export default defineComponent({
|
||||||
const elRef = ref()
|
const elRef = ref()
|
||||||
const ruleOpen = ref(false)
|
const ruleOpen = ref(false)
|
||||||
const ruleMessage = ref('')
|
const ruleMessage = ref('')
|
||||||
const optionsRef = ref<LabelValueOptions>([])
|
const optionsRef = ref([])
|
||||||
const currentValueRef = ref<any>(props.value)
|
const currentValueRef = ref<any>(props.value)
|
||||||
const defaultValueRef = ref<any>(props.value)
|
const defaultValueRef = ref<any>(props.value)
|
||||||
const spinning = ref<boolean>(false)
|
const spinning = ref<boolean>(false)
|
||||||
|
|
@ -63,7 +64,6 @@ export default defineComponent({
|
||||||
const component = unref(getComponent)
|
const component = unref(getComponent)
|
||||||
return ['Checkbox', 'Switch'].includes(component)
|
return ['Checkbox', 'Switch'].includes(component)
|
||||||
})
|
})
|
||||||
|
|
||||||
const getDisable = computed(() => {
|
const getDisable = computed(() => {
|
||||||
const { editDynamicDisabled } = props.column
|
const { editDynamicDisabled } = props.column
|
||||||
let disabled = false
|
let disabled = false
|
||||||
|
|
@ -85,7 +85,7 @@ export default defineComponent({
|
||||||
|
|
||||||
const value = isCheckValue ? (isNumber(val) || isBoolean(val) ? val : !!val) : val
|
const value = isCheckValue ? (isNumber(val) || isBoolean(val) ? val : !!val) : val
|
||||||
|
|
||||||
let compProps = props.column?.editComponentProps ?? {}
|
let compProps = props.column?.editComponentProps ?? ({} as any)
|
||||||
const { record, column, index } = props
|
const { record, column, index } = props
|
||||||
|
|
||||||
if (isFunction(compProps))
|
if (isFunction(compProps))
|
||||||
|
|
@ -96,7 +96,7 @@ export default defineComponent({
|
||||||
delete compProps.onChange
|
delete compProps.onChange
|
||||||
|
|
||||||
const component = unref(getComponent)
|
const component = unref(getComponent)
|
||||||
const apiSelectProps: Recordable = {}
|
const apiSelectProps: Record<string, any> = {}
|
||||||
if (component === 'ApiSelect')
|
if (component === 'ApiSelect')
|
||||||
apiSelectProps.cache = true
|
apiSelectProps.cache = true
|
||||||
|
|
||||||
|
|
@ -133,12 +133,11 @@ export default defineComponent({
|
||||||
if (!component.includes('Select') && !component.includes('Radio'))
|
if (!component.includes('Select') && !component.includes('Radio'))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
const options: LabelValueOptions = unref(getComponentProps)?.options ?? (unref(optionsRef) || [])
|
const options = unref(getComponentProps)?.options ?? (unref(optionsRef) || [])
|
||||||
const option = options.find(item => `${item.value}` === `${value}`)
|
const option = options.find(item => `${item.value}` === `${value}`)
|
||||||
|
|
||||||
return option?.label ?? value
|
return option?.label ?? value
|
||||||
})
|
})
|
||||||
|
|
||||||
const getRowEditable = computed(() => {
|
const getRowEditable = computed(() => {
|
||||||
const { editable } = props.record || {}
|
const { editable } = props.record || {}
|
||||||
return !!editable
|
return !!editable
|
||||||
|
|
@ -184,12 +183,16 @@ export default defineComponent({
|
||||||
const component = unref(getComponent)
|
const component = unref(getComponent)
|
||||||
if (!e)
|
if (!e)
|
||||||
currentValueRef.value = e
|
currentValueRef.value = e
|
||||||
|
|
||||||
else if (component === 'Checkbox')
|
else if (component === 'Checkbox')
|
||||||
currentValueRef.value = (e as ChangeEvent).target.checked
|
currentValueRef.value = e.target.checked
|
||||||
|
|
||||||
else if (component === 'Switch')
|
else if (component === 'Switch')
|
||||||
currentValueRef.value = e
|
currentValueRef.value = e
|
||||||
|
|
||||||
else if (e?.target && Reflect.has(e.target, 'value'))
|
else if (e?.target && Reflect.has(e.target, 'value'))
|
||||||
currentValueRef.value = (e as ChangeEvent).target.value
|
currentValueRef.value = e.target.value
|
||||||
|
|
||||||
else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e))
|
else if (isString(e) || isBoolean(e) || isNumber(e) || isArray(e))
|
||||||
currentValueRef.value = e
|
currentValueRef.value = e
|
||||||
|
|
||||||
|
|
@ -219,7 +222,7 @@ export default defineComponent({
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (isFunction(editRule)) {
|
if (isFunction(editRule)) {
|
||||||
const res = await editRule(currentValue, record as Recordable)
|
const res = await editRule(currentValue, record)
|
||||||
if (res) {
|
if (res) {
|
||||||
ruleMessage.value = res
|
ruleMessage.value = res
|
||||||
ruleOpen.value = true
|
ruleOpen.value = true
|
||||||
|
|
@ -259,7 +262,9 @@ export default defineComponent({
|
||||||
|
|
||||||
if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
|
if (beforeEditSubmit && isFunction(beforeEditSubmit)) {
|
||||||
spinning.value = true
|
spinning.value = true
|
||||||
const keys: string[] = columns.map(_column => _column.dataIndex).filter(field => !!field) as string[]
|
const keys: string[] = columns
|
||||||
|
.map(_column => _column.dataIndex)
|
||||||
|
.filter(field => !!field) as string[]
|
||||||
let result: any = true
|
let result: any = true
|
||||||
try {
|
try {
|
||||||
result = await beforeEditSubmit({
|
result = await beforeEditSubmit({
|
||||||
|
|
@ -322,28 +327,31 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
// only ApiSelect or TreeSelect
|
// only ApiSelect or TreeSelect
|
||||||
function handleOptionsChange(options: LabelValueOptions) {
|
function handleOptionsChange(options) {
|
||||||
const { replaceFields } = unref(getComponentProps)
|
const { replaceFields } = unref(getComponentProps)
|
||||||
const component = unref(getComponent)
|
const component = unref(getComponent)
|
||||||
if (component === 'ApiTreeSelect') {
|
if (component === 'ApiTreeSelect') {
|
||||||
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {}
|
const { title = 'title', value = 'value', children = 'children' } = replaceFields || {}
|
||||||
let listOptions: Recordable[] = treeToList(options, { children })
|
let listOptions = treeToList(options, { children })
|
||||||
listOptions = listOptions.map((item) => {
|
listOptions = listOptions.map((item) => {
|
||||||
return {
|
return {
|
||||||
label: item[title],
|
label: item[title],
|
||||||
value: item[value],
|
value: item[value],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
optionsRef.value = listOptions as LabelValueOptions
|
optionsRef.value = listOptions
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
optionsRef.value = options
|
optionsRef.value = options
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle: Fn) {
|
function initCbs(cbs: 'submitCbs' | 'validCbs' | 'cancelCbs', handle) {
|
||||||
if (props.record)
|
if (props.record) {
|
||||||
isArray(props.record[cbs]) ? props.record[cbs]?.push(handle) : (props.record[cbs] = [handle])
|
isArray(props.record[cbs])
|
||||||
|
? props.record[cbs]?.push(handle)
|
||||||
|
: (props.record[cbs] = [handle])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.record) {
|
if (props.record) {
|
||||||
|
|
@ -434,7 +442,10 @@ export default defineComponent({
|
||||||
/>
|
/>
|
||||||
{!this.getRowEditable && (
|
{!this.getRowEditable && (
|
||||||
<div class={`${this.prefixCls}__action`}>
|
<div class={`${this.prefixCls}__action`}>
|
||||||
<CheckOutlined class={[`${this.prefixCls}__icon`, 'mx-2']} onClick={this.handleSubmitClick} />
|
<CheckOutlined
|
||||||
|
class={[`${this.prefixCls}__icon`, 'mx-2']}
|
||||||
|
onClick={this.handleSubmitClick}
|
||||||
|
/>
|
||||||
<CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} />
|
<CloseOutlined class={`${this.prefixCls}__icon `} onClick={this.handleCancel} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -477,10 +488,12 @@ export default defineComponent({
|
||||||
.edit-cell-rule-popover {
|
.edit-cell-rule-popover {
|
||||||
.ant-popover-inner-content {
|
.ant-popover-inner-content {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
|
color: @error-color;
|
||||||
// border: 1px solid @error-color;
|
// border: 1px solid @error-color;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{prefix-cls} {
|
.@{prefix-cls} {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 24px; // 设置高度让其始终可被hover
|
min-height: 24px; // 设置高度让其始终可被hover
|
||||||
|
|
@ -490,7 +503,7 @@ export default defineComponent({
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
> .ant-select {
|
>.ant-select {
|
||||||
min-width: calc(100% - 50px);
|
min-width: calc(100% - 50px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -498,6 +511,10 @@ export default defineComponent({
|
||||||
&__icon {
|
&__icon {
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.2);
|
transform: scale(1.2);
|
||||||
|
|
||||||
|
svg {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@ import { useDesign } from '@/hooks/web/useDesign'
|
||||||
import { isFunction, isNullAndUnDef } from '@/utils/is'
|
import { isFunction, isNullAndUnDef } from '@/utils/is'
|
||||||
import { getPopupContainer as getParentContainer } from '@/utils'
|
import { getPopupContainer as getParentContainer } from '@/utils'
|
||||||
|
|
||||||
defineOptions({ name: 'ColumnSetting' })
|
|
||||||
|
|
||||||
const emit = defineEmits(['columns-change'])
|
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
checkAll: boolean
|
checkAll: boolean
|
||||||
isInit?: boolean
|
isInit?: boolean
|
||||||
|
|
@ -33,6 +29,10 @@ interface Options {
|
||||||
fixed?: boolean | 'left' | 'right'
|
fixed?: boolean | 'left' | 'right'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineOptions({ name: 'ColumnSetting' })
|
||||||
|
|
||||||
|
const emit = defineEmits(['columns-change'])
|
||||||
|
|
||||||
const CheckboxGroup = Checkbox.Group
|
const CheckboxGroup = Checkbox.Group
|
||||||
const attrs = useAttrs()
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ const plainOptions = ref<Options[] | any>([])
|
||||||
|
|
||||||
const plainSortOptions = ref<Options[]>([])
|
const plainSortOptions = ref<Options[]>([])
|
||||||
|
|
||||||
const columnListRef = ref<ComponentRef>(null)
|
const columnListRef = ref(null)
|
||||||
|
|
||||||
const state = reactive<State>({
|
const state = reactive<State>({
|
||||||
checkAll: true,
|
checkAll: true,
|
||||||
|
|
@ -124,7 +124,6 @@ async function init(isReset = false) {
|
||||||
return item.dataIndex || item.title
|
return item.dataIndex || item.title
|
||||||
})
|
})
|
||||||
.filter(Boolean) as string[]
|
.filter(Boolean) as string[]
|
||||||
|
|
||||||
plainOptions.value = columns
|
plainOptions.value = columns
|
||||||
plainSortOptions.value = columns
|
plainSortOptions.value = columns
|
||||||
// 更新缓存配置
|
// 更新缓存配置
|
||||||
|
|
@ -136,13 +135,14 @@ async function init(isReset = false) {
|
||||||
state.checkAll = checkList.length === columns.length
|
state.checkAll = checkList.length === columns.length
|
||||||
inited = false
|
inited = false
|
||||||
handleOpenChange()
|
handleOpenChange()
|
||||||
state.checkedList = checkList
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAll change
|
// checkAll change
|
||||||
function onCheckAllChange(e: CheckboxChangeEvent) {
|
function onCheckAllChange(e: CheckboxChangeEvent) {
|
||||||
const checkList = plainSortOptions.value.map(item => item.value)
|
const checkList = plainSortOptions.value.map(item => item.value)
|
||||||
plainSortOptions.value.forEach(item => ((item as BasicColumn).defaultHidden = !e.target.checked))
|
plainSortOptions.value.forEach(
|
||||||
|
item => ((item as BasicColumn).defaultHidden = !e.target.checked),
|
||||||
|
)
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
state.checkedList = checkList
|
state.checkedList = checkList
|
||||||
setColumns(checkList)
|
setColumns(checkList)
|
||||||
|
|
@ -169,7 +169,7 @@ function onChange(checkedList: string[]) {
|
||||||
return sortList.indexOf(prev) - sortList.indexOf(next)
|
return sortList.indexOf(prev) - sortList.indexOf(next)
|
||||||
})
|
})
|
||||||
unref(plainSortOptions).forEach((item) => {
|
unref(plainSortOptions).forEach((item) => {
|
||||||
;(item as BasicColumn).defaultHidden = !checkedList.includes(item.value)
|
(item as BasicColumn).defaultHidden = !checkedList.includes(item.value)
|
||||||
})
|
})
|
||||||
setColumns(checkedList)
|
setColumns(checkedList)
|
||||||
}
|
}
|
||||||
|
|
@ -197,7 +197,7 @@ function handleOpenChange() {
|
||||||
const columnListEl = unref(columnListRef)
|
const columnListEl = unref(columnListRef)
|
||||||
if (!columnListEl)
|
if (!columnListEl)
|
||||||
return
|
return
|
||||||
const el = columnListEl.$el as any
|
const el = (columnListEl as any).$el
|
||||||
if (!el)
|
if (!el)
|
||||||
return
|
return
|
||||||
// Drag and drop sort
|
// Drag and drop sort
|
||||||
|
|
@ -256,7 +256,9 @@ function handleColumnFixed(item: BasicColumn, fixed?: 'left' | 'right') {
|
||||||
if (!state.checkedList.includes(item.dataIndex as string))
|
if (!state.checkedList.includes(item.dataIndex as string))
|
||||||
return
|
return
|
||||||
|
|
||||||
const columns = getColumns().filter((c: BasicColumn) => state.checkedList.includes(c.dataIndex as string)) as BasicColumn[]
|
const columns = getColumns().filter((c: BasicColumn) =>
|
||||||
|
state.checkedList.includes(c.dataIndex as string),
|
||||||
|
) as BasicColumn[]
|
||||||
const isFixed = item.fixed === fixed ? false : fixed
|
const isFixed = item.fixed === fixed ? false : fixed
|
||||||
const index = columns.findIndex(col => col.dataIndex === item.dataIndex)
|
const index = columns.findIndex(col => col.dataIndex === item.dataIndex)
|
||||||
if (index !== -1)
|
if (index !== -1)
|
||||||
|
|
@ -278,7 +280,10 @@ function setColumns(columns: BasicColumn[] | string[]) {
|
||||||
table.setColumns(columns)
|
table.setColumns(columns)
|
||||||
const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
|
const data: ColumnChangeParam[] = unref(plainSortOptions).map((col) => {
|
||||||
const open
|
const open
|
||||||
= columns.findIndex((c: BasicColumn | string) => c === col.value || (typeof c !== 'string' && c.dataIndex === col.value)) !== -1
|
= columns.findIndex(
|
||||||
|
(c: BasicColumn | string) =>
|
||||||
|
c === col.value || (typeof c !== 'string' && c.dataIndex === col.value),
|
||||||
|
) !== -1
|
||||||
return { dataIndex: col.value, fixed: col.fixed, open }
|
return { dataIndex: col.value, fixed: col.fixed, open }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -286,7 +291,9 @@ function setColumns(columns: BasicColumn[] | string[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPopupContainer() {
|
function getPopupContainer() {
|
||||||
return isFunction(attrs.getPopupContainer) ? attrs.getPopupContainer() : getParentContainer()
|
return isFunction(attrs.getPopupContainer)
|
||||||
|
? attrs.getPopupContainer()
|
||||||
|
: getParentContainer()
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSortOption(column: BasicColumn) {
|
function updateSortOption(column: BasicColumn) {
|
||||||
|
|
@ -406,6 +413,10 @@ function updateSortOption(column: BasicColumn) {
|
||||||
|
|
||||||
.ant-checkbox-wrapper {
|
.ant-checkbox-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -414,6 +425,11 @@ function updateSortOption(column: BasicColumn) {
|
||||||
color: rgb(0 0 0 / 45%);
|
color: rgb(0 0 0 / 45%);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active,
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color;
|
||||||
|
}
|
||||||
|
|
||||||
&.disabled {
|
&.disabled {
|
||||||
color: @disabled-color;
|
color: @disabled-color;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import { computed, unref } from 'vue'
|
import { computed, unref } from 'vue'
|
||||||
import type { ColumnChangeParam, TableSetting } from '../../types/table'
|
import type { ColumnChangeParam, TableSetting } from '../../types/table'
|
||||||
import { useTableContext } from '../../hooks/useTableContext'
|
import { useTableContext } from '../../hooks/useTableContext'
|
||||||
|
|
@ -44,7 +45,11 @@ function getTableContainer() {
|
||||||
<RedoSetting v-if="getSetting.redo" :get-popup-container="getTableContainer" />
|
<RedoSetting v-if="getSetting.redo" :get-popup-container="getTableContainer" />
|
||||||
<FormSetting v-if="getSetting.form" :get-popup-container="getTableContainer" />
|
<FormSetting v-if="getSetting.form" :get-popup-container="getTableContainer" />
|
||||||
<SizeSetting v-if="getSetting.size" :get-popup-container="getTableContainer" />
|
<SizeSetting v-if="getSetting.size" :get-popup-container="getTableContainer" />
|
||||||
<ColumnSetting v-if="getSetting.setting" :get-popup-container="getTableContainer" @columns-change="handleColumnChange" />
|
<ColumnSetting
|
||||||
|
v-if="getSetting.setting"
|
||||||
|
:get-popup-container="getTableContainer"
|
||||||
|
@columns-change="handleColumnChange"
|
||||||
|
/>
|
||||||
<FullScreenSetting v-if="getSetting.fullScreen" :get-popup-container="getTableContainer" />
|
<FullScreenSetting v-if="getSetting.fullScreen" :get-popup-container="getTableContainer" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,14 @@ import componentSetting from '@/settings/componentSetting'
|
||||||
|
|
||||||
const { table } = componentSetting
|
const { table } = componentSetting
|
||||||
|
|
||||||
const { pageSizeOptions, defaultPageSize, fetchSetting, defaultSize, defaultSortFn, defaultFilterFn } = table
|
const {
|
||||||
|
pageSizeOptions,
|
||||||
|
defaultPageSize,
|
||||||
|
fetchSetting,
|
||||||
|
defaultSize,
|
||||||
|
defaultSortFn,
|
||||||
|
defaultFilterFn,
|
||||||
|
} = table
|
||||||
|
|
||||||
export const ROW_KEY = 'key'
|
export const ROW_KEY = 'key'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,10 @@ function handleActionColumn(propsRef: ComputedRef<BasicTableProps>, columns: Bas
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useColumns(propsRef: ComputedRef<BasicTableProps>, getPaginationRef: ComputedRef<boolean | PaginationProps>) {
|
export function useColumns(
|
||||||
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
|
getPaginationRef: ComputedRef<boolean | PaginationProps>,
|
||||||
|
) {
|
||||||
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>
|
const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>
|
||||||
let cacheColumns = unref(propsRef).columns
|
let cacheColumns = unref(propsRef).columns
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,11 @@ interface Options {
|
||||||
getAutoCreateKey: ComputedRef<boolean | undefined>
|
getAutoCreateKey: ComputedRef<boolean | undefined>
|
||||||
}
|
}
|
||||||
|
|
||||||
function getKey(record: Recordable, rowKey: string | ((record: Record<string, any>) => string) | undefined, autoCreateKey?: boolean) {
|
function getKey(
|
||||||
|
record: Recordable,
|
||||||
|
rowKey: string | ((record: Record<string, any>) => string) | undefined,
|
||||||
|
autoCreateKey?: boolean,
|
||||||
|
) {
|
||||||
if (!rowKey || autoCreateKey)
|
if (!rowKey || autoCreateKey)
|
||||||
return record[ROW_KEY]
|
return record[ROW_KEY]
|
||||||
|
|
||||||
|
|
@ -40,13 +44,15 @@ export function useCustomRow(
|
||||||
return
|
return
|
||||||
const keys = getSelectRowKeys() || []
|
const keys = getSelectRowKeys() || []
|
||||||
const key = getKey(record, rowKey, unref(getAutoCreateKey))
|
const key = getKey(record, rowKey, unref(getAutoCreateKey))
|
||||||
if (!key)
|
if (key === null)
|
||||||
return
|
return
|
||||||
|
|
||||||
const isCheckbox = rowSelection.type === 'checkbox'
|
const isCheckbox = rowSelection.type === 'checkbox'
|
||||||
if (isCheckbox) {
|
if (isCheckbox) {
|
||||||
// 找到tr
|
// 找到tr
|
||||||
const tr: HTMLElement = (e as MouseEvent).composedPath?.().find((dom: HTMLElement) => dom.tagName === 'TR') as HTMLElement
|
const tr = (e as MouseEvent)
|
||||||
|
.composedPath?.()
|
||||||
|
.find(dom => (dom as HTMLElement).tagName === 'TR') as HTMLElement
|
||||||
if (!tr)
|
if (!tr)
|
||||||
return
|
return
|
||||||
// 找到Checkbox,检查是否为disabled
|
// 找到Checkbox,检查是否为disabled
|
||||||
|
|
@ -54,7 +60,8 @@ export function useCustomRow(
|
||||||
if (!checkBox || checkBox.hasAttribute('disabled'))
|
if (!checkBox || checkBox.hasAttribute('disabled'))
|
||||||
return
|
return
|
||||||
if (!keys.includes(key)) {
|
if (!keys.includes(key)) {
|
||||||
setSelectedRowKeys([...keys, key])
|
keys.push(key)
|
||||||
|
setSelectedRowKeys(keys)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const keyIndex = keys.findIndex(item => item === key)
|
const keyIndex = keys.findIndex(item => item === key)
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@ import type { ComputedRef, Ref } from 'vue'
|
||||||
import { computed, onMounted, reactive, ref, unref, watch, watchEffect } from 'vue'
|
import { computed, onMounted, reactive, ref, unref, watch, watchEffect } from 'vue'
|
||||||
import { useTimeoutFn } from '@vueuse/core'
|
import { useTimeoutFn } from '@vueuse/core'
|
||||||
import { cloneDeep, get, merge } from 'lodash-es'
|
import { cloneDeep, get, merge } from 'lodash-es'
|
||||||
import type { BasicTableProps, FetchParams, SorterResult } from '../types/table'
|
|
||||||
import type { PaginationProps } from '../types/pagination'
|
import type { PaginationProps } from '../types/pagination'
|
||||||
|
import type { BasicTableProps, FetchParams, SorterResult } from '../types/table'
|
||||||
import { FETCH_SETTING, PAGE_SIZE, ROW_KEY } from '../const'
|
import { FETCH_SETTING, PAGE_SIZE, ROW_KEY } from '../const'
|
||||||
import { buildUUID } from '@/utils/uuid'
|
|
||||||
import { isBoolean, isFunction, isObject } from '@/utils/is'
|
import { isBoolean, isFunction, isObject } from '@/utils/is'
|
||||||
|
import { buildUUID } from '@/utils/uuid'
|
||||||
|
|
||||||
interface ActionType {
|
interface ActionType {
|
||||||
getPaginationInfo: ComputedRef<boolean | PaginationProps>
|
getPaginationInfo: ComputedRef<boolean | PaginationProps>
|
||||||
|
|
@ -23,7 +23,14 @@ interface SearchState {
|
||||||
}
|
}
|
||||||
export function useDataSource(
|
export function useDataSource(
|
||||||
propsRef: ComputedRef<BasicTableProps>,
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
{ getPaginationInfo, setPagination, setLoading, getFieldsValue, clearSelectedRowKeys, tableData }: ActionType,
|
{
|
||||||
|
getPaginationInfo,
|
||||||
|
setPagination,
|
||||||
|
setLoading,
|
||||||
|
getFieldsValue,
|
||||||
|
clearSelectedRowKeys,
|
||||||
|
tableData,
|
||||||
|
}: ActionType,
|
||||||
emit: EmitType,
|
emit: EmitType,
|
||||||
) {
|
) {
|
||||||
const searchState = reactive<SearchState>({
|
const searchState = reactive<SearchState>({
|
||||||
|
|
@ -48,7 +55,11 @@ export function useDataSource(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
function handleTableChange(pagination: PaginationProps, filters: Partial<Recordable<string[]>>, sorter: SorterResult) {
|
function handleTableChange(
|
||||||
|
pagination: PaginationProps,
|
||||||
|
filters: Partial<Recordable<string[]>>,
|
||||||
|
sorter: SorterResult,
|
||||||
|
) {
|
||||||
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef)
|
const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef)
|
||||||
if (clearSelectOnPageChange)
|
if (clearSelectOnPageChange)
|
||||||
clearSelectedRowKeys()
|
clearSelectedRowKeys()
|
||||||
|
|
@ -117,7 +128,7 @@ export function useDataSource(
|
||||||
return unref(dataSourceRef)
|
return unref(dataSourceRef)
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateTableData(index: number, key: string, value: any) {
|
async function updateTableData(index: number, key: string, value: any) {
|
||||||
const record = dataSourceRef.value[index]
|
const record = dataSourceRef.value[index]
|
||||||
if (record)
|
if (record)
|
||||||
dataSourceRef.value[index][key] = value
|
dataSourceRef.value[index][key] = value
|
||||||
|
|
@ -125,7 +136,10 @@ export function useDataSource(
|
||||||
return dataSourceRef.value[index]
|
return dataSourceRef.value[index]
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTableDataRecord(rowKey: string | number, record: Recordable): Recordable | undefined {
|
function updateTableDataRecord(
|
||||||
|
rowKey: string | number,
|
||||||
|
record: Recordable,
|
||||||
|
): Recordable | undefined {
|
||||||
const row = findTableDataRecord(rowKey)
|
const row = findTableDataRecord(rowKey)
|
||||||
|
|
||||||
if (row) {
|
if (row) {
|
||||||
|
|
@ -185,7 +199,10 @@ export function useDataSource(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertTableDataRecord(record: Recordable | Recordable[], index?: number): Recordable[] | undefined {
|
function insertTableDataRecord(
|
||||||
|
record: Recordable | Recordable[],
|
||||||
|
index?: number,
|
||||||
|
): Recordable[] | undefined {
|
||||||
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
// if (!dataSourceRef.value || dataSourceRef.value.length == 0) return;
|
||||||
index = index ?? dataSourceRef.value?.length
|
index = index ?? dataSourceRef.value?.length
|
||||||
const _record = isObject(record) ? [record as Recordable] : (record as Recordable[])
|
const _record = isObject(record) ? [record as Recordable] : (record as Recordable[])
|
||||||
|
|
@ -207,7 +224,7 @@ export function useDataSource(
|
||||||
let ret
|
let ret
|
||||||
array.some(function iter(r) {
|
array.some(function iter(r) {
|
||||||
if (typeof rowKeyName === 'function') {
|
if (typeof rowKeyName === 'function') {
|
||||||
if ((rowKeyName(r)) === rowKey) {
|
if ((rowKeyName(r) as string) === rowKey) {
|
||||||
ret = r
|
ret = r
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -234,12 +251,25 @@ export function useDataSource(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetch(opt?: FetchParams) {
|
async function fetch(opt?: FetchParams) {
|
||||||
const { api, searchInfo, defSort, fetchSetting, beforeFetch, afterFetch, useSearchForm, pagination } = unref(propsRef)
|
const {
|
||||||
|
api,
|
||||||
|
searchInfo,
|
||||||
|
defSort,
|
||||||
|
fetchSetting,
|
||||||
|
beforeFetch,
|
||||||
|
afterFetch,
|
||||||
|
useSearchForm,
|
||||||
|
pagination,
|
||||||
|
} = unref(propsRef)
|
||||||
if (!api || !isFunction(api))
|
if (!api || !isFunction(api))
|
||||||
return
|
return
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const { pageField, sizeField, listField, totalField } = Object.assign({}, FETCH_SETTING, fetchSetting)
|
const { pageField, sizeField, listField, totalField } = Object.assign(
|
||||||
|
{},
|
||||||
|
FETCH_SETTING,
|
||||||
|
fetchSetting,
|
||||||
|
)
|
||||||
let pageParams: Recordable = {}
|
let pageParams: Recordable = {}
|
||||||
|
|
||||||
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps
|
const { current = 1, pageSize = PAGE_SIZE } = unref(getPaginationInfo) as PaginationProps
|
||||||
|
|
@ -317,8 +347,8 @@ export function useDataSource(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTableData<T extends Ref<Recordable<any>[]>>(values: T[]) {
|
function setTableData<T = Recordable>(values: T[]) {
|
||||||
dataSourceRef.value = values
|
dataSourceRef.value = values as Recordable[]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataSource<T = Recordable>() {
|
function getDataSource<T = Recordable>() {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ interface ItemRender {
|
||||||
function itemRender({ page, type, originalElement }: ItemRender) {
|
function itemRender({ page, type, originalElement }: ItemRender) {
|
||||||
if (type === 'prev')
|
if (type === 'prev')
|
||||||
return page === 0 ? null : <LeftOutlined />
|
return page === 0 ? null : <LeftOutlined />
|
||||||
|
|
||||||
else if (type === 'next')
|
else if (type === 'next')
|
||||||
return page === 1 ? null : <RightOutlined />
|
return page === 1 ? null : <RightOutlined />
|
||||||
|
|
||||||
|
|
@ -76,7 +77,7 @@ export function usePagination(refProps: ComputedRef<BasicTableProps>) {
|
||||||
return unref(show)
|
return unref(show)
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowPagination(flag: boolean) {
|
async function setShowPagination(flag: boolean) {
|
||||||
show.value = flag
|
show.value = flag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,17 @@ import type { ComputedRef, Ref } from 'vue'
|
||||||
import { nextTick, unref } from 'vue'
|
import { nextTick, unref } from 'vue'
|
||||||
import { warn } from '@/utils/log'
|
import { warn } from '@/utils/log'
|
||||||
|
|
||||||
export function useTableScrollTo(tableElRef: Ref<ComponentRef>, getDataSourceRef: ComputedRef<Recordable[]>) {
|
export function useTableScrollTo(
|
||||||
|
tableElRef: Ref<ComponentRef>,
|
||||||
|
getDataSourceRef: ComputedRef<Recordable[]>,
|
||||||
|
) {
|
||||||
let bodyEl: HTMLElement | null
|
let bodyEl: HTMLElement | null
|
||||||
|
|
||||||
async function findTargetRowToScroll(targetRowData: Recordable) {
|
async function findTargetRowToScroll(targetRowData: Recordable) {
|
||||||
const { id } = targetRowData
|
const { id } = targetRowData
|
||||||
const targetRowEl: HTMLElement | null | undefined = bodyEl?.querySelector(`[data-row-key="${id}"]`)
|
const targetRowEl: HTMLElement | null | undefined = bodyEl?.querySelector(
|
||||||
|
`[data-row-key="${id}"]`,
|
||||||
|
)
|
||||||
// Add a delay to get new dataSource
|
// Add a delay to get new dataSource
|
||||||
await nextTick()
|
await nextTick()
|
||||||
bodyEl?.scrollTo({
|
bodyEl?.scrollTo({
|
||||||
|
|
@ -46,6 +51,7 @@ export function useTableScrollTo(tableElRef: Ref<ComponentRef>, getDataSourceRef
|
||||||
const targetRowData = dataSource.find(data => data.id === pos)
|
const targetRowData = dataSource.find(data => data.id === pos)
|
||||||
if (targetRowData)
|
if (targetRowData)
|
||||||
findTargetRowToScroll(targetRowData)
|
findTargetRowToScroll(targetRowData)
|
||||||
|
|
||||||
else
|
else
|
||||||
warn(`id: ${pos} doesn't exist`)
|
warn(`id: ${pos} doesn't exist`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { WatchStopHandle } from 'vue'
|
import type { WatchStopHandle } from 'vue'
|
||||||
import { onUnmounted, ref, toRaw, unref, watch } from 'vue'
|
import { onUnmounted, ref, toRaw, unref, watch } from 'vue'
|
||||||
|
import type { Key } from 'ant-design-vue/lib/table/interface'
|
||||||
import type { BasicColumn, BasicTableProps, FetchParams, TableActionType } from '../types/table'
|
import type { BasicColumn, BasicTableProps, FetchParams, TableActionType } from '../types/table'
|
||||||
import type { PaginationProps } from '../types/pagination'
|
import type { PaginationProps } from '../types/pagination'
|
||||||
import type { DynamicProps } from '@/types/utils'
|
import type { DynamicProps } from '@/types/utils'
|
||||||
|
|
@ -57,9 +58,11 @@ export function useTable(tableProps?: Props): [
|
||||||
|
|
||||||
function getTableInstance(): TableActionType {
|
function getTableInstance(): TableActionType {
|
||||||
const table = unref(tableRef)
|
const table = unref(tableRef)
|
||||||
if (!table)
|
if (!table) {
|
||||||
error('The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!')
|
error(
|
||||||
|
'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!',
|
||||||
|
)
|
||||||
|
}
|
||||||
return table as TableActionType
|
return table as TableActionType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +94,7 @@ export function useTable(tableProps?: Props): [
|
||||||
const columns = getTableInstance().getColumns({ ignoreIndex }) || []
|
const columns = getTableInstance().getColumns({ ignoreIndex }) || []
|
||||||
return toRaw(columns)
|
return toRaw(columns)
|
||||||
},
|
},
|
||||||
setColumns: (columns: BasicColumn[]) => {
|
setColumns: (columns: BasicColumn[] | string[]) => {
|
||||||
getTableInstance().setColumns(columns)
|
getTableInstance().setColumns(columns)
|
||||||
},
|
},
|
||||||
setTableData: (values: any[]) => {
|
setTableData: (values: any[]) => {
|
||||||
|
|
@ -112,7 +115,7 @@ export function useTable(tableProps?: Props): [
|
||||||
clearSelectedRowKeys: () => {
|
clearSelectedRowKeys: () => {
|
||||||
getTableInstance().clearSelectedRowKeys()
|
getTableInstance().clearSelectedRowKeys()
|
||||||
},
|
},
|
||||||
setSelectedRowKeys: (keys: string[] | number[]) => {
|
setSelectedRowKeys: (keys: (string | number)[]) => {
|
||||||
getTableInstance().setSelectedRowKeys(keys)
|
getTableInstance().setSelectedRowKeys(keys)
|
||||||
},
|
},
|
||||||
getPaginationRef: () => {
|
getPaginationRef: () => {
|
||||||
|
|
@ -154,7 +157,7 @@ export function useTable(tableProps?: Props): [
|
||||||
expandAll: () => {
|
expandAll: () => {
|
||||||
getTableInstance().expandAll()
|
getTableInstance().expandAll()
|
||||||
},
|
},
|
||||||
expandRows: (keys: string[]) => {
|
expandRows: (keys: Key[]) => {
|
||||||
getTableInstance().expandRows(keys)
|
getTableInstance().expandRows(keys)
|
||||||
},
|
},
|
||||||
collapseAll: () => {
|
collapseAll: () => {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,11 @@ import { computed, ref, toRaw, unref } from 'vue'
|
||||||
import type { BasicTableProps } from '../types/table'
|
import type { BasicTableProps } from '../types/table'
|
||||||
import { ROW_KEY } from '../const'
|
import { ROW_KEY } from '../const'
|
||||||
|
|
||||||
export function useTableExpand(propsRef: ComputedRef<BasicTableProps>, tableData: Ref<Recordable[]>, emit: EmitType) {
|
export function useTableExpand(
|
||||||
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
|
tableData: Ref<Recordable[]>,
|
||||||
|
emit: EmitType,
|
||||||
|
) {
|
||||||
const expandedRowKeys = ref<(string | number)[]>([])
|
const expandedRowKeys = ref<(string | number)[]>([])
|
||||||
|
|
||||||
const getAutoCreateKey = computed(() => {
|
const getAutoCreateKey = computed(() => {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ export function useTableFooter(
|
||||||
|
|
||||||
const getFooterProps = computed((): Recordable | undefined => {
|
const getFooterProps = computed((): Recordable | undefined => {
|
||||||
const { summaryFunc, showSummary, summaryData } = unref(propsRef)
|
const { summaryFunc, showSummary, summaryData } = unref(propsRef)
|
||||||
return showSummary && !unref(getIsEmptyData) ? () => h(TableFooter, { summaryFunc, summaryData, scroll: unref(scrollRef) }) : undefined
|
return showSummary && !unref(getIsEmptyData)
|
||||||
|
? () => h(TableFooter, { summaryFunc, summaryData, scroll: unref(scrollRef) })
|
||||||
|
: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
|
|
@ -41,7 +43,9 @@ export function useTableFooter(
|
||||||
el: bodyDom,
|
el: bodyDom,
|
||||||
name: 'scroll',
|
name: 'scroll',
|
||||||
listener: () => {
|
listener: () => {
|
||||||
const footerBodyDom = tableEl.$el.querySelector('.ant-table-footer .ant-table-content') as HTMLDivElement
|
const footerBodyDom = tableEl.$el.querySelector(
|
||||||
|
'.ant-table-footer .ant-table-content',
|
||||||
|
) as HTMLDivElement
|
||||||
if (!footerBodyDom || !bodyDom)
|
if (!footerBodyDom || !bodyDom)
|
||||||
return
|
return
|
||||||
footerBodyDom.scrollLeft = bodyDom.scrollLeft
|
footerBodyDom.scrollLeft = bodyDom.scrollLeft
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,15 @@ export function useTableForm(
|
||||||
|
|
||||||
const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
|
const getFormSlotKeys: ComputedRef<string[]> = computed(() => {
|
||||||
const keys = Object.keys(slots)
|
const keys = Object.keys(slots)
|
||||||
return keys.map(item => (item.startsWith('form-') ? item : null)).filter(item => !!item) as string[]
|
return keys
|
||||||
|
.map(item => (item.startsWith('form-') ? item : null))
|
||||||
|
.filter(item => !!item) as string[]
|
||||||
})
|
})
|
||||||
|
|
||||||
function replaceFormSlotKey(key: string) {
|
function replaceFormSlotKey(key: string) {
|
||||||
if (!key)
|
if (!key)
|
||||||
return ''
|
return ''
|
||||||
return key?.replace?.(/form\-/, '') ?? ''
|
return key?.replace?.(/form-/, '') ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSearchInfoChange(info: Recordable) {
|
function handleSearchInfoChange(info: Recordable) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,11 @@ import TableHeader from '../components/TableHeader.vue'
|
||||||
import { isString } from '@/utils/is'
|
import { isString } from '@/utils/is'
|
||||||
import { getSlot } from '@/utils/helper/tsxHelper'
|
import { getSlot } from '@/utils/helper/tsxHelper'
|
||||||
|
|
||||||
export function useTableHeader(propsRef: ComputedRef<BasicTableProps>, slots: Slots, handlers: InnerHandlers) {
|
export function useTableHeader(
|
||||||
|
propsRef: ComputedRef<BasicTableProps>,
|
||||||
|
slots: Slots,
|
||||||
|
handlers: InnerHandlers,
|
||||||
|
) {
|
||||||
const getHeaderProps = computed((): Recordable => {
|
const getHeaderProps = computed((): Recordable => {
|
||||||
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef)
|
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef)
|
||||||
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting
|
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ export function useTableScroll(
|
||||||
|
|
||||||
handleScrollBar(bodyEl, tableEl)
|
handleScrollBar(bodyEl, tableEl)
|
||||||
|
|
||||||
bodyEl.style.height = 'unset'
|
bodyEl!.style.height = 'unset'
|
||||||
|
|
||||||
if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0)
|
if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0)
|
||||||
return
|
return
|
||||||
|
|
@ -207,7 +207,7 @@ export function useTableScroll(
|
||||||
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height
|
height = (height > maxHeight! ? (maxHeight as number) : height) ?? height
|
||||||
setHeight(height)
|
setHeight(height)
|
||||||
|
|
||||||
bodyEl.style.height = `${height}px`
|
bodyEl!.style.height = `${height}px`
|
||||||
}
|
}
|
||||||
useWindowSizeFn(calcTableHeight, { wait: 280 })
|
useWindowSizeFn(calcTableHeight, { wait: 280 })
|
||||||
onMountedOrActivated(() => {
|
onMountedOrActivated(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
|
import type { PropType } from 'vue'
|
||||||
import type { PaginationProps } from './types/pagination'
|
import type { PaginationProps } from './types/pagination'
|
||||||
import type { BasicColumn, FetchSetting, SizeType, SorterResult, TableCustomRecord, TableRowSelection, TableSetting } from './types/table'
|
import type {
|
||||||
|
BasicColumn,
|
||||||
|
FetchSetting,
|
||||||
|
SizeType,
|
||||||
|
SorterResult,
|
||||||
|
TableCustomRecord,
|
||||||
|
TableRowSelection,
|
||||||
|
TableSetting,
|
||||||
|
} from './types/table'
|
||||||
import { DEFAULT_FILTER_FN, DEFAULT_SIZE, DEFAULT_SORT_FN, FETCH_SETTING } from './const'
|
import { DEFAULT_FILTER_FN, DEFAULT_SIZE, DEFAULT_SORT_FN, FETCH_SETTING } from './const'
|
||||||
import type { FormProps } from '@/components/Form'
|
import type { FormProps } from '@/components/Form'
|
||||||
|
|
||||||
|
|
@ -126,7 +135,14 @@ export const basicProps = {
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
beforeEditSubmit: {
|
beforeEditSubmit: {
|
||||||
type: Function as PropType<(data: { record: Recordable; index: number; key: string | number; value: any }) => Promise<any>>,
|
type: Function as PropType<
|
||||||
|
(data: {
|
||||||
|
record: Recordable
|
||||||
|
index: number
|
||||||
|
key: string | number
|
||||||
|
value: any
|
||||||
|
}) => Promise<any>
|
||||||
|
>,
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
type: String as PropType<SizeType>,
|
type: String as PropType<SizeType>,
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,13 @@ export interface ColumnProps<T> {
|
||||||
* Customized filter overlay
|
* Customized filter overlay
|
||||||
* @type any (slot)
|
* @type any (slot)
|
||||||
*/
|
*/
|
||||||
filterDropdown?: VNodeChild | JSX.Element | ((props: FilterDropdownProps) => VNodeChild | JSX.Element)
|
filterDropdown?:
|
||||||
|
| VNodeChild
|
||||||
|
| JSX.Element
|
||||||
|
| ((props: FilterDropdownProps) => VNodeChild | JSX.Element)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether filterDropdown is open
|
* Whether filterDropdown is visible
|
||||||
* @type boolean
|
* @type boolean
|
||||||
*/
|
*/
|
||||||
filterDropdownOpen?: boolean
|
filterDropdownOpen?: boolean
|
||||||
|
|
@ -135,7 +138,7 @@ export interface ColumnProps<T> {
|
||||||
* Sort function for local sort, see Array.sort's compareFunction. If you need sort buttons only, set to true
|
* Sort function for local sort, see Array.sort's compareFunction. If you need sort buttons only, set to true
|
||||||
* @type boolean | Function
|
* @type boolean | Function
|
||||||
*/
|
*/
|
||||||
sorter?: boolean | Fn
|
sorter?: boolean | Function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order of sorted values: 'ascend' 'descend' false
|
* Order of sorted values: 'ascend' 'descend' false
|
||||||
|
|
@ -181,10 +184,10 @@ export interface ColumnProps<T> {
|
||||||
onFilter?: (value: any, record: T) => boolean
|
onFilter?: (value: any, record: T) => boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback executed when filterDropdownOpen is changed, Use as a filterDropdownOpen event when using template or jsx
|
* Callback executed when filterDropdownVisible is changed, Use as a filterDropdownVisible event when using template or jsx
|
||||||
* @type Function
|
* @type Function
|
||||||
*/
|
*/
|
||||||
onFilterDropdownOpenChange?: (open: boolean) => void
|
onFilterDropdownVisibleChange?: (visible: boolean) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When using columns, you can setting this property to configure the properties that support the slot,
|
* When using columns, you can setting this property to configure the properties that support the slot,
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,13 @@ interface PaginationRenderProps {
|
||||||
originalElement: any
|
originalElement: any
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaginationPositon = 'topLeft' | 'topCenter' | 'topRight' | 'bottomLeft' | 'bottomCenter' | 'bottomRight'
|
type PaginationPositon =
|
||||||
|
| 'topLeft'
|
||||||
|
| 'topCenter'
|
||||||
|
| 'topRight'
|
||||||
|
| 'bottomLeft'
|
||||||
|
| 'bottomCenter'
|
||||||
|
| 'bottomRight'
|
||||||
|
|
||||||
export declare class PaginationConfig extends Pagination {
|
export declare class PaginationConfig extends Pagination {
|
||||||
position?: PaginationPositon[]
|
position?: PaginationPositon[]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Ref, VNodeChild } from 'vue'
|
import type { VNodeChild } from 'vue'
|
||||||
import type { TableRowSelection as ITableRowSelection, Key } from 'ant-design-vue/lib/table/interface'
|
import type { TableRowSelection as ITableRowSelection, Key } from 'ant-design-vue/lib/table/interface'
|
||||||
import type { ColumnProps } from 'ant-design-vue/lib/table'
|
import type { ColumnProps } from 'ant-design-vue/lib/table'
|
||||||
import type { PaginationProps } from './pagination'
|
import type { PaginationProps } from './pagination'
|
||||||
|
|
@ -55,6 +55,11 @@ export interface ColumnFilterItem {
|
||||||
children?: any
|
children?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TableCustomRecord<T = Recordable> {
|
||||||
|
record?: T
|
||||||
|
index?: number
|
||||||
|
}
|
||||||
|
|
||||||
export interface SorterResult {
|
export interface SorterResult {
|
||||||
column: ColumnProps
|
column: ColumnProps
|
||||||
order: SortOrder
|
order: SortOrder
|
||||||
|
|
@ -89,7 +94,7 @@ export interface TableActionType {
|
||||||
getSelectRowKeys: () => Key[]
|
getSelectRowKeys: () => Key[]
|
||||||
deleteSelectRowByKey: (key: string) => void
|
deleteSelectRowByKey: (key: string) => void
|
||||||
setPagination: (info: Partial<PaginationProps>) => void
|
setPagination: (info: Partial<PaginationProps>) => void
|
||||||
setTableData: <T extends Ref<Recordable<any>[]>>(values: T[]) => void
|
setTableData: <T = Recordable>(values: T[]) => void
|
||||||
updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void
|
updateTableDataRecord: (rowKey: string | number, record: Recordable) => Recordable | void
|
||||||
deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void
|
deleteTableDataRecord: (rowKey: string | number | string[] | number[]) => void
|
||||||
insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => Recordable[] | void
|
insertTableDataRecord: (record: Recordable | Recordable[], index?: number) => Recordable[] | void
|
||||||
|
|
@ -108,7 +113,7 @@ export interface TableActionType {
|
||||||
getCacheColumns: () => BasicColumn[]
|
getCacheColumns: () => BasicColumn[]
|
||||||
emit?: EmitType
|
emit?: EmitType
|
||||||
updateTableData: (index: number, key: string, value: any) => Recordable
|
updateTableData: (index: number, key: string, value: any) => Recordable
|
||||||
setShowPagination: (show: boolean) => void
|
setShowPagination: (show: boolean) => Promise<void>
|
||||||
getShowPagination: () => boolean
|
getShowPagination: () => boolean
|
||||||
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void
|
setCacheColumnsByField?: (dataIndex: string | undefined, value: BasicColumn) => void
|
||||||
setCacheColumns?: (columns: BasicColumn[]) => void
|
setCacheColumns?: (columns: BasicColumn[]) => void
|
||||||
|
|
@ -257,7 +262,7 @@ export interface BasicTableProps<T = any> {
|
||||||
* Customize row expand Icon.
|
* Customize row expand Icon.
|
||||||
* @type Function | VNodeChild
|
* @type Function | VNodeChild
|
||||||
*/
|
*/
|
||||||
expandIcon?: Fn | VNodeChild | JSX.Element
|
expandIcon?: Function | VNodeChild | JSX.Element
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to expand row by clicking anywhere in the whole row
|
* Whether to expand row by clicking anywhere in the whole row
|
||||||
|
|
@ -275,7 +280,7 @@ export interface BasicTableProps<T = any> {
|
||||||
* Table footer renderer
|
* Table footer renderer
|
||||||
* @type Function | VNodeChild
|
* @type Function | VNodeChild
|
||||||
*/
|
*/
|
||||||
footer?: Fn | VNodeChild | JSX.Element
|
footer?: Function | VNodeChild | JSX.Element
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indent size in pixels of tree data
|
* Indent size in pixels of tree data
|
||||||
|
|
@ -366,14 +371,19 @@ export interface BasicTableProps<T = any> {
|
||||||
*
|
*
|
||||||
* @version 1.5.4
|
* @version 1.5.4
|
||||||
*/
|
*/
|
||||||
transformCellText?: Fn
|
transformCellText?: Function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback executed before editable cell submit value, not for row-editor
|
* Callback executed before editable cell submit value, not for row-editor
|
||||||
*
|
*
|
||||||
* The cell will not submit data while callback return false
|
* The cell will not submit data while callback return false
|
||||||
*/
|
*/
|
||||||
beforeEditSubmit?: (data: { record: Recordable; index: number; key: string | number; value: any }) => Promise<any>
|
beforeEditSubmit?: (data: {
|
||||||
|
record: Recordable
|
||||||
|
index: number
|
||||||
|
key: string | number
|
||||||
|
value: any
|
||||||
|
}) => Promise<any>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback executed when pagination, filters or sorter is changed
|
* Callback executed when pagination, filters or sorter is changed
|
||||||
|
|
@ -401,14 +411,19 @@ export interface BasicTableProps<T = any> {
|
||||||
onColumnsChange?: (data: ColumnChangeParam[]) => void
|
onColumnsChange?: (data: ColumnChangeParam[]) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CellFormat = string | ((text: string, record: Recordable, index: number) => string | number) | Map<string | number, any>
|
export type CellFormat =
|
||||||
|
| string
|
||||||
|
| ((text: string, record: Recordable, index: number) => string | number)
|
||||||
|
| Map<string | number, any>
|
||||||
|
|
||||||
export interface BasicColumn extends ColumnProps<Recordable> {
|
export interface BasicColumn extends ColumnProps<Recordable> {
|
||||||
children?: BasicColumn[]
|
children?: BasicColumn[]
|
||||||
filters?: {
|
filters?: {
|
||||||
text: string
|
text: string
|
||||||
value: string
|
value: string
|
||||||
children?: unknown[] | (((props: Record<string, unknown>) => unknown[]) & (() => unknown[]) & (() => unknown[]))
|
children?:
|
||||||
|
| unknown[]
|
||||||
|
| (((props: Record<string, unknown>) => unknown[]) & (() => unknown[]) & (() => unknown[]))
|
||||||
}[]
|
}[]
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -419,7 +434,6 @@ export interface BasicColumn extends ColumnProps<Recordable> {
|
||||||
|
|
||||||
// 自定义header渲染
|
// 自定义header渲染
|
||||||
customHeaderRender?: (column: BasicColumn) => string | VNodeChild | JSX.Element
|
customHeaderRender?: (column: BasicColumn) => string | VNodeChild | JSX.Element
|
||||||
|
|
||||||
// Whether to hide the column by default, it can be displayed in the column configuration
|
// Whether to hide the column by default, it can be displayed in the column configuration
|
||||||
defaultHidden?: boolean
|
defaultHidden?: boolean
|
||||||
|
|
||||||
|
|
@ -434,7 +448,12 @@ export interface BasicColumn extends ColumnProps<Recordable> {
|
||||||
editable?: boolean
|
editable?: boolean
|
||||||
editComponent?: ComponentType
|
editComponent?: ComponentType
|
||||||
editComponentProps?:
|
editComponentProps?:
|
||||||
| ((opt: { text: string | number | boolean | Recordable; record: Recordable; column: BasicColumn; index: number }) => Recordable)
|
| ((opt: {
|
||||||
|
text: string | number | boolean | Recordable
|
||||||
|
record: Recordable
|
||||||
|
column: BasicColumn
|
||||||
|
index: number
|
||||||
|
}) => Recordable)
|
||||||
| Recordable
|
| Recordable
|
||||||
editRule?: boolean | ((text: string, record: Recordable) => Promise<string>)
|
editRule?: boolean | ((text: string, record: Recordable) => Promise<string>)
|
||||||
editValueMap?: (value: any) => string
|
editValueMap?: (value: any) => string
|
||||||
|
|
@ -457,7 +476,7 @@ export interface BasicColumn extends ColumnProps<Recordable> {
|
||||||
export interface ColumnChangeParam {
|
export interface ColumnChangeParam {
|
||||||
dataIndex: string
|
dataIndex: string
|
||||||
fixed: boolean | 'left' | 'right' | undefined
|
fixed: boolean | 'left' | 'right' | undefined
|
||||||
open: boolean
|
visible: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InnerHandlers {
|
export interface InnerHandlers {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'
|
import { getCurrentInstance, reactive, shallowRef, watchEffect } from 'vue'
|
||||||
import type { Ref } from 'vue'
|
|
||||||
|
|
||||||
interface Params {
|
interface UseAttrsOptions {
|
||||||
excludeListeners?: boolean
|
excludeListeners?: boolean
|
||||||
excludeKeys?: string[]
|
excludeKeys?: string[]
|
||||||
excludeDefaultKeys?: boolean
|
excludeDefaultKeys?: boolean
|
||||||
|
|
@ -10,16 +9,16 @@ interface Params {
|
||||||
const DEFAULT_EXCLUDE_KEYS = ['class', 'style']
|
const DEFAULT_EXCLUDE_KEYS = ['class', 'style']
|
||||||
const LISTENER_PREFIX = /^on[A-Z]/
|
const LISTENER_PREFIX = /^on[A-Z]/
|
||||||
|
|
||||||
export function entries<T>(obj: Recordable<T>): [string, T][] {
|
function entries<T>(obj: Recordable<T>): [string, T][] {
|
||||||
return Object.keys(obj).map((key: string) => [key, obj[key]])
|
return Object.keys(obj).map((key: string) => [key, obj[key]])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAttrs(params: Params = {}): Ref<Recordable> | object {
|
function useAttrs(options: UseAttrsOptions = {}): Recordable<any> {
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
if (!instance)
|
if (!instance)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
const { excludeListeners = false, excludeKeys = [], excludeDefaultKeys = true } = params
|
const { excludeListeners = false, excludeKeys = [], excludeDefaultKeys = true } = options
|
||||||
const attrs = shallowRef({})
|
const attrs = shallowRef({})
|
||||||
const allExcludeKeys = excludeKeys.concat(excludeDefaultKeys ? DEFAULT_EXCLUDE_KEYS : [])
|
const allExcludeKeys = excludeKeys.concat(excludeDefaultKeys ? DEFAULT_EXCLUDE_KEYS : [])
|
||||||
|
|
||||||
|
|
@ -32,10 +31,12 @@ export function useAttrs(params: Params = {}): Ref<Recordable> | object {
|
||||||
acm[key] = val
|
acm[key] = val
|
||||||
|
|
||||||
return acm
|
return acm
|
||||||
}, {} as Recordable)
|
}, {} as Recordable<any>)
|
||||||
|
|
||||||
attrs.value = res
|
attrs.value = res
|
||||||
})
|
})
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { useAttrs, type UseAttrsOptions }
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,24 @@
|
||||||
import type { Ref } from 'vue'
|
import type { ComponentPublicInstance, Ref } from 'vue'
|
||||||
import { onBeforeUpdate, ref } from 'vue'
|
import { onBeforeUpdate, shallowRef } from 'vue'
|
||||||
|
|
||||||
export function useRefs(): [Ref<HTMLElement[]>, (index: number) => (el: HTMLElement) => void] {
|
function useRefs<T = HTMLElement>(): {
|
||||||
const refs = ref([]) as Ref<HTMLElement[]>
|
refs: Ref<T[]>
|
||||||
|
setRefs: (index: number) => (el: Element | ComponentPublicInstance | null) => void
|
||||||
|
} {
|
||||||
|
const refs = shallowRef([]) as Ref<T[]>
|
||||||
|
|
||||||
onBeforeUpdate(() => {
|
onBeforeUpdate(() => {
|
||||||
refs.value = []
|
refs.value = []
|
||||||
})
|
})
|
||||||
|
|
||||||
const setRefs = (index: number) => (el: HTMLElement) => {
|
const setRefs = (index: number) => (el: Element | ComponentPublicInstance | null) => {
|
||||||
refs.value[index] = el
|
refs.value[index] = el as T
|
||||||
}
|
}
|
||||||
|
|
||||||
return [refs, setRefs]
|
return {
|
||||||
|
refs,
|
||||||
|
setRefs,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { useRefs }
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import { ref, unref } from 'vue'
|
import { shallowRef, unref } from 'vue'
|
||||||
import { isFunction, isUnDef } from '@/utils/is'
|
|
||||||
|
|
||||||
export interface ScrollToParams {
|
interface UseScrollToOptions {
|
||||||
el: any
|
el: any
|
||||||
to: number
|
to: number
|
||||||
duration?: number
|
duration?: number
|
||||||
|
|
@ -16,6 +15,7 @@ function easeInOutQuad(t: number, b: number, c: number, d: number) {
|
||||||
t--
|
t--
|
||||||
return (-c / 2) * (t * (t - 2) - 1) + b
|
return (-c / 2) * (t * (t - 2) - 1) + b
|
||||||
}
|
}
|
||||||
|
|
||||||
function move(el: HTMLElement, amount: number) {
|
function move(el: HTMLElement, amount: number) {
|
||||||
el.scrollTop = amount
|
el.scrollTop = amount
|
||||||
}
|
}
|
||||||
|
|
@ -23,13 +23,13 @@ function move(el: HTMLElement, amount: number) {
|
||||||
function position(el: HTMLElement) {
|
function position(el: HTMLElement) {
|
||||||
return el.scrollTop
|
return el.scrollTop
|
||||||
}
|
}
|
||||||
export function useScrollTo({ el, to, duration = 500, callback }: ScrollToParams) {
|
|
||||||
const isActiveRef = ref(false)
|
function useScrollTo({ el, to, duration = 500, callback }: UseScrollToOptions) {
|
||||||
|
const isActiveRef = shallowRef(false)
|
||||||
const start = position(el)
|
const start = position(el)
|
||||||
const change = to - start
|
const change = to - start
|
||||||
const increment = 20
|
const increment = 20
|
||||||
let currentTime = 0
|
let currentTime = 0
|
||||||
duration = isUnDef(duration) ? 500 : duration
|
|
||||||
|
|
||||||
const animateScroll = function () {
|
const animateScroll = function () {
|
||||||
if (!unref(isActiveRef))
|
if (!unref(isActiveRef))
|
||||||
|
|
@ -42,7 +42,7 @@ export function useScrollTo({ el, to, duration = 500, callback }: ScrollToParams
|
||||||
requestAnimationFrame(animateScroll)
|
requestAnimationFrame(animateScroll)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (callback && isFunction(callback))
|
if (callback && typeof callback === 'function')
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,3 +57,5 @@ export function useScrollTo({ el, to, duration = 500, callback }: ScrollToParams
|
||||||
|
|
||||||
return { start: run, stop }
|
return { start: run, stop }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { useScrollTo, type UseScrollToOptions }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core'
|
import { tryOnMounted, tryOnUnmounted, useDebounceFn } from '@vueuse/core'
|
||||||
|
import type { AnyFunction } from '@/utils/types'
|
||||||
|
|
||||||
interface UseWindowSizeOptions {
|
interface UseWindowSizeOptions {
|
||||||
wait?: number
|
wait?: number
|
||||||
|
|
@ -7,7 +8,7 @@ interface UseWindowSizeOptions {
|
||||||
listenerOptions?: AddEventListenerOptions | boolean
|
listenerOptions?: AddEventListenerOptions | boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
function useWindowSizeFn<T>(fn: Fn<T>, options: UseWindowSizeOptions = {}) {
|
function useWindowSizeFn(fn: AnyFunction, options: UseWindowSizeOptions = {}) {
|
||||||
const { wait = 150, immediate } = options
|
const { wait = 150, immediate } = options
|
||||||
let handler = () => {
|
let handler = () => {
|
||||||
fn()
|
fn()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,20 @@ type BiArgEmitter<T, Keys extends keyof T> = <K extends Keys>(evt: K, arg: T[K])
|
||||||
|
|
||||||
export type EventEmitter<T extends Record<string, unknown>> = MonoArgEmitter<T, OptionalKeys<T>> & BiArgEmitter<T, RequiredKeys<T>>
|
export type EventEmitter<T extends Record<string, unknown>> = MonoArgEmitter<T, OptionalKeys<T>> & BiArgEmitter<T, RequiredKeys<T>>
|
||||||
|
|
||||||
export type AnyFunction<T> = (...args: any[]) => T
|
/**
|
||||||
|
* 任意类型的异步函数
|
||||||
|
*/
|
||||||
|
export type AnyPromiseFunction = (...arg: any[]) => PromiseLike<any>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任意类型的普通函数
|
||||||
|
*/
|
||||||
|
export type AnyNormalFunction = (...arg: any[]) => any
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任意类型的函数
|
||||||
|
*/
|
||||||
|
export type AnyFunction = AnyNormalFunction | AnyPromiseFunction
|
||||||
|
|
||||||
export type PartialReturnType<T extends (...args: unknown[]) => unknown> = Partial<ReturnType<T>>
|
export type PartialReturnType<T extends (...args: unknown[]) => unknown> = Partial<ReturnType<T>>
|
||||||
|
|
||||||
|
|
@ -22,6 +35,11 @@ export type SFCWithInstall<T> = T & Plugin
|
||||||
|
|
||||||
export type Nullable<T> = T | null
|
export type Nullable<T> = T | null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串类型对象
|
||||||
|
*/
|
||||||
|
export type Recordable<T = any> = Record<string, T>
|
||||||
|
|
||||||
export type RefElement = Nullable<HTMLElement>
|
export type RefElement = Nullable<HTMLElement>
|
||||||
|
|
||||||
export type CustomizedHTMLElement<T> = HTMLElement & T
|
export type CustomizedHTMLElement<T> = HTMLElement & T
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,6 @@ export const basicInfoSchemas: FormSchema[] = [
|
||||||
component: 'ApiTreeSelect',
|
component: 'ApiTreeSelect',
|
||||||
componentProps: {
|
componentProps: {
|
||||||
api: () => listSimpleMenus(),
|
api: () => listSimpleMenus(),
|
||||||
fieldNames: {
|
|
||||||
label: 'name',
|
|
||||||
key: 'id',
|
|
||||||
value: 'id',
|
|
||||||
},
|
|
||||||
handleTree: 'id',
|
handleTree: 'id',
|
||||||
},
|
},
|
||||||
colProps: { span: 12 },
|
colProps: { span: 12 },
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue