Files
aurora-admin/frameworks/Transfer.jsx
T

104 lines
3.5 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useMemo } from 'react';
import './Transfer.css';
/**
* Aurora Admin Transfer(React)
* 对齐 组件7.txt Transfer 规范:左右两栏、搜索、复选框、已选数量
*
* props:
* - value / defaultValue : 已选 key 数组
* - data : [{ key, label, disabled? }]
* - titles : [左标题, 右标题]
* - filterable
* - onChange(keys)
*/
export default function Transfer({
value,
defaultValue = [],
data = [],
titles = ['候选列表', '已选列表'],
filterable = false,
onChange
}) {
const [selected, setSelected] = useState(value !== undefined ? value : defaultValue);
const current = value !== undefined ? value : selected;
const [leftChecked, setLeftChecked] = useState([]);
const [rightChecked, setRightChecked] = useState([]);
const [leftQ, setLeftQ] = useState('');
const [rightQ, setRightQ] = useState('');
const filteredLeft = useMemo(
() => data.filter(d => !current.includes(d.key) && d.label.includes(leftQ)),
[data, current, leftQ]
);
const filteredRight = useMemo(
() => data.filter(d => current.includes(d.key) && d.label.includes(rightQ)),
[data, current, rightQ]
);
const setVal = (next) => {
if (value === undefined) setSelected(next);
onChange && onChange(next);
};
const toggle = (which, key) => {
const item = data.find(d => d.key === key);
if (item && item.disabled) return;
const arr = which === 'left' ? leftChecked : rightChecked;
const set = which === 'left' ? setLeftChecked : setRightChecked;
set(arr.includes(key) ? arr.filter(k => k !== key) : [...arr, key]);
};
const moveRight = () => {
setVal([...current, ...leftChecked]);
setLeftChecked([]);
};
const moveLeft = () => {
const set = new Set(rightChecked);
setVal(current.filter(k => !set.has(k)));
setRightChecked([]);
};
const Panel = ({ title, items, checked, q, setQ, side }) => (
<div className="aa-transfer-panel">
<div className="aa-transfer-head">
<span>{title}</span>
<span className="count">{checked.length}/{items.length}</span>
</div>
{filterable && (
<div className="aa-transfer-search">
<input value={q} onChange={(e) => setQ(e.target.value)} placeholder="搜索" />
</div>
)}
<div className="aa-transfer-body">
{items.map(d => (
<div
key={d.key}
className={`aa-transfer-item${checked.includes(d.key) ? ' is-checked' : ''}${d.disabled ? ' is-disabled' : ''}`}
onClick={() => toggle(side, d.key)}
>
<span className="box">{checked.includes(d.key) ? '✓' : ''}</span>{d.label}
</div>
))}
{!items.length && <div className="aa-transfer-empty">无数据</div>}
</div>
</div>
);
return (
<div className="aa-transfer">
<Panel title={titles[0]} items={filteredLeft} checked={leftChecked} q={leftQ} setQ={setLeftQ} side="left" />
<div className="aa-transfer-ops">
<button disabled={!leftChecked.length} onClick={moveRight}>›</button>
<button disabled={!rightChecked.length} onClick={moveLeft}>‹</button>
</div>
<Panel title={titles[1]} items={filteredRight} checked={rightChecked} q={rightQ} setQ={setRightQ} side="right" />
</div>
);
}
/*
用法示例:
import Transfer from './Transfer';
const data = [{ key: '1', label: '研发部' }, { key: '2', label: '产品部' }];
<Transfer data={data} defaultValue={['1']} filterable onChange={setKeys} />
*/