feat: 基础迁移完成了

This commit is contained in:
许永平
2025-07-03 18:09:07 +08:00
parent 47ff85bafa
commit 2564e3cfac
13 changed files with 989 additions and 20 deletions

147
nkebao/src/api/devices.ts Normal file
View File

@@ -0,0 +1,147 @@
import { get, post, put, del } from './request';
import type { ApiResponse, PaginatedResponse } from '@/types/common';
import type {
Device,
DeviceStats,
DeviceTaskRecord,
QueryDeviceParams,
CreateDeviceParams,
UpdateDeviceParams,
DeviceStatus,
ServerDevice,
ServerDevicesResponse
} from '@/types/device';
const API_BASE = "/devices";
// 获取设备列表 - 连接到服务器/v1/devices接口
export const fetchDeviceList = async (page: number = 1, limit: number = 20, keyword?: string): Promise<ServerDevicesResponse> => {
const params = new URLSearchParams();
params.append('page', page.toString());
params.append('limit', limit.toString());
if (keyword) {
params.append('keyword', keyword);
}
return get<ServerDevicesResponse>(`/v1/devices?${params.toString()}`);
};
// 获取设备详情 - 连接到服务器/v1/devices/:id接口
export const fetchDeviceDetail = async (id: string | number): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/devices/${id}`);
};
// 获取设备关联的微信账号
export const fetchDeviceRelatedAccounts = async (id: string | number): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/wechats/related-device/${id}`);
};
// 获取设备操作记录
export const fetchDeviceHandleLogs = async (id: string | number, page: number = 1, limit: number = 10): Promise<ApiResponse<any>> => {
return get<ApiResponse<any>>(`/v1/devices/${id}/handle-logs?page=${page}&limit=${limit}`);
};
// 更新设备任务配置
export const updateDeviceTaskConfig = async (
config: {
deviceId: string | number;
autoAddFriend?: boolean;
autoReply?: boolean;
momentsSync?: boolean;
aiChat?: boolean;
}
): Promise<ApiResponse<any>> => {
return post<ApiResponse<any>>(`/v1/devices/task-config`, config);
};
// 删除设备
export const deleteDevice = async (id: number): Promise<ApiResponse<any>> => {
return del<ApiResponse<any>>(`/v1/devices/${id}`);
};
// 设备管理API
export const deviceApi = {
// 创建设备
async create(params: CreateDeviceParams): Promise<ApiResponse<Device>> {
return post<ApiResponse<Device>>(`${API_BASE}`, params);
},
// 更新设备
async update(params: UpdateDeviceParams): Promise<ApiResponse<Device>> {
return put<ApiResponse<Device>>(`${API_BASE}/${params.id}`, params);
},
// 获取设备详情
async getById(id: string): Promise<ApiResponse<Device>> {
return get<ApiResponse<Device>>(`${API_BASE}/${id}`);
},
// 查询设备列表
async query(params: QueryDeviceParams): Promise<ApiResponse<PaginatedResponse<Device>>> {
// 创建一个新对象用于构建URLSearchParams
const queryParams: Record<string, string> = {};
// 按需将params中的属性添加到queryParams
if (params.keyword) queryParams.keyword = params.keyword;
if (params.status) queryParams.status = params.status;
if (params.type) queryParams.type = params.type;
if (params.page) queryParams.page = params.page.toString();
if (params.pageSize) queryParams.pageSize = params.pageSize.toString();
// 特殊处理需要JSON序列化的属性
if (params.tags) queryParams.tags = JSON.stringify(params.tags);
if (params.dateRange) queryParams.dateRange = JSON.stringify(params.dateRange);
// 构建查询字符串
const queryString = new URLSearchParams(queryParams).toString();
return get<ApiResponse<PaginatedResponse<Device>>>(`${API_BASE}?${queryString}`);
},
// 删除设备
async delete(id: string): Promise<ApiResponse<void>> {
return del<ApiResponse<void>>(`${API_BASE}/${id}`);
},
// 重启设备
async restart(id: string): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/${id}/restart`);
},
// 解绑设备
async unbind(id: string): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/${id}/unbind`);
},
// 获取设备统计数据
async getStats(id: string): Promise<ApiResponse<DeviceStats>> {
return get<ApiResponse<DeviceStats>>(`${API_BASE}/${id}/stats`);
},
// 获取设备任务记录
async getTaskRecords(id: string, page = 1, pageSize = 20): Promise<ApiResponse<PaginatedResponse<DeviceTaskRecord>>> {
return get<ApiResponse<PaginatedResponse<DeviceTaskRecord>>>(`${API_BASE}/${id}/tasks?page=${page}&pageSize=${pageSize}`);
},
// 批量更新设备标签
async updateTags(ids: string[], tags: string[]): Promise<ApiResponse<void>> {
return post<ApiResponse<void>>(`${API_BASE}/tags`, { deviceIds: ids, tags });
},
// 批量导出设备数据
async exportDevices(ids: string[]): Promise<Blob> {
const response = await fetch(`${process.env.REACT_APP_API_BASE || 'http://localhost:3000/api'}${API_BASE}/export`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ deviceIds: ids }),
});
return response.blob();
},
// 检查设备在线状态
async checkStatus(ids: string[]): Promise<ApiResponse<Record<string, DeviceStatus>>> {
return post<ApiResponse<Record<string, DeviceStatus>>>(`${API_BASE}/status`, { deviceIds: ids });
},
};

