|
@@ -1,22 +1,22 @@
|
|
|
<script lang="tsx">
|
|
|
- import type { PropType, Ref } from 'vue';
|
|
|
- import type { FormActionType, FormProps } from '../types/form';
|
|
|
- import type { FormSchema } from '../types/form';
|
|
|
- import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
|
|
|
- import type { TableActionType } from '/@/components/Table';
|
|
|
+ import type { PropType, Ref } from 'vue'
|
|
|
+ import type { FormActionType, FormProps } from '../types/form'
|
|
|
+ import type { FormSchema } from '../types/form'
|
|
|
+ import type { ValidationRule } from 'ant-design-vue/lib/form/Form'
|
|
|
+ import type { TableActionType } from '/@/components/Table'
|
|
|
|
|
|
- import { defineComponent, computed, unref, toRefs } from 'vue';
|
|
|
- import { Form, Col } from 'ant-design-vue';
|
|
|
- import { componentMap } from '../componentMap';
|
|
|
- import { BasicHelp } from '/@/components/Basic';
|
|
|
+ import { defineComponent, computed, unref, toRefs } from 'vue'
|
|
|
+ import { Form, Col } from 'ant-design-vue'
|
|
|
+ import { componentMap } from '../componentMap'
|
|
|
+ import { BasicHelp } from '/@/components/Basic'
|
|
|
|
|
|
- import { isBoolean, isFunction } from '/@/utils/is';
|
|
|
- import { getSlot } from '/@/utils/helper/tsxHelper';
|
|
|
- import { createPlaceholderMessage, setComponentRuleType } from '../helper';
|
|
|
- import { upperFirst, cloneDeep } from 'lodash-es';
|
|
|
+ import { isBoolean, isFunction, isNull } from '/@/utils/is'
|
|
|
+ import { getSlot } from '/@/utils/helper/tsxHelper'
|
|
|
+ import { createPlaceholderMessage, setComponentRuleType } from '../helper'
|
|
|
+ import { upperFirst, cloneDeep } from 'lodash-es'
|
|
|
|
|
|
- import { useItemLabelWidth } from '../hooks/useLabelWidth';
|
|
|
- import { useI18n } from '/@/hooks/web/useI18n';
|
|
|
+ import { useItemLabelWidth } from '../hooks/useLabelWidth'
|
|
|
+ import { useI18n } from '/@/hooks/web/useI18n'
|
|
|
|
|
|
export default defineComponent({
|
|
|
name: 'BasicFormItem',
|
|
@@ -24,270 +24,280 @@
|
|
|
props: {
|
|
|
schema: {
|
|
|
type: Object as PropType<FormSchema>,
|
|
|
- default: () => {},
|
|
|
+ default: () => ({})
|
|
|
},
|
|
|
formProps: {
|
|
|
type: Object as PropType<FormProps>,
|
|
|
- default: () => {},
|
|
|
+ default: () => ({})
|
|
|
},
|
|
|
allDefaultValues: {
|
|
|
type: Object as PropType<Recordable>,
|
|
|
- default: () => {},
|
|
|
+ default: () => ({})
|
|
|
},
|
|
|
formModel: {
|
|
|
type: Object as PropType<Recordable>,
|
|
|
- default: () => {},
|
|
|
+ default: () => ({})
|
|
|
},
|
|
|
setFormModel: {
|
|
|
type: Function as PropType<(key: string, value: any) => void>,
|
|
|
- default: null,
|
|
|
+ default: null
|
|
|
},
|
|
|
tableAction: {
|
|
|
- type: Object as PropType<TableActionType>,
|
|
|
+ type: Object as PropType<TableActionType>
|
|
|
},
|
|
|
formActionType: {
|
|
|
- type: Object as PropType<FormActionType>,
|
|
|
- },
|
|
|
+ type: Object as PropType<FormActionType>
|
|
|
+ }
|
|
|
},
|
|
|
setup(props, { slots }) {
|
|
|
- const { t } = useI18n();
|
|
|
+ const { t } = useI18n()
|
|
|
|
|
|
const { schema, formProps } = toRefs(props) as {
|
|
|
- schema: Ref<FormSchema>;
|
|
|
- formProps: Ref<FormProps>;
|
|
|
- };
|
|
|
+ schema: Ref<FormSchema>
|
|
|
+ formProps: Ref<FormProps>
|
|
|
+ }
|
|
|
|
|
|
- const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
|
|
|
+ const itemLabelWidthProp = useItemLabelWidth(schema, formProps)
|
|
|
|
|
|
const getValues = computed(() => {
|
|
|
- const { allDefaultValues, formModel, schema } = props;
|
|
|
- const { mergeDynamicData } = props.formProps;
|
|
|
+ const { allDefaultValues, formModel, schema } = props
|
|
|
+ const { mergeDynamicData } = props.formProps
|
|
|
return {
|
|
|
field: schema.field,
|
|
|
model: formModel,
|
|
|
values: {
|
|
|
...mergeDynamicData,
|
|
|
...allDefaultValues,
|
|
|
- ...formModel,
|
|
|
+ ...formModel
|
|
|
} as Recordable,
|
|
|
- schema: schema,
|
|
|
- };
|
|
|
- });
|
|
|
+ schema: schema
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
const getComponentsProps = computed(() => {
|
|
|
- const { schema, tableAction, formModel, formActionType } = props;
|
|
|
- const { componentProps = {} } = schema;
|
|
|
+ const { schema, tableAction, formModel, formActionType } = props
|
|
|
+ const { componentProps = {} } = schema
|
|
|
if (!isFunction(componentProps)) {
|
|
|
- return componentProps;
|
|
|
+ return componentProps
|
|
|
}
|
|
|
- return componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
|
|
|
- });
|
|
|
+ return componentProps({ schema, tableAction, formModel, formActionType }) ?? {}
|
|
|
+ })
|
|
|
|
|
|
const getDisable = computed(() => {
|
|
|
- const { disabled: globDisabled } = props.formProps;
|
|
|
- const { dynamicDisabled } = props.schema;
|
|
|
- const { disabled: itemDisabled = false } = unref(getComponentsProps);
|
|
|
- let disabled = !!globDisabled || itemDisabled;
|
|
|
+ const { disabled: globDisabled } = props.formProps
|
|
|
+ const { dynamicDisabled } = props.schema
|
|
|
+ const { disabled: itemDisabled = false } = unref(getComponentsProps)
|
|
|
+ let disabled = !!globDisabled || itemDisabled
|
|
|
if (isBoolean(dynamicDisabled)) {
|
|
|
- disabled = dynamicDisabled;
|
|
|
+ disabled = dynamicDisabled
|
|
|
}
|
|
|
|
|
|
if (isFunction(dynamicDisabled)) {
|
|
|
- disabled = dynamicDisabled(unref(getValues));
|
|
|
+ disabled = dynamicDisabled(unref(getValues))
|
|
|
}
|
|
|
- return disabled;
|
|
|
- });
|
|
|
+ return disabled
|
|
|
+ })
|
|
|
|
|
|
function getShow(): { isShow: boolean; isIfShow: boolean } {
|
|
|
- const { show, ifShow } = props.schema;
|
|
|
- const { showAdvancedButton } = props.formProps;
|
|
|
+ const { show, ifShow } = props.schema
|
|
|
+ const { showAdvancedButton } = props.formProps
|
|
|
const itemIsAdvanced = showAdvancedButton
|
|
|
? isBoolean(props.schema.isAdvanced)
|
|
|
? props.schema.isAdvanced
|
|
|
: true
|
|
|
- : true;
|
|
|
+ : true
|
|
|
|
|
|
- let isShow = true;
|
|
|
- let isIfShow = true;
|
|
|
+ let isShow = true
|
|
|
+ let isIfShow = true
|
|
|
|
|
|
if (isBoolean(show)) {
|
|
|
- isShow = show;
|
|
|
+ isShow = show
|
|
|
}
|
|
|
if (isBoolean(ifShow)) {
|
|
|
- isIfShow = ifShow;
|
|
|
+ isIfShow = ifShow
|
|
|
}
|
|
|
if (isFunction(show)) {
|
|
|
- isShow = show(unref(getValues));
|
|
|
+ isShow = show(unref(getValues))
|
|
|
}
|
|
|
if (isFunction(ifShow)) {
|
|
|
- isIfShow = ifShow(unref(getValues));
|
|
|
+ isIfShow = ifShow(unref(getValues))
|
|
|
}
|
|
|
- isShow = isShow && itemIsAdvanced;
|
|
|
- return { isShow, isIfShow };
|
|
|
+ isShow = isShow && itemIsAdvanced
|
|
|
+ return { isShow, isIfShow }
|
|
|
}
|
|
|
|
|
|
function handleRules(): ValidationRule[] {
|
|
|
- const {
|
|
|
- rules: defRules = [],
|
|
|
- component,
|
|
|
- rulesMessageJoinLabel,
|
|
|
- label,
|
|
|
- dynamicRules,
|
|
|
- required,
|
|
|
- } = props.schema;
|
|
|
+ const { rules: defRules = [], component, rulesMessageJoinLabel, label, dynamicRules, required } = props.schema
|
|
|
|
|
|
if (isFunction(dynamicRules)) {
|
|
|
- return dynamicRules(unref(getValues)) as ValidationRule[];
|
|
|
+ return dynamicRules(unref(getValues)) as ValidationRule[]
|
|
|
+ }
|
|
|
+
|
|
|
+ let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[]
|
|
|
+ const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps
|
|
|
+
|
|
|
+ const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
|
|
|
+ ? rulesMessageJoinLabel
|
|
|
+ : globalRulesMessageJoinLabel
|
|
|
+ const defaultMsg = createPlaceholderMessage(component) + `${joinLabel ? label : ''}`
|
|
|
+
|
|
|
+ function validator(rule: any, value: any) {
|
|
|
+ const msg = rule.message || defaultMsg
|
|
|
+ if (value === undefined || isNull(value)) {
|
|
|
+ // 空值
|
|
|
+ return Promise.reject(msg)
|
|
|
+ } else if (Array.isArray(value) && value.length === 0) {
|
|
|
+ // 数组类型
|
|
|
+ return Promise.reject(msg)
|
|
|
+ } else if (typeof value === 'string' && value.trim() === '') {
|
|
|
+ // 空字符串
|
|
|
+ return Promise.reject(msg)
|
|
|
+ } else if (
|
|
|
+ typeof value === 'object' &&
|
|
|
+ Reflect.has(value, 'checked') &&
|
|
|
+ Reflect.has(value, 'halfChecked') &&
|
|
|
+ Array.isArray(value.checked) &&
|
|
|
+ Array.isArray(value.halfChecked) &&
|
|
|
+ value.checked.length === 0 &&
|
|
|
+ value.halfChecked.length === 0
|
|
|
+ ) {
|
|
|
+ // 非关联选择的tree组件
|
|
|
+ return Promise.reject(msg)
|
|
|
+ }
|
|
|
+ return Promise.resolve()
|
|
|
}
|
|
|
|
|
|
- let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
|
|
|
+ const getRequired = isFunction(required) ? required(unref(getValues)) : required
|
|
|
|
|
|
- if ((!rules || rules.length === 0) && required) {
|
|
|
- rules = [{ required, type: 'string' }];
|
|
|
+ if ((!rules || rules.length === 0) && getRequired) {
|
|
|
+ rules = [{ required: getRequired, validator }]
|
|
|
}
|
|
|
|
|
|
const requiredRuleIndex: number = rules.findIndex(
|
|
|
- (rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator')
|
|
|
- );
|
|
|
- const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps;
|
|
|
+ rule => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator')
|
|
|
+ )
|
|
|
+
|
|
|
if (requiredRuleIndex !== -1) {
|
|
|
- const rule = rules[requiredRuleIndex];
|
|
|
- const { isShow } = getShow();
|
|
|
+ const rule = rules[requiredRuleIndex]
|
|
|
+ const { isShow } = getShow()
|
|
|
if (!isShow) {
|
|
|
- rule.required = false;
|
|
|
+ rule.required = false
|
|
|
}
|
|
|
if (component) {
|
|
|
if (!Reflect.has(rule, 'type')) {
|
|
|
- rule.type = component === 'InputNumber' ? 'number' : 'string';
|
|
|
+ rule.type = component === 'InputNumber' ? 'number' : 'string'
|
|
|
}
|
|
|
- const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel')
|
|
|
- ? rulesMessageJoinLabel
|
|
|
- : globalRulesMessageJoinLabel;
|
|
|
|
|
|
- rule.message =
|
|
|
- rule.message || createPlaceholderMessage(component) + `${joinLabel ? label : ''}`;
|
|
|
+ rule.message = rule.message || defaultMsg
|
|
|
|
|
|
if (component.includes('Input') || component.includes('Textarea')) {
|
|
|
- rule.whitespace = true;
|
|
|
+ rule.whitespace = true
|
|
|
}
|
|
|
- const valueFormat = unref(getComponentsProps)?.valueFormat;
|
|
|
- setComponentRuleType(rule, component, valueFormat);
|
|
|
+ const valueFormat = unref(getComponentsProps)?.valueFormat
|
|
|
+ setComponentRuleType(rule, component, valueFormat)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// Maximum input length rule check
|
|
|
- const characterInx = rules.findIndex((val) => val.max);
|
|
|
+ const characterInx = rules.findIndex(val => val.max)
|
|
|
if (characterInx !== -1 && !rules[characterInx].validator) {
|
|
|
rules[characterInx].message =
|
|
|
- rules[characterInx].message ||
|
|
|
- t('component.form.maxTip', [rules[characterInx].max] as Recordable);
|
|
|
+ rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max] as Recordable)
|
|
|
}
|
|
|
- return rules;
|
|
|
+ return rules
|
|
|
}
|
|
|
|
|
|
function renderComponent() {
|
|
|
- const {
|
|
|
- renderComponentContent,
|
|
|
- component,
|
|
|
- field,
|
|
|
- changeEvent = 'change',
|
|
|
- valueField,
|
|
|
- } = props.schema;
|
|
|
+ const { renderComponentContent, component, field, changeEvent = 'change', valueField } = props.schema
|
|
|
|
|
|
- const isCheck = component && ['Switch', 'Checkbox'].includes(component);
|
|
|
+ const isCheck = component && ['Switch', 'Checkbox'].includes(component)
|
|
|
|
|
|
- const eventKey = `on${upperFirst(changeEvent)}`;
|
|
|
+ const eventKey = `on${upperFirst(changeEvent)}`
|
|
|
|
|
|
const on = {
|
|
|
[eventKey]: (e: Nullable<Recordable>) => {
|
|
|
if (propsData[eventKey]) {
|
|
|
- propsData[eventKey](e);
|
|
|
+ propsData[eventKey](e)
|
|
|
}
|
|
|
- const target = e ? e.target : null;
|
|
|
- const value = target ? (isCheck ? target.checked : target.value) : e;
|
|
|
- props.setFormModel(field, value);
|
|
|
- },
|
|
|
- };
|
|
|
- const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
|
|
|
-
|
|
|
- const { autoSetPlaceHolder, size } = props.formProps;
|
|
|
+ const target = e ? e.target : null
|
|
|
+ const value = target ? (isCheck ? target.checked : target.value) : e
|
|
|
+ props.setFormModel(field, value)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>
|
|
|
+
|
|
|
+ const { autoSetPlaceHolder, size } = props.formProps
|
|
|
const propsData: Recordable = {
|
|
|
allowClear: true,
|
|
|
getPopupContainer: (trigger: Element) => trigger.parentNode,
|
|
|
size,
|
|
|
...unref(getComponentsProps),
|
|
|
- disabled: unref(getDisable),
|
|
|
- };
|
|
|
+ disabled: unref(getDisable)
|
|
|
+ }
|
|
|
|
|
|
- const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
|
|
|
- let placeholder;
|
|
|
+ const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder
|
|
|
// RangePicker place is an array
|
|
|
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
|
|
|
- placeholder =
|
|
|
- unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component);
|
|
|
+ propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component)
|
|
|
}
|
|
|
- propsData.placeholder = placeholder;
|
|
|
- propsData.codeField = field;
|
|
|
- propsData.formValues = unref(getValues);
|
|
|
+ propsData.codeField = field
|
|
|
+ propsData.formValues = unref(getValues)
|
|
|
|
|
|
const bindValue: Recordable = {
|
|
|
- [valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
|
|
|
- };
|
|
|
+ [valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field]
|
|
|
+ }
|
|
|
|
|
|
const compAttr: Recordable = {
|
|
|
...propsData,
|
|
|
...on,
|
|
|
- ...bindValue,
|
|
|
- };
|
|
|
+ ...bindValue
|
|
|
+ }
|
|
|
|
|
|
if (!renderComponentContent) {
|
|
|
- return <Comp {...compAttr} />;
|
|
|
+ return <Comp {...compAttr} />
|
|
|
}
|
|
|
const compSlot = isFunction(renderComponentContent)
|
|
|
? { ...renderComponentContent(unref(getValues)) }
|
|
|
: {
|
|
|
- default: () => renderComponentContent,
|
|
|
- };
|
|
|
+ default: () => renderComponentContent
|
|
|
+ }
|
|
|
|
|
|
- return <Comp {...compAttr}>{compSlot}</Comp>;
|
|
|
+ return <Comp {...compAttr}>{compSlot}</Comp>
|
|
|
}
|
|
|
|
|
|
function renderLabelHelpMessage() {
|
|
|
- const { label, helpMessage, helpComponentProps, subLabel } = props.schema;
|
|
|
+ const { label, helpMessage, helpComponentProps, subLabel } = props.schema
|
|
|
const renderLabel = subLabel ? (
|
|
|
<span>
|
|
|
{label} <span class="text-secondary">{subLabel}</span>
|
|
|
</span>
|
|
|
) : (
|
|
|
label
|
|
|
- );
|
|
|
- if (!helpMessage || (Array.isArray(helpMessage) && helpMessage.length === 0)) {
|
|
|
- return renderLabel;
|
|
|
+ )
|
|
|
+ const getHelpMessage = isFunction(helpMessage) ? helpMessage(unref(getValues)) : helpMessage
|
|
|
+ if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0)) {
|
|
|
+ return renderLabel
|
|
|
}
|
|
|
return (
|
|
|
<span>
|
|
|
{renderLabel}
|
|
|
- <BasicHelp placement="top" class="mx-1" text={helpMessage} {...helpComponentProps} />
|
|
|
+ <BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} />
|
|
|
</span>
|
|
|
- );
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
function renderItem() {
|
|
|
- const { itemProps, slot, render, field, suffix } = props.schema;
|
|
|
- const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
|
|
|
- const { colon } = props.formProps;
|
|
|
+ const { itemProps, slot, render, field, suffix } = props.schema
|
|
|
+ const { labelCol, wrapperCol } = unref(itemLabelWidthProp)
|
|
|
+ const { colon } = props.formProps
|
|
|
|
|
|
const getContent = () => {
|
|
|
- return slot
|
|
|
- ? getSlot(slots, slot, unref(getValues))
|
|
|
- : render
|
|
|
- ? render(unref(getValues))
|
|
|
- : renderComponent();
|
|
|
- };
|
|
|
+ return slot ? getSlot(slots, slot, unref(getValues)) : render ? render(unref(getValues)) : renderComponent()
|
|
|
+ }
|
|
|
|
|
|
- const showSuffix = !!suffix;
|
|
|
+ const showSuffix = !!suffix
|
|
|
|
|
|
- const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
|
|
|
+ const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix
|
|
|
|
|
|
return (
|
|
|
<Form.Item
|
|
@@ -305,25 +315,21 @@
|
|
|
{showSuffix && <span class="suffix">{getSuffix}</span>}
|
|
|
</>
|
|
|
</Form.Item>
|
|
|
- );
|
|
|
+ )
|
|
|
}
|
|
|
return () => {
|
|
|
- const { colProps = {}, colSlot, renderColContent, component } = props.schema;
|
|
|
- if (!componentMap.has(component)) return null;
|
|
|
+ const { colProps = {}, colSlot, renderColContent, component } = props.schema
|
|
|
+ if (!componentMap.has(component)) return null
|
|
|
|
|
|
- const { baseColProps = {} } = props.formProps;
|
|
|
+ const { baseColProps = {} } = props.formProps
|
|
|
|
|
|
- const realColProps = { ...baseColProps, ...colProps };
|
|
|
- const { isIfShow, isShow } = getShow();
|
|
|
+ const realColProps = { ...baseColProps, ...colProps }
|
|
|
+ const { isIfShow, isShow } = getShow()
|
|
|
|
|
|
- const values = unref(getValues);
|
|
|
+ const values = unref(getValues)
|
|
|
const getContent = () => {
|
|
|
- return colSlot
|
|
|
- ? getSlot(slots, colSlot, values)
|
|
|
- : renderColContent
|
|
|
- ? renderColContent(values)
|
|
|
- : renderItem();
|
|
|
- };
|
|
|
+ return colSlot ? getSlot(slots, colSlot, values) : renderColContent ? renderColContent(values) : renderItem()
|
|
|
+ }
|
|
|
|
|
|
return (
|
|
|
isIfShow && (
|
|
@@ -331,8 +337,8 @@
|
|
|
{getContent()}
|
|
|
</Col>
|
|
|
)
|
|
|
- );
|
|
|
- };
|
|
|
- },
|
|
|
- });
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
</script>
|