fix: 完善mobile级联组件的地区功能和只读样式 (#1226)
Reviewed-on: daoyoucloud/tachybase#1226 Reviewed-by: sealday <zhanglin@daoyoucloud.com> Co-authored-by: wjh <wwwjh0710@163.com> Co-committed-by: wjh <wwwjh0710@163.com>
This commit is contained in:
parent
4fddd1023a
commit
299c01da9f
@ -11,9 +11,7 @@ export const useChinaRegionDataSource = (options) => {
|
|||||||
params: {
|
params: {
|
||||||
sort: 'code',
|
sort: 'code',
|
||||||
paginate: false,
|
paginate: false,
|
||||||
filter: {
|
filter: { level: 1 },
|
||||||
level: 1,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -38,7 +36,7 @@ export const useChinaRegionLoadData = () => {
|
|||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const field = useField<ArrayField>();
|
const field = useField<ArrayField>();
|
||||||
const maxLevel = field.componentProps.maxLevel;
|
const maxLevel = field.componentProps.maxLevel;
|
||||||
return (selectedOptions) => {
|
return (selectedOptions, onSuccess?) => {
|
||||||
const targetOption = selectedOptions[selectedOptions.length - 1];
|
const targetOption = selectedOptions[selectedOptions.length - 1];
|
||||||
if (targetOption?.children?.length > 0) {
|
if (targetOption?.children?.length > 0) {
|
||||||
return;
|
return;
|
||||||
@ -54,14 +52,18 @@ export const useChinaRegionLoadData = () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
targetOption.loading = false;
|
if (onSuccess) {
|
||||||
targetOption.children =
|
onSuccess(data);
|
||||||
data?.data?.map((item) => {
|
} else {
|
||||||
if (maxLevel > item.level) {
|
targetOption.loading = false;
|
||||||
item.isLeaf = false;
|
targetOption.children =
|
||||||
}
|
data?.data?.map((item) => {
|
||||||
return item;
|
if (maxLevel > item.level) {
|
||||||
}) || [];
|
item.isLeaf = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}) || [];
|
||||||
|
}
|
||||||
field.dataSource = [...field.dataSource];
|
field.dataSource = [...field.dataSource];
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
useFieldServiceFilter,
|
useFieldServiceFilter,
|
||||||
useRequest,
|
useRequest,
|
||||||
} from '@tachybase/client';
|
} from '@tachybase/client';
|
||||||
import { observer, useFieldSchema, useForm } from '@tachybase/schema';
|
import { ArrayField, observer, useField, useFieldSchema, useForm } from '@tachybase/schema';
|
||||||
import { isArray } from '@tachybase/utils/client';
|
import { isArray } from '@tachybase/utils/client';
|
||||||
|
|
||||||
import { Button, CascaderView, Divider, Popup, SearchBar, Space } from 'antd-mobile';
|
import { Button, CascaderView, Divider, Popup, SearchBar, Space } from 'antd-mobile';
|
||||||
@ -18,7 +18,18 @@ import { MInput } from '../Input';
|
|||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
|
|
||||||
export const AntdCascader = observer((props) => {
|
export const AntdCascader = observer((props) => {
|
||||||
const { service, fieldNames, disabled, multiple, onChange, value, formCascaderValues, index } = props as any;
|
const {
|
||||||
|
service,
|
||||||
|
fieldNames,
|
||||||
|
disabled,
|
||||||
|
useLoadData,
|
||||||
|
useDataSource,
|
||||||
|
multiple,
|
||||||
|
onChange,
|
||||||
|
value,
|
||||||
|
formCascaderValues,
|
||||||
|
index,
|
||||||
|
} = props as any;
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const cm = useCollectionManager();
|
const cm = useCollectionManager();
|
||||||
const { styles } = useStyles();
|
const { styles } = useStyles();
|
||||||
@ -34,7 +45,8 @@ export const AntdCascader = observer((props) => {
|
|||||||
const [cascaderValue, setCascaderValue] = useState(value);
|
const [cascaderValue, setCascaderValue] = useState(value);
|
||||||
const [valueText, setValueText] = useState('');
|
const [valueText, setValueText] = useState('');
|
||||||
const [flatOption, setFlatOption] = useState([]);
|
const [flatOption, setFlatOption] = useState([]);
|
||||||
const { run } = useRequest(
|
const field = useField<ArrayField>();
|
||||||
|
const { loading: collectionLoading, run: collectionRun } = useRequest(
|
||||||
{
|
{
|
||||||
resource: collection?.name,
|
resource: collection?.name,
|
||||||
action: 'list',
|
action: 'list',
|
||||||
@ -47,7 +59,8 @@ export const AntdCascader = observer((props) => {
|
|||||||
manual: true,
|
manual: true,
|
||||||
onSuccess({ data }) {
|
onSuccess({ data }) {
|
||||||
if (data) {
|
if (data) {
|
||||||
setOptions(cascadeOption(data));
|
setOptions(data);
|
||||||
|
field.dataSource = data || [];
|
||||||
const valueOption = flatOptions(data);
|
const valueOption = flatOptions(data);
|
||||||
setFlatOption(valueOption);
|
setFlatOption(valueOption);
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -57,39 +70,40 @@ export const AntdCascader = observer((props) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const loadData = useLoadData?.(props);
|
||||||
const cascadeOption = (option) => {
|
const { loading: areaLoading, run: areaRun } = useDataSource?.({
|
||||||
option.forEach((item) => {
|
onSuccess(data) {
|
||||||
item['value'] = item[fieldNames.value];
|
field.dataSource = data?.data || [];
|
||||||
item['label'] = item[fieldNames.label];
|
setOptions(data?.data);
|
||||||
if (item.children) {
|
},
|
||||||
item.children = cascadeOption(item.children);
|
}) || { loading: true, run: null };
|
||||||
}
|
if (!valueText && value && isChinaRegion) {
|
||||||
});
|
setValueText(getChinaRegionText(value, fieldNames));
|
||||||
return option;
|
}
|
||||||
};
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isChinaRegion && collection?.name) {
|
if (!isChinaRegion && collection?.name) {
|
||||||
checkedPopup();
|
checkedPopup();
|
||||||
}
|
}
|
||||||
}, [filter]);
|
}, [filter]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (options.length) {
|
if (!isChinaRegion && flatOption.length) {
|
||||||
cascadeOption(options);
|
setValueText(getValueText(flatOption, value, '', fieldNames['label']));
|
||||||
}
|
}
|
||||||
}, [fieldSchema['x-component-props']?.['fieldNames']]);
|
}, [fieldSchema['x-component-props']?.['fieldNames']]);
|
||||||
|
|
||||||
const handleSelect = async (option) => {
|
const handleSelect = async (option) => {
|
||||||
if (option) {
|
if (option) {
|
||||||
setCascaderValue(option[option.length - 1]);
|
setCascaderValue(isChinaRegion ? option : option[option.length - 1]);
|
||||||
} else {
|
} else {
|
||||||
setCascaderValue({});
|
setCascaderValue({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkedPopup = () => {
|
const checkedPopup = () => {
|
||||||
if (collection && collection.name) {
|
if (!isChinaRegion) {
|
||||||
run();
|
collectionRun();
|
||||||
|
} else {
|
||||||
|
areaRun();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,18 +149,47 @@ export const AntdCascader = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<MobileProvider>
|
<MobileProvider>
|
||||||
<SearchBar
|
{!isChinaRegion ? (
|
||||||
placeholder="请输入内容"
|
<>
|
||||||
value={searchValue}
|
<SearchBar
|
||||||
onChange={(value) => {
|
placeholder="请输入内容"
|
||||||
const paramsFilter = { ...filter };
|
value={searchValue}
|
||||||
paramsFilter[fieldNames['label']] = { $includes: value };
|
onChange={(value) => {
|
||||||
setFilter(paramsFilter);
|
const paramsFilter = { ...filter };
|
||||||
setSearchValue(value);
|
paramsFilter[fieldNames['label']] = { $includes: value };
|
||||||
|
setFilter(paramsFilter);
|
||||||
|
setSearchValue(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Divider />
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
<CascaderView
|
||||||
|
loading={isChinaRegion ? areaLoading : collectionLoading}
|
||||||
|
fieldNames={fieldNames}
|
||||||
|
options={options}
|
||||||
|
onChange={(value, extend) => {
|
||||||
|
if (isChinaRegion) {
|
||||||
|
const maxLevel = field.componentProps.maxLevel;
|
||||||
|
const targetOption = extend['items'][extend['items'].length - 1];
|
||||||
|
if (maxLevel > targetOption.level) {
|
||||||
|
targetOption.children = [];
|
||||||
|
}
|
||||||
|
loadData(extend['items'], (data) => {
|
||||||
|
if (data?.data.length) {
|
||||||
|
targetOption.children = data.data.map((item) => {
|
||||||
|
if (maxLevel > item.level) {
|
||||||
|
item.isLeaf = false;
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
setOptions([...options]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
handleSelect(extend['items']);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Divider />
|
|
||||||
<CascaderView options={options} onChange={(value, extend) => handleSelect(extend['items'])} />
|
|
||||||
<Space justify="evenly" align="center">
|
<Space justify="evenly" align="center">
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -163,20 +206,25 @@ export const AntdCascader = observer((props) => {
|
|||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const changevalue = ['m2m', 'o2m'].includes(collectionField.interface)
|
const changevalue = multiple ? getChangValue(formCascaderValues, cascaderValue, index) : cascaderValue;
|
||||||
? getChangValue(formCascaderValues, cascaderValue, index)
|
|
||||||
: cascaderValue;
|
|
||||||
onChange(changevalue);
|
onChange(changevalue);
|
||||||
setValueText(getValueText(flatOption, cascaderValue, '', fieldNames['label']));
|
const valText = isChinaRegion
|
||||||
|
? getChinaRegionText(cascaderValue, fieldNames)
|
||||||
|
: getValueText(flatOption, cascaderValue, '', fieldNames['label']);
|
||||||
|
setValueText(valText);
|
||||||
setPopupVisible(false);
|
setPopupVisible(false);
|
||||||
const paramsFilter = { ...filter };
|
if (!isChinaRegion) {
|
||||||
if (paramsFilter[fieldNames['label']]) delete paramsFilter[fieldNames['label']];
|
const paramsFilter = { ...filter };
|
||||||
setSearchValue('');
|
delete paramsFilter[fieldNames['label']];
|
||||||
setFilter(paramsFilter);
|
setSearchValue('');
|
||||||
|
setFilter(paramsFilter);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
disabled={
|
disabled={
|
||||||
!changOnSelect
|
!changOnSelect
|
||||||
? cascaderValue && cascaderValue !== '{}' && !cascaderValue?.children
|
? cascaderValue &&
|
||||||
|
cascaderValue !== '{}' &&
|
||||||
|
(!cascaderValue?.children || !cascaderValue?.children.length)
|
||||||
? false
|
? false
|
||||||
: true
|
: true
|
||||||
: cascaderValue && cascaderValue !== '{}'
|
: cascaderValue && cascaderValue !== '{}'
|
||||||
@ -232,16 +280,18 @@ const getChangValue = (formCascaderValues, cascaderValue, index) => {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getChinaRegionText = (value, fieldNames) => {
|
||||||
|
return value?.reduce((prev, curr, index) => {
|
||||||
|
return prev + `${curr[fieldNames['label']]}${value.length - 1 === index ? '' : '/'}`;
|
||||||
|
}, '');
|
||||||
|
};
|
||||||
|
|
||||||
export const InternalCascader = observer((props) => {
|
export const InternalCascader = observer((props) => {
|
||||||
const { value, onChange } = props as any;
|
const { value, onChange, multiple } = props as any;
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const cm = useCollectionManager();
|
|
||||||
const collectionField = cm.getCollectionField(fieldSchema['x-collection-field']);
|
|
||||||
const form = useForm();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isArray(value) ? (
|
{isArray(value) && multiple ? (
|
||||||
<>
|
<>
|
||||||
{value.map((item, index) => {
|
{value.map((item, index) => {
|
||||||
const filterProps = {
|
const filterProps = {
|
||||||
@ -256,7 +306,7 @@ export const InternalCascader = observer((props) => {
|
|||||||
) : (
|
) : (
|
||||||
<AntdCascader {...props} />
|
<AntdCascader {...props} />
|
||||||
)}
|
)}
|
||||||
{['m2m', 'o2m'].includes(collectionField.interface) ? (
|
{multiple ? (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
style={{
|
style={{
|
||||||
@ -270,6 +320,7 @@ export const InternalCascader = observer((props) => {
|
|||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const pushValue = value ? [...value, {}] : [{}, {}];
|
const pushValue = value ? [...value, {}] : [{}, {}];
|
||||||
|
|
||||||
onChange(pushValue);
|
onChange(pushValue);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { AssociationField, useCollectionManager } from '@tachybase/client';
|
||||||
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@tachybase/schema';
|
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@tachybase/schema';
|
||||||
import { isArray } from '@tachybase/utils/client';
|
|
||||||
|
|
||||||
import { InternalCascader } from './AntdCadcader';
|
import { InternalCascader } from './AntdCadcader';
|
||||||
import { ReadPretty } from './ReadPretty';
|
import { ReadPretty } from './ReadPretty';
|
||||||
@ -10,5 +10,11 @@ export const MCascader = connect(
|
|||||||
mapProps((props) => {
|
mapProps((props) => {
|
||||||
return { ...props };
|
return { ...props };
|
||||||
}),
|
}),
|
||||||
mapReadPretty(ReadPretty),
|
mapReadPretty((props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const cm = useCollectionManager();
|
||||||
|
const collectionField = cm.getCollectionField(fieldSchema['x-collection-field']);
|
||||||
|
const isChinaRegion = collectionField.interface === 'chinaRegion';
|
||||||
|
return isChinaRegion ? <ReadPretty {...props} /> : <AssociationField.ReadPretty {...props} />;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { css, useCollectionField, useCollectionManager } from '@tachybase/client';
|
import { AssociationField, css, useCollectionField, useCollectionManager } from '@tachybase/client';
|
||||||
import { connect, isValid, mapProps, mapReadPretty, useField, useFieldSchema } from '@tachybase/schema';
|
import { connect, isValid, mapProps, mapReadPretty, useField, useFieldSchema } from '@tachybase/schema';
|
||||||
import { isArray } from '@tachybase/utils/client';
|
import { isArray } from '@tachybase/utils/client';
|
||||||
|
|
||||||
@ -28,48 +28,7 @@ export const MSelect = connect(
|
|||||||
return { ...filterProps };
|
return { ...filterProps };
|
||||||
}),
|
}),
|
||||||
mapReadPretty((props) => {
|
mapReadPretty((props) => {
|
||||||
const { value, fieldNames } = props;
|
return <AssociationField.ReadPretty {...props} />;
|
||||||
const collectionField = useCollectionField();
|
|
||||||
const isSlectField = ['multipleSelect', 'select'].includes(collectionField?.interface);
|
|
||||||
const field = useField<any>();
|
|
||||||
const dataSource = field?.dataSource || collectionField?.uiSchema.enum || [];
|
|
||||||
const fieldNamesLabel = fieldNames?.label || 'label';
|
|
||||||
if (isSlectField) {
|
|
||||||
const option = [];
|
|
||||||
if (!isArray(value)) {
|
|
||||||
if (typeof value === 'object') {
|
|
||||||
option.push(value);
|
|
||||||
} else {
|
|
||||||
option.push(dataSource.find((item) => item.value === value));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
option.push(...value);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{option.map((item, index) => (
|
|
||||||
<Tag key={index} color={getMobileColor(item.color)}>
|
|
||||||
{item.label}
|
|
||||||
</Tag>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
let redValue = '';
|
|
||||||
if (isArray(value)) {
|
|
||||||
redValue = value.reduce((prev, curr, index) => {
|
|
||||||
const currContext = value.length - 1 === index ? '' : ', ';
|
|
||||||
return prev + curr?.[fieldNamesLabel] + currContext;
|
|
||||||
}, '');
|
|
||||||
} else {
|
|
||||||
redValue = value?.[fieldNamesLabel] || '';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Space>{redValue}</Space>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user