61
nkebao/src/api/request.ts Normal file
View File

@@ -0,0 +1,61 @@
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
// 创建axios实例
const request: AxiosInstance = axios.create({
baseURL: process.env.REACT_APP_API_BASE || 'http://localhost:3000/api',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
request.interceptors.request.use(
(config) => {
// 可以在这里添加token等认证信息
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response: AxiosResponse) => {
return response.data;
},
(error) => {
// 统一错误处理
console.error('API请求错误:', error);
return Promise.reject(error);
}
);
// 封装GET请求
export const get = <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.get(url, config);
};
// 封装POST请求
export const post = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.post(url, data, config);
};
// 封装PUT请求
export const put = <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.put(url, data, config);
};
// 封装DELETE请求
export const del = <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.delete(url, config);
};
// 导出request实例
export { request };
export default request;

120
nkebao/src/api/scenarios.ts Normal file
View File

@@ -0,0 +1,120 @@
import { get } from './request';
import type { ApiResponse } from '@/types/common';
// 服务器返回的场景数据类型
export interface SceneItem {
id: number;
name: string;
image: string;
status: number;
createTime: number;
updateTime: number | null;
deleteTime: number | null;
}
// 服务器返回的场景列表响应类型
export interface ScenesResponse {
code: number;
msg: string;
data: SceneItem[];
}
// 前端使用的场景数据类型
export interface Channel {
id: string;
name: string;
icon: string;
stats: {
daily: number;
growth: number;
};
link?: string;
plans?: Plan[];
}
// 计划类型
export interface Plan {
id: string;
name: string;
isNew?: boolean;
status: "active" | "paused" | "completed";
acquisitionCount: number;
}
/**
* 获取获客场景列表
*
* @param params 查询参数
* @returns 获客场景列表
*/
export const fetchScenes = async (params: {
page?: number;
limit?: number;
keyword?: string;
} = {}): Promise<ScenesResponse> => {
const { page = 1, limit = 10, keyword = "" } = params;
const queryParams = new URLSearchParams();
queryParams.append("page", String(page));
queryParams.append("limit", String(limit));
if (keyword) {
queryParams.append("keyword", keyword);
}
try {
return await get<ScenesResponse>(`/v1/plan/scenes?${queryParams.toString()}`);
} catch (error) {
console.error("Error fetching scenes:", error);
// 返回一个错误响应
return {
code: 500,
msg: "获取场景列表失败",
data: []
};
}
};
/**
* 将服务器返回的场景数据转换为前端展示需要的格式
*
* @param item 服务器返回的场景数据
* @returns 前端展示的场景数据
*/
export const transformSceneItem = (item: SceneItem): Channel => {
// 为每个场景生成随机的"今日"数据和"增长百分比"
const dailyCount = Math.floor(Math.random() * 100);
const growthPercent = Math.floor(Math.random() * 40) - 10; // -10% 到 30% 的随机值
// 默认图标(如果服务器没有返回)
const defaultIcon = "/assets/icons/poster-icon.svg";
return {
id: String(item.id),
name: item.name,
icon: item.image || defaultIcon,
stats: {
daily: dailyCount,
growth: growthPercent
}
};
};
/**
* 获取场景详情
*
* @param id 场景ID
* @returns 场景详情
*/
export const fetchSceneDetail = async (id: string | number): Promise<ApiResponse<SceneItem>> => {
try {
return await get<ApiResponse<SceneItem>>(`/v1/plan/scenes/${id}`);
} catch (error) {
console.error("Error fetching scene detail:", error);
return {
code: 500,
msg: "获取场景详情失败",
data: null
};
}
};

View File

