FEAT => 本次更新项目为:

This commit is contained in:
超级老白兔
2025-08-14 18:12:03 +08:00
parent 5f58a1a2c4
commit d17ed6e5c3
8 changed files with 141 additions and 58 deletions

View File

@@ -33,7 +33,7 @@
"name": "vendor"
},
"index.html": {
"file": "assets/index-BIYsFR36.js",
"file": "assets/index-BRxvrekd.js",
"name": "index",
"src": "index.html",
"isEntry": true,
@@ -44,7 +44,7 @@
"_charts-D0fT04H8.js"
],
"css": [
"assets/index-B7GfwY9T.css"
"assets/index-qTkOjY3P.css"
]
}
}

View File

@@ -11,13 +11,13 @@
</style>
<!-- 引入 uni-app web-view SDK必须 -->
<script type="text/javascript" src="/websdk.js"></script>
<script type="module" crossorigin src="/assets/index-BIYsFR36.js"></script>
<script type="module" crossorigin src="/assets/index-BRxvrekd.js"></script>
<link rel="modulepreload" crossorigin href="/assets/vendor-2vc8h_ct.js">
<link rel="modulepreload" crossorigin href="/assets/ui-qLeQLv1F.js">
<link rel="modulepreload" crossorigin href="/assets/utils-6WF66_dS.js">
<link rel="modulepreload" crossorigin href="/assets/charts-D0fT04H8.js">
<link rel="stylesheet" crossorigin href="/assets/ui-D0C0OGrH.css">
<link rel="stylesheet" crossorigin href="/assets/index-B7GfwY9T.css">
<link rel="stylesheet" crossorigin href="/assets/index-qTkOjY3P.css">
</head>
<body>
<div id="root"></div>

View File

@@ -31,4 +31,5 @@ export interface AccountSelectionProps {
showSelectedList?: boolean;
readonly?: boolean;
onConfirm?: (selectedOptions: AccountItem[]) => void;
accountGroups?: any[]; // 传递账号组数据
}

View File

@@ -25,4 +25,5 @@ export interface DeviceSelectionProps {
showInput?: boolean; // 新增
showSelectedList?: boolean; // 新增
readonly?: boolean; // 新增
deviceGroups?: any[]; // 传递设备组数据
}

View File

