140 lines
4.0 KiB
TypeScript
140 lines
4.0 KiB
TypeScript
import React, { useState } from "react";
|
||
import { SearchOutlined } from "@ant-design/icons";
|
||
import { Input, Button } from "antd";
|
||
import { DeleteOutlined } from "@ant-design/icons";
|
||
import { DeviceSelectionProps } from "./data";
|
||
import SelectionPopup from "./selectionPopup";
|
||
import style from "./index.module.scss";
|
||
|
||
const DeviceSelection: React.FC<DeviceSelectionProps> = ({
|
||
selectedOptions,
|
||
onSelect,
|
||
placeholder = "选择设备",
|
||
className = "",
|
||
mode = "input",
|
||
open,
|
||
onOpenChange,
|
||
selectedListMaxHeight = 300, // 默认300
|
||
showInput = true,
|
||
showSelectedList = true,
|
||
readonly = false,
|
||
}) => {
|
||
// 弹窗控制
|
||
const [popupVisible, setPopupVisible] = useState(false);
|
||
const isDialog = mode === "dialog";
|
||
const realVisible = isDialog ? !!open : popupVisible;
|
||
const setRealVisible = (v: boolean) => {
|
||
if (isDialog && onOpenChange) onOpenChange(v);
|
||
if (!isDialog) setPopupVisible(v);
|
||
};
|
||
|
||
// 打开弹窗
|
||
const openPopup = () => {
|
||
if (readonly) return;
|
||
setRealVisible(true);
|
||
};
|
||
|
||
// 获取显示文本
|
||
const getDisplayText = () => {
|
||
if (selectedOptions.length === 0) return "";
|
||
return `已选择 ${selectedOptions.length} 个设备`;
|
||
};
|
||
|
||
// 删除已选设备
|
||
const handleRemoveDevice = (id: number) => {
|
||
if (readonly) return;
|
||
onSelect(selectedOptions.filter(v => v.id !== id));
|
||
};
|
||
|
||
return (
|
||
<>
|
||
{/* mode=input 显示输入框,mode=dialog不显示 */}
|
||
{mode === "input" && showInput && (
|
||
<div className={`${style.inputWrapper} ${className}`}>
|
||
<Input
|
||
placeholder={placeholder}
|
||
value={getDisplayText()}
|
||
onClick={openPopup}
|
||
prefix={<SearchOutlined />}
|
||
allowClear={!readonly}
|
||
size="large"
|
||
readOnly={readonly}
|
||
disabled={readonly}
|
||
style={
|
||
readonly ? { background: "#f5f5f5", cursor: "not-allowed" } : {}
|
||
}
|
||
/>
|
||
</div>
|
||
)}
|
||
{/* 已选设备列表窗口 */}
|
||
{mode === "input" && showSelectedList && selectedOptions.length > 0 && (
|
||
<div
|
||
className={style.selectedListWindow}
|
||
style={{
|
||
maxHeight: selectedListMaxHeight,
|
||
overflowY: "auto",
|
||
marginTop: 8,
|
||
border: "1px solid #e5e6eb",
|
||
borderRadius: 8,
|
||
background: "#fff",
|
||
}}
|
||
>
|
||
{selectedOptions.map(device => (
|
||
<div
|
||
key={device.id}
|
||
className={style.selectedListRow}
|
||
style={{
|
||
display: "flex",
|
||
alignItems: "center",
|
||
padding: "4px 8px",
|
||
borderBottom: "1px solid #f0f0f0",
|
||
fontSize: 14,
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
flex: 1,
|
||
minWidth: 0,
|
||
whiteSpace: "nowrap",
|
||
overflow: "hidden",
|
||
textOverflow: "ellipsis",
|
||
}}
|
||
>
|
||
【 {device.name}】 - {device.wechatId}
|
||
</div>
|
||
{!readonly && (
|
||
<Button
|
||
type="text"
|
||
icon={<DeleteOutlined />}
|
||
size="small"
|
||
style={{
|
||
marginLeft: 4,
|
||
color: "#ff4d4f",
|
||
border: "none",
|
||
background: "none",
|
||
minWidth: 24,
|
||
height: 24,
|
||
display: "flex",
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
}}
|
||
onClick={() => handleRemoveDevice(device.id)}
|
||
/>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
)}
|
||
{/* 弹窗 */}
|
||
<SelectionPopup
|
||
visible={realVisible && !readonly}
|
||
onClose={() => setRealVisible(false)}
|
||
selectedOptions={selectedOptions}
|
||
onSelect={onSelect}
|
||
/>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default DeviceSelection;
|