@@ -0,0 +1,219 @@
import { get, post, put } from './request';
import type { ApiResponse } from '@/types/common';
// 添加接口返回数据类型定义
interface WechatAccountSummary {
accountAge: string;
activityLevel: {
allTimes: number;
dayTimes: number;
};
accountWeight: {
scope: number;
ageWeight: number;
activityWeigth: number;
restrictWeight: number;
realNameWeight: number;
};
statistics: {
todayAdded: number;
addLimit: number;
};
restrictions: {
id: number;
level: string;
reason: string;
date: string;
}[];
}
interface WechatAccountSummaryResponse {
code: number;
msg: string;
data: WechatAccountSummary;
}
interface ServerWechatAccountsResponse {
code: number;
msg: string;
data: {
list: any[];
total: number;
page: number;
limit: number;
};
}
interface QueryWechatAccountParams {
page?: number;
limit?: number;
keyword?: string;
sort?: string;
order?: string;
}
/**
* 获取微信账号列表
* @param params 查询参数
* @returns 微信账号列表响应
*/
export const fetchWechatAccountList = async (params: QueryWechatAccountParams = {}): Promise<ServerWechatAccountsResponse> => {
const queryParams = new URLSearchParams();
// 添加查询参数
if (params.page) queryParams.append('page', params.page.toString());
if (params.limit) queryParams.append('limit', params.limit.toString());
if (params.keyword) queryParams.append('nickname', params.keyword); // 使用nickname作为关键词搜索参数
if (params.sort) queryParams.append('sort', params.sort);
if (params.order) queryParams.append('order', params.order);
// 发起API请求
return get<ServerWechatAccountsResponse>(`/v1/wechats?${queryParams.toString()}`);
};
/**
* 刷新微信账号状态
* @returns 刷新结果
*/
export const refreshWechatAccounts = async (): Promise<{ code: number; msg: string; data: any }> => {
return put<{ code: number; msg: string; data: any }>('/v1/wechats/refresh', {});
};
/**
* 执行微信好友转移
* @param sourceId 源微信账号ID
* @param targetId 目标微信账号ID
* @returns 转移结果
*/
export const transferWechatFriends = async (sourceId: string | number, targetId: string | number): Promise<{ code: number; msg: string; data: any }> => {
return post<{ code: number; msg: string; data: any }>('/v1/wechats/transfer-friends', {
source_id: sourceId,
target_id: targetId
});
};
/**
* 将服务器返回的微信账号数据转换为前端使用的格式
* @param serverAccount 服务器返回的微信账号数据
* @returns 前端使用的微信账号数据
*/
export const transformWechatAccount = (serverAccount: any): any => {
// 从deviceInfo中提取设备信息
let deviceId = '';
let deviceName = '';
if (serverAccount.deviceInfo) {
// 尝试解析设备信息字符串
const deviceInfo = serverAccount.deviceInfo.split(' ');
if (deviceInfo.length > 0) {
// 提取数字部分作为设备ID确保是整数
const possibleId = deviceInfo[0].trim();
// 验证是否为数字
deviceId = /^\d+$/.test(possibleId) ? possibleId : '';
// 提取设备名称
if (deviceInfo.length > 1) {
deviceName = deviceInfo[1] ? deviceInfo[1].replace(/[()]/g, '').trim() : '';
}
}
}
// 如果从deviceInfo无法获取有效的设备ID使用imei作为备选
if (!deviceId && serverAccount.imei) {
deviceId = serverAccount.imei;
}
// 如果仍然没有设备ID使用微信账号的ID作为最后的备选
if (!deviceId && serverAccount.id) {
deviceId = serverAccount.id.toString();
}
// 如果没有设备名称,使用备用名称
if (!deviceName) {
deviceName = serverAccount.deviceMemo || '未命名设备';
}
// 假设每天最多可添加20个好友
const maxDailyAdds = 20;
const todayAdded = serverAccount.todayNewFriendCount || 0;
return {
id: serverAccount.id.toString(),
avatar: serverAccount.avatar || '',
nickname: serverAccount.nickname || serverAccount.accountNickname || '未命名',
wechatId: serverAccount.wechatId || '',
deviceId,
deviceName,
friendCount: serverAccount.totalFriend || 0,
todayAdded,
remainingAdds: serverAccount.canAddFriendCount || (maxDailyAdds - todayAdded),
maxDailyAdds,
status: serverAccount.wechatAlive === 1 ? "normal" : "abnormal" as "normal" | "abnormal",
lastActive: new Date().toLocaleString() // 服务端未提供,使用当前时间
};
};
/**
* 获取微信好友列表
* @param wechatId 微信账号ID
* @param page 页码
* @param pageSize 每页数量
* @param searchQuery 搜索关键词
* @returns 好友列表数据
*/
export const fetchWechatFriends = async (wechatId: string, page: number = 1, pageSize: number = 20, searchQuery: string = '') => {
try {
return get(`/v1/wechats/${wechatId}/friends?page=${page}&limit=${pageSize}${searchQuery ? `&search=${searchQuery}` : ''}`);
} catch (error) {
console.error("获取好友列表失败:", error);
throw error;
}
};
/**
* 获取微信账号概览信息
* @param id 微信账号ID
* @returns 微信账号概览信息
*/
export const fetchWechatAccountSummary = async (wechatIdid: string): Promise<WechatAccountSummaryResponse> => {
try {
return get<WechatAccountSummaryResponse>(`/v1/wechats/${wechatIdid}/summary`);
} catch (error) {
console.error("获取账号概览失败:", error);
throw error;
}
};
/**
* 获取好友详情信息
* @param wechatId 微信账号ID
* @param friendId 好友ID
* @returns 好友详情信息
*/
export interface WechatFriendDetail {
id: number;
avatar: string;
nickname: string;
region: string;
wechatId: string;
addDate: string;
tags: string[];
playDate: string;
memo: string;
source: string;
}
interface WechatFriendDetailResponse {
code: number;
msg: string;
data: WechatFriendDetail;
}
export const fetchWechatFriendDetail = async (wechatId: string): Promise<WechatFriendDetailResponse> => {
try {
return get<WechatFriendDetailResponse>(`/v1/wechats/${wechatId}`);
} catch (error) {
console.error("获取好友详情失败:", error);
throw error;
}
};