@@ -23,8 +23,10 @@ export interface TrafficDistributionConfig {
timeType: number;
startTime: string;
endTime: string;
account: (string | number)[];
devices: string[];
accountGroups: any[];
accountGroupsOptions: any[];
deviceGroups: any[];
deviceGroupsOptions: any[];
pools: any[];
exp: number;
createTime: string;
@@ -52,8 +54,10 @@ export interface TrafficDistributionFormData {
timeType: number;
startTime: string;
endTime: string;
devices: string[];
account: (string | number)[];
deviceGroups: any[];
deviceGroupsOptions: any[];
accountGroups: any[];
accountGroupsOptions: any[];
pools: any[];
enabled: boolean;
}

View File

@@ -60,6 +60,51 @@
.accountSelectItem {
margin-bottom: 0 !important;
}
.deviceSelectItem {
margin-bottom: 0 !important;
}
.searchWrapper {
margin-bottom: 16px;
}
.tabWrapper {
margin-bottom: 16px;
}
.tabList {
display: flex;
background: #f5f5f5;
border-radius: 8px;
padding: 4px;
}
.tabItem {
flex: 1;
text-align: center;
padding: 8px 16px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
color: #666;
cursor: pointer;
transition: all 0.2s ease;
}
.tabItem:hover {
color: #1890ff;
}
.tabActive {
background: #fff;
color: #1890ff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.tabContent {
min-height: 200px;
}
.accountListWrap {
display: flex;
flex-wrap: wrap;

View File

@@ -9,6 +9,7 @@ import {
message,
Checkbox,
} from "antd";
import { SearchOutlined } from "@ant-design/icons";
import { useNavigate, useParams } from "react-router-dom";
import style from "./index.module.scss";
import StepIndicator from "@/components/StepIndicator";
@@ -16,6 +17,8 @@ import Layout from "@/components/Layout/Layout";
import NavCommon from "@/components/NavCommon";
import AccountSelection from "@/components/AccountSelection";
import { AccountItem } from "@/components/AccountSelection/data";
import DeviceSelection from "@/components/DeviceSelection";
import { DeviceSelectionItem } from "@/components/DeviceSelection/data";
import {
getTrafficDistributionDetail,
updateTrafficDistribution,
@@ -62,6 +65,14 @@ const TrafficDistributionForm: React.FC = () => {
const [current, setCurrent] = useState(0);
const [selectedAccounts, setSelectedAccounts] = useState<AccountItem[]>([]);
const [selectedDevices, setSelectedDevices] = useState<DeviceSelectionItem[]>(
[],
);
// 设备组和账号组数据
const [deviceGroups, setDeviceGroups] = useState<any[]>([]);
const [deviceGroupsOptions, setDeviceGroupsOptions] = useState<any[]>([]);
const [accountGroups, setAccountGroups] = useState<any[]>([]);
const [accountGroupsOptions, setAccountGroupsOptions] = useState<any[]>([]);
const [distributeType, setDistributeType] = useState(1);
const [maxPerDay, setMaxPerDay] = useState(50);
const [timeType, setTimeType] = useState(1);
@@ -69,11 +80,11 @@ const TrafficDistributionForm: React.FC = () => {
const [loading, setLoading] = useState(false);
const [detailLoading, setDetailLoading] = useState(false);
const [targetUserCount, setTargetUserCount] = useState(100);
const [targetTypes, setTargetTypes] = useState<string[]>([]);
const [targetScenarios, setTargetScenarios] = useState<string[]>([]);
const [selectedPools, setSelectedPools] = useState<string[]>([]);
const [poolSearch, setPoolSearch] = useState("");
const [targetSelectionTab, setTargetSelectionTab] = useState<
"device" | "account"
>("device");
// 编辑时的详情数据
const [detailData, setDetailData] =
@@ -116,7 +127,15 @@ const TrafficDistributionForm: React.FC = () => {
setMaxPerDay(config.maxPerDay);
setTimeType(config.timeType);
setSelectedAccounts(config.accountGroupsOptions);
// 设置账号组数据
setAccountGroups(config.accountGroups || []);
setAccountGroupsOptions(config.accountGroupsOptions || []);
setSelectedAccounts(config.accountGroupsOptions || []);
// 设置设备组数据
setDeviceGroups(config.deviceGroups || []);
setDeviceGroupsOptions(config.deviceGroupsOptions || []);
setSelectedDevices(config.deviceGroupsOptions || []);
// 设置时间范围 - 使用dayjs格式
if (config.timeType === 2 && config.startTime && config.endTime) {
@@ -161,8 +180,10 @@ const TrafficDistributionForm: React.FC = () => {
timeType === 2 && timeRange?.[0] ? timeRange[0].format("HH:mm") : "",
endTime:
timeType === 2 && timeRange?.[1] ? timeRange[1].format("HH:mm") : "",
devices: detailData?.config.devices || [],
account: selectedAccounts.map(acc => acc.id),
deviceGroups: deviceGroups,
deviceGroupsOptions: deviceGroupsOptions,
accountGroups: accountGroups,
accountGroupsOptions: accountGroupsOptions,
pools: selectedPools,
enabled: true,
};
@@ -261,19 +282,6 @@ const TrafficDistributionForm: React.FC = () => {
>
<Input placeholder="流量分发 20250724 1700" maxLength={30} />
</Form.Item>
<Form.Item
label="选择账号"
required
className={style.accountSelectItem}
>
<AccountSelection
selectedOptions={selectedAccounts}
onSelect={setSelectedAccounts}
placeholder="请选择账号"
showSelectedList={true}
selectedListMaxHeight={300}
/>
</Form.Item>
<Form.Item label="分配方式" name="distributeType" required>
<Radio.Group
value={distributeType}
@@ -355,37 +363,61 @@ const TrafficDistributionForm: React.FC = () => {
{current === 1 && (
<div>
<div className={style.sectionTitle}></div>
<div className={style.formBlock}>
<div className={style.formLabel}></div>
<Slider
min={1}
max={1000}
value={targetUserCount}
onChange={setTargetUserCount}
className={style.slider}
/>
<div className={style.sliderValue}>{targetUserCount} </div>
{/* Tab 切换 */}
<div className={style.tabWrapper}>
<div className={style.tabList}>
<div
className={`${style.tabItem} ${
targetSelectionTab === "device" ? style.tabActive : ""
}`}
onClick={() => setTargetSelectionTab("device")}
>
</div>
<div
className={`${style.tabItem} ${
targetSelectionTab === "account" ? style.tabActive : ""
}`}
onClick={() => setTargetSelectionTab("account")}
>
</div>
</div>
</div>
<div className={style.formBlock}>
<div className={style.formLabel}></div>
<Checkbox.Group
options={["高价值客户", "新用户", "潜在客户", "流失预警"]}
value={targetTypes}
onChange={setTargetTypes}
className={style.checkboxGroup}
/>
</div>
<div className={style.formBlock}>
<div className={style.formLabel}></div>
<Checkbox.Group
options={scenarioList.map(s => ({
label: s.label,
value: s.value,
}))}
value={targetScenarios}
onChange={setTargetScenarios}
className={style.checkboxGroup}
/>
{/* Tab 内容 */}
<div className={style.tabContent}>
{targetSelectionTab === "device" && (
<div className={style.formBlock}>
<DeviceSelection
selectedOptions={selectedDevices}
onSelect={devices => {
setSelectedDevices(devices);
setDeviceGroupsOptions(devices);
}}
placeholder="请选择设备"
showSelectedList={true}
selectedListMaxHeight={300}
deviceGroups={deviceGroups}
/>
</div>
)}
{targetSelectionTab === "account" && (
<div className={style.formBlock}>
<AccountSelection
selectedOptions={selectedAccounts}
onSelect={accounts => {
setSelectedAccounts(accounts);
setAccountGroupsOptions(accounts);
}}
placeholder="请选择客服"
showSelectedList={true}
selectedListMaxHeight={300}
accountGroups={accountGroups}
/>
</div>
)}
</div>
</div>
)}

View File

@@ -343,7 +343,7 @@ const TrafficDistributionList: React.FC = () => {
}
loading={loading}
footer={
<div className={style.pagination}>
<div className="pagination-container">
<Pagination
current={page}
pageSize={PAGE_SIZE}