Skip to content

Commit

Permalink
Merge pull request #257 from linjyuan/feat-MultiplePicker-addLink
Browse files Browse the repository at this point in the history
feat: MultiplePicker add value selected linkage
  • Loading branch information
DIYCCC committed Nov 22, 2023
2 parents c85af8e + a36ff0f commit c6a0098
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 10 deletions.
19 changes: 18 additions & 1 deletion src/components/MultiplePicker/demo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ const Page: FC = () => {
};

const foodList = [
{
foodName: '东坡肉',
foodId: '东坡肉',
},
{
foodName: '宫保鸡丁',
foodId: '宫保鸡丁',
Expand All @@ -44,6 +48,10 @@ const Page: FC = () => {
foodName: '红烧肉',
foodId: '红烧肉',
},
{
foodName: '铁板牛肉',
foodId: '铁板牛肉',
},
];
const formsValues = {
youFood: ['红烧肉', '清蒸小黄鱼'],
Expand All @@ -70,7 +78,16 @@ const Page: FC = () => {
label: 'foodName',
value: 'foodId',
}}
defaultValue={['爆炒虾仁', '宫保鸡丁']}
defaultValue={['清蒸小黄鱼', '宫保鸡丁']}
valueLinks={{
清蒸小黄鱼: {
linkVals: ['爆炒虾仁', '铁板牛肉'],
unLlinkVals: ['可乐鸡翅'],
},
宫保鸡丁: {
unLlinkVals: ['红烧肉'],
},
}}
clear
/>
<MultiplePicker
Expand Down
5 changes: 5 additions & 0 deletions src/components/MultiplePicker/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
.alitajs-dform-multiple-picker-checked {
color: @alita-dform-radio-color;
}
.alitajs-dform-box-wrapper-disabled,
.alitajs-dform-box-wrapper-disabled + div {
color: @color-text-disabled;
filter: grayscale(100%);
}

.alitajs-dform-multiple-picker-right {
width: 40 * @hd;
Expand Down
14 changes: 14 additions & 0 deletions src/components/MultiplePicker/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ nav:
| clear | 清空数据 | boolean | `false` ||
| renderHeader | 组件头部 | `string` or `React.ReactNode` | '' ||
| renderFooter | 组件尾部 | `string` or `React.ReactNode` | '' ||
| valueLink | 选值联动 | `ValueLinks` | [] ||

## ValueLinks

| 参数 | 说明 | 类型 | 默认值 | 是否必填 |
| --------------- | ------------ | --------------- | ------ | -------- |
| `[key: string]` | 联动其他字段 | `ChangeValLink` | - ||

## ChangeValLink

| 参数 | 说明 | 类型 | 默认值 | 是否必填 |
| ----------- | ------------ | ------------- | -------- | -------- | --- |
| linkVals | 选中的值集 | `Array<string | number>` | - ||
| unLlinkVals | 非选中的值集 | `Array<string | number>` | - ||

## 备注

Expand Down
2 changes: 2 additions & 0 deletions src/components/MultiplePicker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const MultiplePicker: FC<IMultiplePickerProps> = (props) => {
titleStyle,
formFlag = true,
disabled = false,
valueLinks = {},
} = props;

const { cDisabled } = useContext<CardContextProps>(CardContext);
Expand Down Expand Up @@ -101,6 +102,7 @@ const MultiplePicker: FC<IMultiplePickerProps> = (props) => {
data={aliasData}
onChange={fieldChange}
fieldProps={fieldKey}
valueLinks={valueLinks}
>
<HorizontalTitle
required={required}
Expand Down
9 changes: 9 additions & 0 deletions src/components/MultiplePicker/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ export interface IDataItem {
[key: string]: string | number;
}

export interface ChangeValLink {
linkVals?: Array<string | number>;
unLlinkVals?: Array<string | number>;
}

export interface ValueLinks {
[key: string]: ChangeValLink;
}
export interface IMultiplePickerProps extends BaseComponentProps {
data: IDataItem[];
onChange?: (currentActiveLink: (string | number)[]) => void;
Expand All @@ -22,4 +30,5 @@ export interface IMultiplePickerProps extends BaseComponentProps {
defaultValue?: (string | number)[] | undefined;
clear?: boolean;
arrow?: boolean;
valueLinks?: ValueLinks;
}
81 changes: 76 additions & 5 deletions src/components/MultiplePicker/multiplePickerGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import React, { FC, useState, useEffect } from 'react';
import { Modal, List } from 'antd-mobile-v2';
import classnames from 'classnames';
import { IMultiplePickerProps, IDataItem } from './interface';
import {
IMultiplePickerProps,
IDataItem,
ValueLinks,
ChangeValLink,
} from './interface';
import TextItem from '../../baseComponents/TextItem';
import './index.less';

Expand All @@ -12,6 +17,7 @@ interface IMultiplePickerGroupProps
onChange?: (values: (string | number)[] | undefined, flag?: string) => void;
value?: (string | number)[] | undefined;
children?: any;
valueLinks: ValueLinks;
}

const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
Expand All @@ -36,6 +42,7 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
clear = false,
extra,
arrow,
valueLinks,
} = props;

const [selValueList, setSelValueList] = useState<(string | number)[]>([]); // 当前选中的值列表
Expand All @@ -44,13 +51,49 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {

const isVertical = positionType === 'vertical';

const setValueList = (
changeValLink: ChangeValLink,
hasValue: (string | number)[],
oldValue: (string | number)[],
): (string | number)[] => {
let valueArr: (string | number)[] = hasValue;
if (changeValLink && Object.keys(changeValLink).length > 0) {
if (changeValLink?.linkVals) {
valueArr = Array.from(
new Set([...valueArr, ...(changeValLink?.linkVals || [])]),
);
}
if (changeValLink?.unLlinkVals) {
changeValLink?.unLlinkVals?.forEach((it: string | number) => {
if (oldValue?.some((i) => i === it)) {
valueArr.splice(valueArr.indexOf(it), 1);
}
});
}
}
return [...valueArr];
};

/**
* 设值
* @param da 数据源
* @param val 值
*/
const setValues = (da: IDataItem[], val: (string | number)[] | undefined) => {
const filter = da.filter((item) => val?.indexOf(item.value) !== -1);
let hasValue = Array.isArray(val) && val.length > 0 ? [...val] : [];

if (
Array.isArray(val) &&
val.length > 0 &&
valueLinks &&
Object.keys(valueLinks)?.length > 0
) {
val?.forEach((item, index, array: (string | number)[]) => {
hasValue = setValueList(valueLinks[item], hasValue, array);
});
}

const filter = da.filter((item) => hasValue?.indexOf(item.value) !== -1);
const labels = filter.map((item) => item.label);
const values = filter.map((item) => item.value);
setMultipleLabel(labels.join(','));
Expand All @@ -62,15 +105,22 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
const { labels, values } = setValues(data, value || []);
setMultipleLabel(labels.join(','));
setSelValueList(values);
}, [value]);
}, [value, JSON.stringify(valueLinks)]);
useEffect(() => {
const { labels, values } = setValues(data, value || []);
setMultipleLabel(labels.join(','));
setSelValueList(values);
}, [data]);
}, [data, JSON.stringify(valueLinks)]);

