feat: 本次提交更新内容如下
存一版
This commit is contained in:
10
nkebao/src/components/AccountSelection/api.ts
Normal file
10
nkebao/src/components/AccountSelection/api.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import request from "@/api/request";
|
||||||
|
|
||||||
|
// 获取好友列表
|
||||||
|
export function getAccountList(params: {
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
keyword?: string;
|
||||||
|
}) {
|
||||||
|
return request("/v1/workbench/account-list", params, "GET");
|
||||||
|
}
|
||||||
231
nkebao/src/components/AccountSelection/index.module.scss
Normal file
231
nkebao/src/components/AccountSelection/index.module.scss
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
.inputWrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.inputIcon {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #bdbdbd;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
padding-left: 38px !important;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 16px !important;
|
||||||
|
border: 1px solid #e5e6eb !important;
|
||||||
|
font-size: 16px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100vh;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.popupHeader {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.popupTitle {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.searchWrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.searchInput {
|
||||||
|
padding-left: 40px !important;
|
||||||
|
padding-top: 8px !important;
|
||||||
|
padding-bottom: 8px !important;
|
||||||
|
border-radius: 24px !important;
|
||||||
|
border: 1px solid #e5e6eb !important;
|
||||||
|
font-size: 15px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
}
|
||||||
|
.searchIcon {
|
||||||
|
position: absolute;
|
||||||
|
left: 12px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #bdbdbd;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.clearBtn {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
height: 24px;
|
||||||
|
width: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
min-width: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.friendList {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.friendListInner {
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.friendItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
&:hover {
|
||||||
|
background: #f5f6fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.radioWrapper {
|
||||||
|
margin-right: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.radioSelected {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #1890ff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.radioUnselected {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid #e5e6eb;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.radioDot {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #1890ff;
|
||||||
|
}
|
||||||
|
.friendInfo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.friendAvatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.avatarImg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
.friendDetail {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.friendName {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #222;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.friendId {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.friendCustomer {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loadingBox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.loadingText {
|
||||||
|
color: #888;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.emptyBox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.emptyText {
|
||||||
|
color: #888;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginationRow {
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.totalCount {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
.paginationControls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.pageBtn {
|
||||||
|
padding: 0 8px;
|
||||||
|
height: 32px;
|
||||||
|
min-width: 32px;
|
||||||
|
}
|
||||||
|
.pageInfo {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popupFooter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.selectedCount {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
.footerBtnGroup {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.cancelBtn {
|
||||||
|
padding: 0 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
border: 1px solid #e5e6eb;
|
||||||
|
}
|
||||||
|
.confirmBtn {
|
||||||
|
padding: 0 24px;
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
340
nkebao/src/components/AccountSelection/index.tsx
Normal file
340
nkebao/src/components/AccountSelection/index.tsx
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { SearchOutlined, DeleteOutlined } from "@ant-design/icons";
|
||||||
|
import { Popup } from "antd-mobile";
|
||||||
|
import { Button, Input } from "antd";
|
||||||
|
import { getAccountList } from "./api";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
import Layout from "@/components/Layout/Layout";
|
||||||
|
import PopupHeader from "@/components/PopuLayout/header";
|
||||||
|
import PopupFooter from "@/components/PopuLayout/footer";
|
||||||
|
|
||||||
|
// 账号对象类型
|
||||||
|
export interface AccountItem {
|
||||||
|
id: number;
|
||||||
|
userName: string;
|
||||||
|
realName: string;
|
||||||
|
departmentName: string;
|
||||||
|
avatar?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件属性接口
|
||||||
|
interface AccountSelectionProps {
|
||||||
|
value: number[];
|
||||||
|
onChange: (ids: number[]) => void;
|
||||||
|
accounts?: AccountItem[];
|
||||||
|
placeholder?: string;
|
||||||
|
className?: string;
|
||||||
|
visible?: boolean;
|
||||||
|
onVisibleChange?: (visible: boolean) => void;
|
||||||
|
selectedListMaxHeight?: number;
|
||||||
|
showInput?: boolean;
|
||||||
|
showSelectedList?: boolean;
|
||||||
|
readonly?: boolean;
|
||||||
|
onConfirm?: (selectedIds: number[], selectedItems: AccountItem[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function AccountSelection({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
accounts: propAccounts = [],
|
||||||
|
placeholder = "选择账号",
|
||||||
|
className = "",
|
||||||
|
visible,
|
||||||
|
onVisibleChange,
|
||||||
|
selectedListMaxHeight = 300,
|
||||||
|
showInput = true,
|
||||||
|
showSelectedList = true,
|
||||||
|
readonly = false,
|
||||||
|
onConfirm,
|
||||||
|
}: AccountSelectionProps) {
|
||||||
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
|
const [accountsList, setAccountsList] = useState<AccountItem[]>(propAccounts);
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
// 受控弹窗逻辑
|
||||||
|
const realVisible = visible !== undefined ? visible : popupVisible;
|
||||||
|
const setRealVisible = (v: boolean) => {
|
||||||
|
if (onVisibleChange) onVisibleChange(v);
|
||||||
|
if (visible === undefined) setPopupVisible(v);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 打开弹窗时先显示弹窗再请求账号数据
|
||||||
|
const openPopup = () => {
|
||||||
|
if (readonly) return;
|
||||||
|
setCurrentPage(1);
|
||||||
|
setSearchQuery("");
|
||||||
|
setRealVisible(true);
|
||||||
|
setTimeout(async () => {
|
||||||
|
if (typeof getAccountList === "function") {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await getAccountList({
|
||||||
|
page: 1,
|
||||||
|
limit: 100,
|
||||||
|
keyword: "",
|
||||||
|
});
|
||||||
|
if (response && response.list) {
|
||||||
|
setAccountsList(response.list);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 搜索时请求账号数据
|
||||||
|
useEffect(() => {
|
||||||
|
if (!realVisible) return;
|
||||||
|
const timer = setTimeout(async () => {
|
||||||
|
setCurrentPage(1);
|
||||||
|
if (typeof getAccountList === "function") {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const response = await getAccountList({
|
||||||
|
page: 1,
|
||||||
|
limit: 100,
|
||||||
|
keyword: searchQuery,
|
||||||
|
});
|
||||||
|
if (response && response.list) {
|
||||||
|
setAccountsList(response.list);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 400);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [searchQuery, realVisible]);
|
||||||
|
|
||||||
|
// 渲染和过滤都依赖内部accountsList
|
||||||
|
const filteredAccounts = accountsList.filter(
|
||||||
|
(acc) =>
|
||||||
|
acc.userName.includes(searchQuery) ||
|
||||||
|
acc.realName.includes(searchQuery) ||
|
||||||
|
acc.departmentName.includes(searchQuery)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 处理账号选择
|
||||||
|
const handleAccountToggle = (accountId: number) => {
|
||||||
|
if (readonly) return;
|
||||||
|
const newSelected = value.includes(accountId)
|
||||||
|
? value.filter((id) => id !== accountId)
|
||||||
|
: [...value, accountId];
|
||||||
|
onChange(newSelected);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取显示文本
|
||||||
|
const getDisplayText = () => {
|
||||||
|
if (value.length === 0) return "";
|
||||||
|
return `已选择 ${value.length} 个账号`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取已选账号详细信息
|
||||||
|
const selectedAccountObjs = [
|
||||||
|
...accountsList.filter((acc) => value.includes(acc.id)),
|
||||||
|
...value
|
||||||
|
.filter((id) => !accountsList.some((acc) => acc.id === id))
|
||||||
|
.map((id) => ({
|
||||||
|
id,
|
||||||
|
userName: String(id),
|
||||||
|
realName: "",
|
||||||
|
departmentName: "",
|
||||||
|
})),
|
||||||
|
];
|
||||||
|
|
||||||
|
// 删除已选账号
|
||||||
|
const handleRemoveAccount = (id: number) => {
|
||||||
|
if (readonly) return;
|
||||||
|
onChange(value.filter((d) => d !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认选择
|
||||||
|
const handleConfirm = () => {
|
||||||
|
if (onConfirm) {
|
||||||
|
onConfirm(value, selectedAccountObjs);
|
||||||
|
}
|
||||||
|
setRealVisible(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* 输入框 */}
|
||||||
|
{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>
|
||||||
|
)}
|
||||||
|
{/* 已选账号列表窗口 */}
|
||||||
|
{showSelectedList && selectedAccountObjs.length > 0 && (
|
||||||
|
<div
|
||||||
|
className={style.selectedListWindow}
|
||||||
|
style={{
|
||||||
|
maxHeight: selectedListMaxHeight,
|
||||||
|
overflowY: "auto",
|
||||||
|
marginTop: 8,
|
||||||
|
border: "1px solid #e5e6eb",
|
||||||
|
borderRadius: 8,
|
||||||
|
background: "#fff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{selectedAccountObjs.map((acc) => (
|
||||||
|
<div
|
||||||
|
key={acc.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",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{acc.userName}({acc.realName})- {acc.departmentName}
|
||||||
|
</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={() => handleRemoveAccount(acc.id)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* 弹窗 */}
|
||||||
|
<Popup
|
||||||
|
visible={realVisible && !readonly}
|
||||||
|
onMaskClick={() => setRealVisible(false)}
|
||||||
|
position="bottom"
|
||||||
|
bodyStyle={{ height: "100vh" }}
|
||||||
|
>
|
||||||
|
<Layout
|
||||||
|
header={
|
||||||
|
<PopupHeader
|
||||||
|
title="选择账号"
|
||||||
|
searchQuery={searchQuery}
|
||||||
|
setSearchQuery={setSearchQuery}
|
||||||
|
searchPlaceholder="搜索账号"
|
||||||
|
loading={loading}
|
||||||
|
onRefresh={() => {}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
footer={
|
||||||
|
<PopupFooter
|
||||||
|
total={filteredAccounts.length}
|
||||||
|
currentPage={currentPage}
|
||||||
|
totalPages={1}
|
||||||
|
loading={loading}
|
||||||
|
selectedCount={value.length}
|
||||||
|
onPageChange={setCurrentPage}
|
||||||
|
onCancel={() => setRealVisible(false)}
|
||||||
|
onConfirm={handleConfirm}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className={style.friendList}>
|
||||||
|
{loading ? (
|
||||||
|
<div className={style.loadingBox}>
|
||||||
|
<div className={style.loadingText}>加载中...</div>
|
||||||
|
</div>
|
||||||
|
) : filteredAccounts.length > 0 ? (
|
||||||
|
<div className={style.friendListInner}>
|
||||||
|
{filteredAccounts.map((acc) => (
|
||||||
|
<label
|
||||||
|
key={acc.id}
|
||||||
|
className={style.friendItem}
|
||||||
|
onClick={() => !readonly && handleAccountToggle(acc.id)}
|
||||||
|
>
|
||||||
|
<div className={style.radioWrapper}>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
value.includes(acc.id)
|
||||||
|
? style.radioSelected
|
||||||
|
: style.radioUnselected
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{value.includes(acc.id) && (
|
||||||
|
<div className={style.radioDot}></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={style.friendInfo}>
|
||||||
|
<div className={style.friendAvatar}>
|
||||||
|
{acc.avatar ? (
|
||||||
|
<img
|
||||||
|
src={acc.avatar}
|
||||||
|
alt={acc.userName}
|
||||||
|
className={style.avatarImg}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
acc.userName.charAt(0)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={style.friendDetail}>
|
||||||
|
<div className={style.friendName}>{acc.userName}</div>
|
||||||
|
<div className={style.friendId}>
|
||||||
|
真实姓名: {acc.realName}
|
||||||
|
</div>
|
||||||
|
<div className={style.friendId}>
|
||||||
|
部门: {acc.departmentName}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className={style.emptyBox}>
|
||||||
|
<div className={style.emptyText}>
|
||||||
|
{searchQuery
|
||||||
|
? `没有找到包含"${searchQuery}"的账号`
|
||||||
|
: "没有找到账号"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</Popup>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import DeviceSelection from "@/components/DeviceSelection";
|
|||||||
import FriendSelection from "@/components/FriendSelection";
|
import FriendSelection from "@/components/FriendSelection";
|
||||||
import GroupSelection from "@/components/GroupSelection";
|
import GroupSelection from "@/components/GroupSelection";
|
||||||
import ContentLibrarySelection from "@/components/ContentLibrarySelection";
|
import ContentLibrarySelection from "@/components/ContentLibrarySelection";
|
||||||
|
import AccountSelection from "@/components/AccountSelection";
|
||||||
|
|
||||||
const ComponentTest: React.FC = () => {
|
const ComponentTest: React.FC = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -25,6 +26,8 @@ const ComponentTest: React.FC = () => {
|
|||||||
// 内容库选择状态
|
// 内容库选择状态
|
||||||
const [selectedLibraries, setSelectedLibraries] = useState<string[]>([]);
|
const [selectedLibraries, setSelectedLibraries] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const [selectedAccounts, setSelectedAccounts] = useState<string[]>([]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout header={<NavCommon title="组件调试" />}>
|
<Layout header={<NavCommon title="组件调试" />}>
|
||||||
<div style={{ padding: 16 }}>
|
<div style={{ padding: 16 }}>
|
||||||
@@ -131,6 +134,23 @@ const ComponentTest: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
|
|
||||||
|
<Tabs.Tab title="账号选择" key="accounts">
|
||||||
|
<div style={{ padding: "16px 0" }}>
|
||||||
|
<h3 style={{ marginBottom: 16 }}>AccountSelection 组件测试</h3>
|
||||||
|
<AccountSelection
|
||||||
|
value={selectedAccounts}
|
||||||
|
onChange={setSelectedAccounts}
|
||||||
|
// 可根据实际API和props补充其它参数
|
||||||
|
/>
|
||||||
|
<div style={{ marginTop: 16 }}>
|
||||||
|
<strong>已选账号:</strong>
|
||||||
|
{selectedAccounts.length > 0
|
||||||
|
? selectedAccounts.join(", ")
|
||||||
|
: "无"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tabs.Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -15,12 +15,9 @@ import style from "./index.module.scss";
|
|||||||
import StepIndicator from "@/components/StepIndicator";
|
import StepIndicator from "@/components/StepIndicator";
|
||||||
import Layout from "@/components/Layout/Layout";
|
import Layout from "@/components/Layout/Layout";
|
||||||
import NavCommon from "@/components/NavCommon";
|
import NavCommon from "@/components/NavCommon";
|
||||||
|
import AccountSelection from "@/components/AccountSelection";
|
||||||
|
import { getAccountList } from "@/components/AccountSelection/api";
|
||||||
|
|
||||||
const accountList = [
|
|
||||||
{ label: "客服A", value: "a" },
|
|
||||||
{ label: "客服B", value: "b" },
|
|
||||||
{ label: "客服C", value: "c" },
|
|
||||||
];
|
|
||||||
const scenarioList = [
|
const scenarioList = [
|
||||||
{ label: "海报获客", value: "poster" },
|
{ label: "海报获客", value: "poster" },
|
||||||
{ label: "电话获客", value: "phone" },
|
{ label: "电话获客", value: "phone" },
|
||||||
@@ -52,19 +49,13 @@ const TrafficDistributionForm: React.FC = () => {
|
|||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [current, setCurrent] = useState(0);
|
const [current, setCurrent] = useState(0);
|
||||||
const [selectedAccounts, setSelectedAccounts] = useState<string[]>([]);
|
const [selectedAccountIds, setSelectedAccountIds] = useState<number[]>([]);
|
||||||
const [distributeType, setDistributeType] = useState(1);
|
const [distributeType, setDistributeType] = useState(1);
|
||||||
const [maxPerDay, setMaxPerDay] = useState(50);
|
const [maxPerDay, setMaxPerDay] = useState(50);
|
||||||
const [timeType, setTimeType] = useState(1);
|
const [timeType, setTimeType] = useState(1);
|
||||||
const [timeRange, setTimeRange] = useState<any>(null);
|
const [timeRange, setTimeRange] = useState<any>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
// 账号搜索(模拟)
|
|
||||||
const [accountSearch, setAccountSearch] = useState("");
|
|
||||||
const filteredAccounts = accountList.filter((acc) =>
|
|
||||||
acc.label.includes(accountSearch)
|
|
||||||
);
|
|
||||||
|
|
||||||
const [targetUserCount, setTargetUserCount] = useState(100);
|
const [targetUserCount, setTargetUserCount] = useState(100);
|
||||||
const [targetTypes, setTargetTypes] = useState<string[]>([]);
|
const [targetTypes, setTargetTypes] = useState<string[]>([]);
|
||||||
const [targetScenarios, setTargetScenarios] = useState<string[]>([]);
|
const [targetScenarios, setTargetScenarios] = useState<string[]>([]);
|
||||||
@@ -126,33 +117,10 @@ const TrafficDistributionForm: React.FC = () => {
|
|||||||
required
|
required
|
||||||
className={style.accountSelectItem}
|
className={style.accountSelectItem}
|
||||||
>
|
>
|
||||||
<Input
|
<AccountSelection
|
||||||
placeholder="请选择账号"
|
value={selectedAccountIds}
|
||||||
value={accountSearch}
|
onChange={setSelectedAccountIds}
|
||||||
onChange={(e) => setAccountSearch(e.target.value)}
|
|
||||||
suffix={<span className={style.accountSearchIcon} />}
|
|
||||||
/>
|
/>
|
||||||
<div className={style.accountListWrap}>
|
|
||||||
{filteredAccounts.map((acc) => (
|
|
||||||
<label key={acc.value} className={style.accountItem}>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={selectedAccounts.includes(acc.value)}
|
|
||||||
onChange={(e) => {
|
|
||||||
setSelectedAccounts((val) =>
|
|
||||||
e.target.checked
|
|
||||||
? [...val, acc.value]
|
|
||||||
: val.filter((v) => v !== acc.value)
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<span>{acc.label}</span>
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className={style.accountSelectedCount}>
|
|
||||||
已选账号:<span>{selectedAccounts.length}</span> 个
|
|
||||||
</div>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="分配方式" name="distributeType" required>
|
<Form.Item label="分配方式" name="distributeType" required>
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
|
|||||||
Reference in New Issue
Block a user