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