const pickerClick = (val: IDataItem) => {
const list = JSON.parse(JSON.stringify(selValueList));
let list = JSON.parse(JSON.stringify(selValueList));
if (
!list.some((i: string | number) => i === val.value) &&
valueLinks[val?.value] &&
Object.keys(valueLinks[val?.value]).length > 0
) {
list = setValueList(valueLinks[val?.value], list, list);
}
if (list.indexOf(val.value) !== -1) {
list.splice(list.indexOf(val.value), 1);
} else {
Expand All @@ -82,6 +132,25 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
setSelValueList(list);
};

const isHasLink = (value: string | number): boolean => {
let isNoHasLink = false;
if (valueLinks && Object.keys(valueLinks).length > 0) {
selValueList.forEach((item) => {
if (valueLinks[item] && Object.keys(valueLinks[item]).length > 0) {
if (
(valueLinks[item]?.linkVals &&
valueLinks[item]?.linkVals?.some((i) => i === value)) ||
(valueLinks[item]?.unLlinkVals &&
valueLinks[item]?.unLlinkVals?.some((i) => i === value))
) {
isNoHasLink = true;
}
}
});
}
return isNoHasLink;
};

const openMoal = () => {
if (disabled) return;
const { labels, values } = setValues(data, value || []);
Expand Down Expand Up @@ -173,6 +242,7 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
<div
className="alitajs-dform-multiple-picker-item"
onClick={() => {
if (isHasLink(item.value)) return;
pickerClick(item);
}}
>
Expand All @@ -181,6 +251,7 @@ const MultiplePickerGroup: FC<IMultiplePickerGroupProps> = (props) => {
'alitajs-dform-multiple-picker-label': true,
'alitajs-dform-multiple-picker-checked':
selValueList.indexOf(item?.value) !== -1,
'alitajs-dform-box-wrapper-disabled': isHasLink(item.value),
})}
>
{item.label}
Expand Down
11 changes: 10 additions & 1 deletion src/components/MultiplePicker/tests/demos/single.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ interface pageProps {
}
const Page: FC<pageProps> = (props) => {
const { onSbumit } = props;
const [mulValue, setMulValue] = useState<(string | number)[]>(['红烧肉']);
const [mulValue, setMulValue] = useState<(string | number)[]>(['宫保鸡丁']);
return (
<>
<MultiplePicker
Expand All @@ -51,6 +51,15 @@ const Page: FC<pageProps> = (props) => {
formFlag={false}
defaultValue={mulValue}
clear
valueLinks={{
清蒸小黄鱼: {
linkVals: ['爆炒虾仁'],
unLlinkVals: ['可乐鸡翅'],
},
宫保鸡丁: {
unLlinkVals: ['红烧肉'],
},
}}
onChange={(e: (string | number)[]) => setMulValue(e)}
/>
<WhiteSpace size="sm" />
Expand Down
20 changes: 17 additions & 3 deletions src/components/MultiplePicker/tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,31 @@ test('single basic', async () => {
const { getByText, getAllByText } = render(
<SingleText onSbumit={onSbumit} />,
);
expect(getByText('红烧肉')).toBeDefined();
expect(getByText('宫保鸡丁')).toBeDefined();
await waitFor(() => {
fireEvent.click(getByText('红烧肉'));
fireEvent.click(getByText('宫保鸡丁'));
});
await waitFor(() => {
fireEvent.click(getByText('清蒸小黄鱼'));
});
await waitFor(() => {
expect(getByText('红烧肉')).toHaveClass(
'alitajs-dform-box-wrapper-disabled',
);
expect(getByText('爆炒虾仁')?.parentElement?.lastChild).toHaveClass(
'alitajs-dform-tick',
);
expect(getByText('可乐鸡翅')).toHaveClass(
'alitajs-dform-box-wrapper-disabled',
);
});
await waitFor(() => {
fireEvent.click(getByText('可乐鸡翅'));
});
await waitFor(() => {
fireEvent.click(getByText('确定'));
});
expect(getByText('可乐鸡翅,红烧肉')).toBeDefined();
expect(getByText('宫保鸡丁,爆炒虾仁,清蒸小黄鱼')).toBeDefined();
await waitFor(() => {
fireEvent.click(getByText('Submit'));
});
Expand Down

0 comments on commit c6a0098

Please sign in to comment.