FEAT => 本次更新项目为:
This commit is contained in:
4
Cunkebao/dist/.vite/manifest.json
vendored
4
Cunkebao/dist/.vite/manifest.json
vendored
@@ -33,7 +33,7 @@
|
|||||||
"name": "vendor"
|
"name": "vendor"
|
||||||
},
|
},
|
||||||
"index.html": {
|
"index.html": {
|
||||||
"file": "assets/index-Cp05akVy.js",
|
"file": "assets/index-AbKWTcUz.js",
|
||||||
"name": "index",
|
"name": "index",
|
||||||
"src": "index.html",
|
"src": "index.html",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
"_charts-D0fT04H8.js"
|
"_charts-D0fT04H8.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"assets/index-Eg_DAu9e.css"
|
"assets/index-V1Q-fxX3.css"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
4
Cunkebao/dist/index.html
vendored
4
Cunkebao/dist/index.html
vendored
@@ -11,13 +11,13 @@
|
|||||||
</style>
|
</style>
|
||||||
<!-- 引入 uni-app web-view SDK(必须) -->
|
<!-- 引入 uni-app web-view SDK(必须) -->
|
||||||
<script type="text/javascript" src="/websdk.js"></script>
|
<script type="text/javascript" src="/websdk.js"></script>
|
||||||
<script type="module" crossorigin src="/assets/index-Cp05akVy.js"></script>
|
<script type="module" crossorigin src="/assets/index-AbKWTcUz.js"></script>
|
||||||
<link rel="modulepreload" crossorigin href="/assets/vendor-2vc8h_ct.js">
|
<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/ui-qLeQLv1F.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/utils-6WF66_dS.js">
|
<link rel="modulepreload" crossorigin href="/assets/utils-6WF66_dS.js">
|
||||||
<link rel="modulepreload" crossorigin href="/assets/charts-D0fT04H8.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/ui-D0C0OGrH.css">
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-Eg_DAu9e.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-V1Q-fxX3.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -87,18 +87,14 @@ const FriendRequestSettings: React.FC<FriendRequestSettingsProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className={styles["friend-container"]}>
|
<div className={styles["friend-container"]}>
|
||||||
{/* 选择设备区块 */}
|
{/* 选择设备区块 */}
|
||||||
{![7].includes(formData.scenario) && (
|
<div className={styles["friend-label"]}>选择设备</div>
|
||||||
<>
|
<div className={styles["friend-block"]}>
|
||||||
<div className={styles["friend-label"]}>选择设备</div>
|
<DeviceSelection
|
||||||
<div className={styles["friend-block"]}>
|
selectedOptions={formData.deveiceGroupsOptions}
|
||||||
<DeviceSelection
|
onSelect={handleDevicesChange}
|
||||||
selectedOptions={formData.deveiceGroupsOptions}
|
placeholder="选择设备"
|
||||||
onSelect={handleDevicesChange}
|
/>
|
||||||
placeholder="选择设备"
|
</div>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 好友备注区块 */}
|
{/* 好友备注区块 */}
|
||||||
<div className={styles["friend-label"]}>好友备注</div>
|
<div className={styles["friend-label"]}>好友备注</div>
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Popup, Avatar } from "antd-mobile";
|
||||||
|
import { Button } from "antd";
|
||||||
|
import { CloseOutlined } from "@ant-design/icons";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
|
||||||
|
interface AccountItem {
|
||||||
|
id: string | number;
|
||||||
|
nickname?: string;
|
||||||
|
wechatId?: string;
|
||||||
|
avatar?: string;
|
||||||
|
status?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AccountListModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
accounts: AccountItem[];
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccountListModal: React.FC<AccountListModalProps> = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
accounts,
|
||||||
|
title = "分发账号列表",
|
||||||
|
}) => {
|
||||||
|
const getStatusColor = (status?: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case "normal":
|
||||||
|
return "#52c41a";
|
||||||
|
case "limited":
|
||||||
|
return "#faad14";
|
||||||
|
case "blocked":
|
||||||
|
return "#ff4d4f";
|
||||||
|
default:
|
||||||
|
return "#d9d9d9";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = (status?: string) => {
|
||||||
|
switch (status) {
|
||||||
|
case "normal":
|
||||||
|
return "正常";
|
||||||
|
case "limited":
|
||||||
|
return "受限";
|
||||||
|
case "blocked":
|
||||||
|
return "封禁";
|
||||||
|
default:
|
||||||
|
return "未知";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popup
|
||||||
|
visible={visible}
|
||||||
|
onMaskClick={onClose}
|
||||||
|
position="bottom"
|
||||||
|
bodyStyle={{
|
||||||
|
height: "70vh",
|
||||||
|
borderTopLeftRadius: 16,
|
||||||
|
borderTopRightRadius: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={style.accountModal}>
|
||||||
|
{/* 头部 */}
|
||||||
|
<div className={style.accountModalHeader}>
|
||||||
|
<h3 className={style.accountModalTitle}>{title}</h3>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<CloseOutlined />}
|
||||||
|
onClick={onClose}
|
||||||
|
className={style.accountModalClose}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 账号列表 */}
|
||||||
|
<div className={style.accountList}>
|
||||||
|
{accounts.length > 0 ? (
|
||||||
|
accounts.map((account, index) => (
|
||||||
|
<div key={account.id || index} className={style.accountItem}>
|
||||||
|
<div className={style.accountAvatar}>
|
||||||
|
<Avatar src={account.avatar} style={{ "--size": "48px" }}>
|
||||||
|
{(account.nickname || account.wechatId || "账号")[0]}
|
||||||
|
</Avatar>
|
||||||
|
</div>
|
||||||
|
<div className={style.accountInfo}>
|
||||||
|
<div className={style.accountName}>
|
||||||
|
{account.nickname ||
|
||||||
|
account.wechatId ||
|
||||||
|
`账号${account.id}`}
|
||||||
|
</div>
|
||||||
|
<div className={style.accountWechatId}>
|
||||||
|
{account.wechatId || "未绑定微信号"}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={style.accountStatus}>
|
||||||
|
<span
|
||||||
|
className={style.statusDot}
|
||||||
|
style={{ backgroundColor: getStatusColor(account.status) }}
|
||||||
|
/>
|
||||||
|
<span className={style.statusText}>
|
||||||
|
{getStatusText(account.status)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className={style.accountEmpty}>
|
||||||
|
<div className={style.accountEmptyText}>暂无账号数据</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部统计 */}
|
||||||
|
<div className={style.accountModalFooter}>
|
||||||
|
<div className={style.accountStats}>
|
||||||
|
<span>共 {accounts.length} 个账号</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AccountListModal;
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Popup, Avatar } from "antd-mobile";
|
||||||
|
import { Button } from "antd";
|
||||||
|
import { CloseOutlined } from "@ant-design/icons";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
|
||||||
|
interface DeviceItem {
|
||||||
|
id: string | number;
|
||||||
|
memo?: string;
|
||||||
|
imei?: string;
|
||||||
|
wechatId?: string;
|
||||||
|
status?: "online" | "offline";
|
||||||
|
avatar?: string;
|
||||||
|
totalFriend?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DeviceListModalProps {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
devices: DeviceItem[];
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeviceListModal: React.FC<DeviceListModalProps> = ({
|
||||||
|
visible,
|
||||||
|
onClose,
|
||||||
|
devices,
|
||||||
|
title = "分发设备列表",
|
||||||
|
}) => {
|
||||||
|
const getStatusColor = (status?: string) => {
|
||||||
|
return status === "online" ? "#52c41a" : "#ff4d4f";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = (status?: string) => {
|
||||||
|
return status === "online" ? "在线" : "离线";
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popup
|
||||||
|
visible={visible}
|
||||||
|
onMaskClick={onClose}
|
||||||
|
position="bottom"
|
||||||
|
bodyStyle={{
|
||||||
|
height: "70vh",
|
||||||
|
borderTopLeftRadius: 16,
|
||||||
|
borderTopRightRadius: 16,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={style.deviceModal}>
|
||||||
|
{/* 头部 */}
|
||||||
|
<div className={style.deviceModalHeader}>
|
||||||
|
<h3 className={style.deviceModalTitle}>{title}</h3>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<CloseOutlined />}
|
||||||
|
onClick={onClose}
|
||||||
|
className={style.deviceModalClose}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 设备列表 */}
|
||||||
|
<div className={style.deviceList}>
|
||||||
|
{devices.length > 0 ? (
|
||||||
|
devices.map((device, index) => (
|
||||||
|
<div key={device.id || index} className={style.deviceItem}>
|
||||||
|
{/* 顶部行:IMEI */}
|
||||||
|
<div className={style.deviceHeaderRow}>
|
||||||
|
<span className={style.deviceImeiText}>
|
||||||
|
IMEI: {device.imei?.toUpperCase() || "-"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 主要内容区域:头像和详细信息 */}
|
||||||
|
<div className={style.deviceMainContent}>
|
||||||
|
{/* 头像 */}
|
||||||
|
<div className={style.deviceAvatar}>
|
||||||
|
{device.avatar ? (
|
||||||
|
<img src={device.avatar} alt="头像" />
|
||||||
|
) : (
|
||||||
|
<span className={style.deviceAvatarText}>
|
||||||
|
{(device.memo || device.wechatId || "设")[0]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 设备信息 */}
|
||||||
|
<div className={style.deviceInfo}>
|
||||||
|
<div className={style.deviceInfoHeader}>
|
||||||
|
<h3 className={style.deviceName}>
|
||||||
|
{device.memo || "未命名设备"}
|
||||||
|
</h3>
|
||||||
|
<span
|
||||||
|
className={`${style.deviceStatusBadge} ${
|
||||||
|
device.status === "online"
|
||||||
|
? style.deviceStatusOnline
|
||||||
|
: style.deviceStatusOffline
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{getStatusText(device.status)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={style.deviceInfoList}>
|
||||||
|
<div className={style.deviceInfoItem}>
|
||||||
|
<span className={style.deviceInfoLabel}>微信号:</span>
|
||||||
|
<span className={style.deviceInfoValue}>
|
||||||
|
{device.wechatId || "未绑定"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className={style.deviceInfoItem}>
|
||||||
|
<span className={style.deviceInfoLabel}>好友数:</span>
|
||||||
|
<span
|
||||||
|
className={`${style.deviceInfoValue} ${style.deviceFriendCount}`}
|
||||||
|
>
|
||||||
|
{device.totalFriend ?? "-"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className={style.deviceEmpty}>
|
||||||
|
<div className={style.deviceEmptyText}>暂无设备数据</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 底部统计 */}
|
||||||
|
<div className={style.deviceModalFooter}>
|
||||||
|
<div className={style.deviceStats}>
|
||||||
|
<span>共 {devices.length} 个设备</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popup>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeviceListModal;
|
||||||
@@ -69,10 +69,15 @@
|
|||||||
.ruleMetaItem {
|
.ruleMetaItem {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
}
|
}
|
||||||
.ruleMetaItem:not(:last-child) {
|
.ruleMetaItem:not(:last-child) {
|
||||||
border-right: 1px solid #f0f0f0;
|
border-right: 1px solid #f0f0f0;
|
||||||
}
|
}
|
||||||
|
.ruleMetaItem:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
.ruleDivider {
|
.ruleDivider {
|
||||||
border-top: 1px solid #f0f0f0;
|
border-top: 1px solid #f0f0f0;
|
||||||
@@ -124,3 +129,313 @@
|
|||||||
padding: 16px 0;
|
padding: 16px 0;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 账号列表弹窗样式
|
||||||
|
.accountModal {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountModalHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountModalTitle {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountModalClose {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: #888;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountList {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountItem:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountAvatar {
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountInfo {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountName {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #222;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountWechatId {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountStatus {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusDot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusText {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountEmpty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 200px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountEmptyText {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountModalFooter {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountStats {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设备列表弹窗样式
|
||||||
|
.deviceModal {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceModalHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceModalTitle {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceModalClose {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
color: #888;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceList {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceItem {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceItem:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceHeaderRow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceImeiText {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #888;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceMainContent {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceAvatar {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceAvatar img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceAvatarText {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfo {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfoHeader {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceName {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #222;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex: 1;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceStatusBadge {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceStatusOnline {
|
||||||
|
background: rgba(82, 196, 26, 0.1);
|
||||||
|
color: #52c41a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceStatusOffline {
|
||||||
|
background: rgba(255, 77, 79, 0.1);
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfoList {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfoItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfoLabel {
|
||||||
|
color: #888;
|
||||||
|
margin-right: 6px;
|
||||||
|
min-width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceInfoValue {
|
||||||
|
color: #444;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceFriendCount {
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceEmpty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 200px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceEmptyText {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceModalFooter {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.deviceStats {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import {
|
|||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import style from "./index.module.scss";
|
import style from "./index.module.scss";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import AccountListModal from "./AccountListModal";
|
||||||
|
import DeviceListModal from "./DeviceListModal";
|
||||||
|
|
||||||
const PAGE_SIZE = 10;
|
const PAGE_SIZE = 10;
|
||||||
|
|
||||||
@@ -51,6 +53,14 @@ const TrafficDistributionList: React.FC = () => {
|
|||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
// 优化:用menuLoadingId标记当前操作的item
|
// 优化:用menuLoadingId标记当前操作的item
|
||||||
const [menuLoadingId, setMenuLoadingId] = useState<number | null>(null);
|
const [menuLoadingId, setMenuLoadingId] = useState<number | null>(null);
|
||||||
|
// 账号列表弹窗
|
||||||
|
const [accountModalVisible, setAccountModalVisible] = useState(false);
|
||||||
|
const [currentAccounts, setCurrentAccounts] = useState<any[]>([]);
|
||||||
|
const [currentRuleName, setCurrentRuleName] = useState("");
|
||||||
|
// 设备列表弹窗
|
||||||
|
const [deviceModalVisible, setDeviceModalVisible] = useState(false);
|
||||||
|
const [currentDevices, setCurrentDevices] = useState<any[]>([]);
|
||||||
|
const [currentDeviceRuleName, setCurrentDeviceRuleName] = useState("");
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -128,6 +138,44 @@ const TrafficDistributionList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 显示账号列表弹窗
|
||||||
|
const showAccountList = (item: DistributionRule) => {
|
||||||
|
// 这里需要根据实际的账号数据结构来转换
|
||||||
|
// 假设 item.config.account 是账号ID数组,需要转换为账号对象数组
|
||||||
|
const accounts = (item.config?.account || []).map(
|
||||||
|
(accountId: string | number) => ({
|
||||||
|
id: accountId,
|
||||||
|
nickname: `账号${accountId}`,
|
||||||
|
wechatId: `wx_${accountId}`,
|
||||||
|
avatar: "",
|
||||||
|
status: "normal",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
setCurrentAccounts(accounts);
|
||||||
|
setCurrentRuleName(item.name);
|
||||||
|
setAccountModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 显示设备列表弹窗
|
||||||
|
const showDeviceList = (item: DistributionRule) => {
|
||||||
|
// 这里需要根据实际的设备数据结构来转换
|
||||||
|
// 假设 item.config.devices 是设备ID数组,需要转换为设备对象数组
|
||||||
|
const devices = (item.config?.devices || []).map((deviceId: string) => ({
|
||||||
|
id: deviceId,
|
||||||
|
memo: `设备${deviceId}`,
|
||||||
|
imei: `IMEI${deviceId}`,
|
||||||
|
wechatId: `wx_${deviceId}`,
|
||||||
|
status: "online" as const,
|
||||||
|
avatar: "",
|
||||||
|
totalFriend: Math.floor(Math.random() * 1000) + 100,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setCurrentDevices(devices);
|
||||||
|
setCurrentDeviceRuleName(item.name);
|
||||||
|
setDeviceModalVisible(true);
|
||||||
|
};
|
||||||
|
|
||||||
const renderCard = (item: DistributionRule) => {
|
const renderCard = (item: DistributionRule) => {
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu onClick={({ key }) => handleMenuClick(key, item)}>
|
<Menu onClick={({ key }) => handleMenuClick(key, item)}>
|
||||||
@@ -213,13 +261,21 @@ const TrafficDistributionList: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.ruleMeta}>
|
<div className={style.ruleMeta}>
|
||||||
<div className={style.ruleMetaItem}>
|
<div
|
||||||
|
className={style.ruleMetaItem}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
onClick={() => showAccountList(item)}
|
||||||
|
>
|
||||||
<div style={{ fontSize: 18, fontWeight: 600 }}>
|
<div style={{ fontSize: 18, fontWeight: 600 }}>
|
||||||
{item.config?.account?.length || 0}
|
{item.config?.account?.length || 0}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: 13, color: "#888" }}>分发账号</div>
|
<div style={{ fontSize: 13, color: "#888" }}>分发账号</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={style.ruleMetaItem}>
|
<div
|
||||||
|
className={style.ruleMetaItem}
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
onClick={() => showDeviceList(item)}
|
||||||
|
>
|
||||||
<div style={{ fontSize: 18, fontWeight: 600 }}>
|
<div style={{ fontSize: 18, fontWeight: 600 }}>
|
||||||
{item.config?.devices?.length || 0}
|
{item.config?.devices?.length || 0}
|
||||||
</div>
|
</div>
|
||||||
@@ -325,6 +381,22 @@ const TrafficDistributionList: React.FC = () => {
|
|||||||
<div className={style.empty}>暂无数据</div>
|
<div className={style.empty}>暂无数据</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 账号列表弹窗 */}
|
||||||
|
<AccountListModal
|
||||||
|
visible={accountModalVisible}
|
||||||
|
onClose={() => setAccountModalVisible(false)}
|
||||||
|
accounts={currentAccounts}
|
||||||
|
title={`${currentRuleName} - 分发账号列表`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 设备列表弹窗 */}
|
||||||
|
<DeviceListModal
|
||||||
|
visible={deviceModalVisible}
|
||||||
|
onClose={() => setDeviceModalVisible(false)}
|
||||||
|
devices={currentDevices}
|
||||||
|
title={`${currentDeviceRuleName} - 分发设备列表`}
|
||||||
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user