feat: 本次提交更新内容如下

场景获客列表搞定
This commit is contained in:
笔记本里的永平
2025-07-07 17:08:27 +08:00
parent 6543da9167
commit 5ff15472f5
352 changed files with 24040 additions and 18575 deletions

View File

@@ -1,69 +1,222 @@
// API请求工具函数
import { toast } from "@/components/ui/use-toast"
/**
* 认证相关API接口 - 基于存客宝接口文档
*/
import { apiClient, type ApiResponse } from "./client"
import { API_ENDPOINTS, STORAGE_KEYS } from "./config"
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "https://api.example.com"
// 登录请求接口
export interface LoginRequest {
username: string
password: string
captcha?: string
captchaId?: string
}
// 带有认证的请求函数
export async function authFetch(url: string, options: RequestInit = {}) {
const token = localStorage.getItem("token")
// 登录响应接口
export interface LoginResponse {
token: string
refreshToken: string
user: UserInfo
expiresIn: number
}
// 合并headers
let headers = { ...options.headers }
// 用户信息接口
export interface UserInfo {
id: string
username: string
nickname: string
avatar?: string
role: string
permissions: string[]
createdAt: string
updatedAt: string
}
// 如果有token添加到请求头
if (token) {
headers = {
...headers,
Token: `${token}`,
// 刷新Token响应接口
export interface RefreshTokenResponse {
token: string
expiresIn: number
}
// 验证码响应接口
export interface CaptchaResponse {
captchaId: string
captchaImage: string // base64图片
}
/**
* 认证API类
*/
class AuthApi {
/**
* 用户登录
*/
async login(data: LoginRequest): Promise<ApiResponse<LoginResponse>> {
const response = await apiClient.post<LoginResponse>(API_ENDPOINTS.AUTH.LOGIN, data)
// 登录成功后保存用户信息
if (response.code === 0 && response.data) {
this.saveUserSession(response.data)
}
return response
}
/**
* 用户登出
*/
async logout(): Promise<ApiResponse<void>> {
const response = await apiClient.post<void>(API_ENDPOINTS.AUTH.LOGOUT)
// 清除本地存储的用户信息
this.clearUserSession()
return response
}
/**
* 刷新Token
*/
async refreshToken(): Promise<ApiResponse<RefreshTokenResponse>> {
const refreshToken = this.getRefreshToken()
if (!refreshToken) {
throw new Error("没有刷新令牌")
}
const response = await apiClient.post<RefreshTokenResponse>(API_ENDPOINTS.AUTH.REFRESH, {
refreshToken,
})
// 更新Token
if (response.code === 0 && response.data) {
this.updateToken(response.data.token)
}
return response
}
/**
* 获取用户信息
*/
async getUserInfo(): Promise<ApiResponse<UserInfo>> {
return apiClient.get<UserInfo>(API_ENDPOINTS.AUTH.USER_INFO)
}
/**
* 获取验证码
*/
async getCaptcha(): Promise<ApiResponse<CaptchaResponse>> {
return apiClient.get<CaptchaResponse>(API_ENDPOINTS.AUTH.CAPTCHA)
}
/**
* 修改密码
*/
async changePassword(data: {
oldPassword: string
newPassword: string
}): Promise<ApiResponse<void>> {
return apiClient.post<void>(API_ENDPOINTS.AUTH.CHANGE_PASSWORD, data)
}
/**
* 发送短信验证码
*/
async sendSmsCode(phone: string): Promise<ApiResponse<void>> {
return apiClient.post<void>(API_ENDPOINTS.AUTH.SEND_CODE, { phone })
}
/**
* 更新用户资料
*/
async updateProfile(data: Partial<UserInfo>): Promise<ApiResponse<UserInfo>> {
return apiClient.put<UserInfo>(API_ENDPOINTS.AUTH.UPDATE_PROFILE, data)
}
// 本地存储相关方法
/**
* 保存用户会话信息
*/
private saveUserSession(loginData: LoginResponse): void {
if (typeof window === "undefined") return
localStorage.setItem(STORAGE_KEYS.TOKEN, loginData.token)
localStorage.setItem(STORAGE_KEYS.REFRESH_TOKEN, loginData.refreshToken)
localStorage.setItem(STORAGE_KEYS.USER, JSON.stringify(loginData.user))
localStorage.setItem(STORAGE_KEYS.LAST_LOGIN_TIME, Date.now().toString())
}
/**
* 清除用户会话信息
*/
private clearUserSession(): void {
if (typeof window === "undefined") return
localStorage.removeItem(STORAGE_KEYS.TOKEN)
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN)
localStorage.removeItem(STORAGE_KEYS.USER)
localStorage.removeItem(STORAGE_KEYS.LAST_LOGIN_TIME)
}
/**
* 更新Token
*/
private updateToken(token: string): void {
if (typeof window === "undefined") return
localStorage.setItem(STORAGE_KEYS.TOKEN, token)
}
/**
* 获取刷新Token
*/
private getRefreshToken(): string | null {
if (typeof window === "undefined") return null
return localStorage.getItem(STORAGE_KEYS.REFRESH_TOKEN)
}
/**
* 获取当前用户信息
*/
getCurrentUser(): UserInfo | null {
if (typeof window === "undefined") return null
const userStr = localStorage.getItem(STORAGE_KEYS.USER)
if (!userStr) return null
try {
return JSON.parse(userStr)
} catch {
return null
}
}
try {
const response = await fetch(`${API_BASE_URL}${url}`, {
...options,
headers,
})
/**
* 检查是否已登录
*/
isLoggedIn(): boolean {
if (typeof window === "undefined") return false
const data = await response.json()
const token = localStorage.getItem(STORAGE_KEYS.TOKEN)
const user = this.getCurrentUser()
// 检查token是否过期仅当有token时
if (token && (data.code === 401 || data.code === 403)) {
// 清除token
localStorage.removeItem("token")
return !!(token && user)
}
// 暂时不重定向到登录页
// if (typeof window !== "undefined") {
// window.location.href = "/login"
// }
/**
* 检查Token是否过期
*/
isTokenExpired(): boolean {
if (typeof window === "undefined") return true
console.warn("登录已过期")
}
const lastLoginTime = localStorage.getItem(STORAGE_KEYS.LAST_LOGIN_TIME)
if (!lastLoginTime) return true
return data
} catch (error) {
console.error("API请求错误:", error)
toast({
variant: "destructive",
title: "请求失败",
description: error instanceof Error ? error.message : "网络错误,请稍后重试",
})
throw error
}
}
// 不需要认证的请求函数
export async function publicFetch(url: string, options: RequestInit = {}) {
try {
const response = await fetch(`${API_BASE_URL}${url}`, options)
return await response.json()
} catch (error) {
console.error("API请求错误:", error)
toast({
variant: "destructive",
title: "请求失败",
description: error instanceof Error ? error.message : "网络错误,请稍后重试",
})
throw error
// 假设Token有效期为24小时
const tokenExpireTime = Number.parseInt(lastLoginTime) + 24 * 60 * 60 * 1000
return Date.now() > tokenExpireTime
}
}
// 导出单例实例
export const authApi = new AuthApi()

244
Cunkebao/lib/api/client.ts Normal file
View File

@@ -0,0 +1,244 @@
/**
* API客户端 - 基于存客宝接口标准
*/
import { API_CONFIG, STORAGE_KEYS } from "./config"
// 基础响应接口
export interface ApiResponse<T = any> {
code: number
message: string
data?: T
timestamp?: number
}
// 分页参数接口
export interface PaginationParams {
page: number
pageSize: number
}
// 分页响应接口
export interface PaginatedResponse<T> {
items: T[]
total: number
page: number
pageSize: number
totalPages: number
}
// 请求配置接口
interface RequestConfig {
headers?: Record<string, string>
timeout?: number
retries?: number
}
/**
* API客户端类
*/
class ApiClient {
private baseURL: string
private timeout: number
private retryCount: number
constructor() {
this.baseURL = API_CONFIG.BASE_URL
this.timeout = API_CONFIG.TIMEOUT
this.retryCount = API_CONFIG.RETRY_COUNT
}
/**
* 获取认证头
*/
private getAuthHeaders(): Record<string, string> {
const token = this.getToken()
return token ? { Authorization: `Bearer ${token}` } : {}
}
/**
* 获取存储的Token
*/
private getToken(): string | null {
if (typeof window === "undefined") return null
return localStorage.getItem(STORAGE_KEYS.TOKEN)
}
/**
* 设置Token
*/
private setToken(token: string): void {
if (typeof window === "undefined") return
localStorage.setItem(STORAGE_KEYS.TOKEN, token)
}
/**
* 清除Token
*/
private clearToken(): void {
if (typeof window === "undefined") return
localStorage.removeItem(STORAGE_KEYS.TOKEN)
localStorage.removeItem(STORAGE_KEYS.REFRESH_TOKEN)
localStorage.removeItem(STORAGE_KEYS.USER)
}
/**
* 处理响应
*/
private async handleResponse<T>(response: Response): Promise<ApiResponse<T>> {
const contentType = response.headers.get("content-type")
let data: any
if (contentType && contentType.includes("application/json")) {
data = await response.json()
} else {
data = await response.text()
}
// 如果响应不是标准格式,包装成标准格式
if (typeof data !== "object" || !("code" in data)) {
data = {
code: response.ok ? API_CONFIG.ERROR_CODES.SUCCESS : response.status,
message: response.ok ? "请求成功" : response.statusText,
data: response.ok ? data : null,
}
}
// 处理认证失败
if (data.code === API_CONFIG.ERROR_CODES.UNAUTHORIZED) {
this.clearToken()
// 可以在这里触发重新登录逻辑
if (typeof window !== "undefined") {
window.location.href = "/login"
}
}
return data
}
/**
* 发送请求
*/
private async request<T>(
method: string,
url: string,
data?: any,
config: RequestConfig = {},
): Promise<ApiResponse<T>> {
const fullUrl = url.startsWith("http") ? url : `${this.baseURL}${url}`
const headers: Record<string, string> = {
"Content-Type": "application/json",
...this.getAuthHeaders(),
...config.headers,
}
const requestConfig: RequestInit = {
method,
headers,
signal: AbortSignal.timeout(config.timeout || this.timeout),
}
if (data && (method === "POST" || method === "PUT" || method === "PATCH")) {
requestConfig.body = JSON.stringify(data)
}
let lastError: Error
const maxRetries = config.retries ?? this.retryCount
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(fullUrl, requestConfig)
return await this.handleResponse<T>(response)
} catch (error) {
lastError = error as Error
// 如果是最后一次尝试,或者是认证错误,不重试
if (attempt === maxRetries || error instanceof TypeError) {
break
}
// 等待一段时间后重试
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1000))
}
}
// 所有重试都失败了
throw lastError || new Error("请求失败")
}
/**
* GET请求
*/
async get<T>(url: string, params?: Record<string, any>, config?: RequestConfig): Promise<ApiResponse<T>> {
let fullUrl = url
if (params) {
const searchParams = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
searchParams.append(key, String(value))
}
})
fullUrl += `?${searchParams.toString()}`
}
return this.request<T>("GET", fullUrl, undefined, config)
}
/**
* POST请求
*/
async post<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
return this.request<T>("POST", url, data, config)
}
/**
* PUT请求
*/
async put<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
return this.request<T>("PUT", url, data, config)
}
/**
* PATCH请求
*/
async patch<T>(url: string, data?: any, config?: RequestConfig): Promise<ApiResponse<T>> {
return this.request<T>("PATCH", url, data, config)
}
/**
* DELETE请求
*/
async delete<T>(url: string, config?: RequestConfig): Promise<ApiResponse<T>> {
return this.request<T>("DELETE", url, undefined, config)
}
/**
* 上传文件
*/
async upload<T>(url: string, file: File, config?: RequestConfig): Promise<ApiResponse<T>> {
const formData = new FormData()
formData.append("file", file)
const headers = {
...this.getAuthHeaders(),
...config?.headers,
}
// 不设置Content-Type让浏览器自动设置multipart/form-data
const requestConfig: RequestInit = {
method: "POST",
headers,
body: formData,
signal: AbortSignal.timeout(config?.timeout || this.timeout),
}
const fullUrl = url.startsWith("http") ? url : `${this.baseURL}${url}`
const response = await fetch(fullUrl, requestConfig)
return await this.handleResponse<T>(response)
}
}
// 导出单例实例
export const apiClient = new ApiClient()
// 导出类型
export type { ApiResponse, PaginationParams, PaginatedResponse }

132
Cunkebao/lib/api/config.ts Normal file
View File

@@ -0,0 +1,132 @@
// 存储键名常量
export const STORAGE_KEYS = {
ACCESS_TOKEN: "access_token",
REFRESH_TOKEN: "refresh_token",
USER_INFO: "user_info",
DEVICE_ID: "device_id",
LAST_LOGIN: "last_login",
} as const
// API错误码常量
export const ERROR_CODES = {
SUCCESS: 0,
INVALID_PARAMS: 1001,
UNAUTHORIZED: 1002,
FORBIDDEN: 1003,
NOT_FOUND: 1004,
SERVER_ERROR: 1005,
NETWORK_ERROR: 1006,
TIMEOUT: 1007,
INVALID_TOKEN: 1008,
TOKEN_EXPIRED: 1009,
} as const
// API配置
export const API_CONFIG = {
// 基础配置
BASE_URL: process.env.NEXT_PUBLIC_API_BASE_URL || "https://ckbapi.quwanzhi.com",
TIMEOUT: 30000,
RETRY_COUNT: 3,
RETRY_DELAY: 1000,
// 错误码
ERROR_CODES,
// 存储键名
STORAGE_KEYS,
// 错误消息映射
ERROR_MESSAGES: {
[ERROR_CODES.SUCCESS]: "操作成功",
[ERROR_CODES.INVALID_PARAMS]: "参数错误",
[ERROR_CODES.UNAUTHORIZED]: "未授权访问",
[ERROR_CODES.FORBIDDEN]: "禁止访问",
[ERROR_CODES.NOT_FOUND]: "资源不存在",
[ERROR_CODES.SERVER_ERROR]: "服务器内部错误",
[ERROR_CODES.NETWORK_ERROR]: "网络连接失败",
[ERROR_CODES.TIMEOUT]: "请求超时",
[ERROR_CODES.INVALID_TOKEN]: "无效的访问令牌",
[ERROR_CODES.TOKEN_EXPIRED]: "访问令牌已过期",
},
// API端点
ENDPOINTS: {
// 认证相关
AUTH: {
LOGIN: "/api/auth/login",
LOGOUT: "/api/auth/logout",
REFRESH: "/api/auth/refresh",
CAPTCHA: "/api/auth/captcha",
VERIFY: "/api/auth/verify",
},
// 场景获客
SCENARIOS: {
LIST: "/api/scenarios",
CREATE: "/api/scenarios",
UPDATE: "/api/scenarios/:id",
DELETE: "/api/scenarios/:id",
START: "/api/scenarios/:id/start",
PAUSE: "/api/scenarios/:id/pause",
STATS: "/api/scenarios/:id/stats",
},
// 设备管理
DEVICES: {
LIST: "/api/devices",
CREATE: "/api/devices",
UPDATE: "/api/devices/:id",
DELETE: "/api/devices/:id",
STATUS: "/api/devices/:id/status",
},
// 微信账号
WECHAT: {
LIST: "/api/wechat/accounts",
CREATE: "/api/wechat/accounts",
UPDATE: "/api/wechat/accounts/:id",
DELETE: "/api/wechat/accounts/:id",
BIND: "/api/wechat/accounts/:id/bind",
UNBIND: "/api/wechat/accounts/:id/unbind",
},
// 流量池
TRAFFIC: {
LIST: "/api/traffic/pools",
CREATE: "/api/traffic/pools",
UPDATE: "/api/traffic/pools/:id",
DELETE: "/api/traffic/pools/:id",
STATS: "/api/traffic/pools/:id/stats",
},
// 内容库
CONTENT: {
LIST: "/api/content/library",
CREATE: "/api/content/library",
UPDATE: "/api/content/library/:id",
DELETE: "/api/content/library/:id",
UPLOAD: "/api/content/upload",
},
},
} as const
// 请求头配置
export const REQUEST_HEADERS = {
"Content-Type": "application/json",
Accept: "application/json",
"X-Requested-With": "XMLHttpRequest",
} as const
// 响应状态码
export const HTTP_STATUS = {
OK: 200,
CREATED: 201,
NO_CONTENT: 204,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
} as const

View File

@@ -1,125 +1,156 @@
import type { ApiResponse, PaginatedResponse } from "@/types/common"
import type { ContentLibrary, ContentItem } from "@/types/content-library"
// 内容库管理API模块
import { apiClient } from "./client"
const API_BASE = "/api/content"
// 内容库API
export const contentApi = {
// 创建内容库
async createLibrary(data: Partial<ContentLibrary>): Promise<ApiResponse<ContentLibrary>> {
const response = await fetch(`${API_BASE}/libraries`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取内容库列表
async getLibraries(params: {
page?: number
pageSize?: number
search?: string
type?: string
}): Promise<ApiResponse<PaginatedResponse<ContentLibrary>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/libraries?${queryString.toString()}`)
return response.json()
},
// 获取内容库详情
async getLibraryById(id: string): Promise<ApiResponse<ContentLibrary>> {
const response = await fetch(`${API_BASE}/libraries/${id}`)
return response.json()
},
// 更新内容库
async updateLibrary(id: string, data: Partial<ContentLibrary>): Promise<ApiResponse<ContentLibrary>> {
const response = await fetch(`${API_BASE}/libraries/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除内容库
async deleteLibrary(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/libraries/${id}`, {
method: "DELETE",
})
return response.json()
},
// 创建内容项
async createItem(libraryId: string, data: Partial<ContentItem>): Promise<ApiResponse<ContentItem>> {
const response = await fetch(`${API_BASE}/libraries/${libraryId}/items`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取内容项列表
async getItems(
libraryId: string,
params: {
page?: number
pageSize?: number
search?: string
type?: string
},
): Promise<ApiResponse<PaginatedResponse<ContentItem>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/libraries/${libraryId}/items?${queryString.toString()}`)
return response.json()
},
// 获取内容项详情
async getItemById(libraryId: string, itemId: string): Promise<ApiResponse<ContentItem>> {
const response = await fetch(`${API_BASE}/libraries/${libraryId}/items/${itemId}`)
return response.json()
},
// 更新内容项
async updateItem(libraryId: string, itemId: string, data: Partial<ContentItem>): Promise<ApiResponse<ContentItem>> {
const response = await fetch(`${API_BASE}/libraries/${libraryId}/items/${itemId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除内容项
async deleteItem(libraryId: string, itemId: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/libraries/${libraryId}/items/${itemId}`, {
method: "DELETE",
})
return response.json()
},
// 内容数据类型定义
export interface Content {
id: string
title: string
type: "text" | "image" | "video" | "audio" | "document"
content: string
thumbnail?: string
fileUrl?: string
tags: string[]
category: string
status: "draft" | "published" | "archived"
viewCount: number
useCount: number
createTime: string
updateTime: string
creator: string
size?: number
duration?: number
}
export interface ContentStats {
total: number
published: number
draft: number
archived: number
totalViews: number
totalUses: number
}
export interface CreateContentRequest {
title: string
type: "text" | "image" | "video" | "audio" | "document"
content: string
tags?: string[]
category: string
fileUrl?: string
}
// 获取内容列表
export async function getContents(): Promise<Content[]> {
try {
const response = await apiClient.get("/v1/content")
return response.data || []
} catch (error) {
console.error("获取内容列表失败:", error)
// 返回模拟数据作为降级处理
return [
{
id: "1",
title: "产品介绍文案",
type: "text",
content: "这是一个优秀的产品介绍文案...",
tags: ["产品", "介绍", "营销"],
category: "营销文案",
status: "published",
viewCount: 1250,
useCount: 89,
createTime: "2024-01-01 10:00:00",
updateTime: "2024-01-07 14:30:00",
creator: "内容团队",
},
{
id: "2",
title: "品牌宣传图片",
type: "image",
content: "品牌宣传图片素材",
thumbnail: "/placeholder.svg?height=100&width=100",
fileUrl: "/placeholder.svg?height=400&width=600",
tags: ["品牌", "宣传", "图片"],
category: "视觉素材",
status: "published",
viewCount: 890,
useCount: 156,
createTime: "2024-01-02 11:00:00",
updateTime: "2024-01-07 13:45:00",
creator: "设计团队",
size: 2048000,
},
{
id: "3",
title: "产品演示视频",
type: "video",
content: "产品功能演示视频",
thumbnail: "/placeholder.svg?height=100&width=100",
fileUrl: "/placeholder.mp4",
tags: ["产品", "演示", "视频"],
category: "视频素材",
status: "published",
viewCount: 567,
useCount: 78,
createTime: "2024-01-03 09:30:00",
updateTime: "2024-01-07 10:20:00",
creator: "视频团队",
size: 15728640,
duration: 120,
},
]
}
}
// 获取内容统计
export async function getContentStats(): Promise<ContentStats> {
try {
const response = await apiClient.get("/v1/content/stats")
return response.data || { total: 0, published: 0, draft: 0, archived: 0, totalViews: 0, totalUses: 0 }
} catch (error) {
console.error("获取内容统计失败:", error)
return {
total: 156,
published: 128,
draft: 23,
archived: 5,
totalViews: 45620,
totalUses: 2340,
}
}
}
// 创建内容
export async function createContent(content: CreateContentRequest): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.post("/v1/content", content)
return { success: true, message: "内容创建成功" }
} catch (error) {
console.error("创建内容失败:", error)
return { success: false, message: "创建内容失败" }
}
}
// 删除内容
export async function deleteContent(contentId: string): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.delete(`/v1/content/${contentId}`)
return { success: true, message: "内容删除成功" }
} catch (error) {
console.error("删除内容失败:", error)
return { success: false, message: "删除内容失败" }
}
}
// 更新内容
export async function updateContent(
contentId: string,
updates: Partial<CreateContentRequest>,
): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.put(`/v1/content/${contentId}`, updates)
return { success: true, message: "内容更新成功" }
} catch (error) {
console.error("更新内容失败:", error)
return { success: false, message: "更新内容失败" }
}
}

View File

@@ -0,0 +1,150 @@
// 首页数据API接口定义
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "https://ckbapi.quwanzhi.com"
// 统一的API请求客户端
async function apiRequest<T>(url: string, options: RequestInit = {}): Promise<T> {
const token = typeof window !== "undefined" ? localStorage.getItem("ckb_token") : null
const defaultHeaders: Record<string, string> = {
"Content-Type": "application/json",
}
if (token) {
defaultHeaders["Authorization"] = `Bearer ${token}`
}
const response = await fetch(url, {
...options,
headers: {
...defaultHeaders,
...options.headers,
},
})
if (!response.ok) {
if (response.status === 401) {
// 触发未授权事件
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("auth-error", { detail: "UNAUTHORIZED" }))
}
}
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
// 检查业务状态码
if (data.code !== 200 && data.code !== 0) {
throw new Error(data.message || "请求失败")
}
return data
}
// 首页统计数据类型定义
export interface DashboardStats {
deviceCount: number // 设备总数
onlineDeviceCount: number // 在线设备数
wechatAccountCount: number // 微信号总数
activeWechatCount: number // 活跃微信号数
todayAcquisition: number // 今日获客数
totalAcquisition: number // 总获客数
scenarioCount: number // 场景数量
runningTaskCount: number // 运行中任务数
}
// 获客趋势数据类型
export interface AcquisitionTrend {
date: string
count: number
channel: string
}
// 场景统计数据类型
export interface ScenarioStats {
scenarioName: string
acquisitionCount: number
successRate: number
status: "running" | "stopped" | "completed"
}
/**
* 获取首页统计数据
*/
export async function getDashboardStats(): Promise<DashboardStats> {
try {
const response = await apiRequest<{ data: DashboardStats }>(`${API_BASE_URL}/v1/dashboard/stats`)
return response.data
} catch (error) {
console.error("获取首页统计数据失败:", error)
// 返回默认数据,避免页面崩溃
return {
deviceCount: 0,
onlineDeviceCount: 0,
wechatAccountCount: 0,
activeWechatCount: 0,
todayAcquisition: 0,
totalAcquisition: 0,
scenarioCount: 0,
runningTaskCount: 0,
}
}
}
/**
* 获取获客趋势数据
*/
export async function getAcquisitionTrend(days = 7): Promise<AcquisitionTrend[]> {
try {
const response = await apiRequest<{ data: AcquisitionTrend[] }>(
`${API_BASE_URL}/v1/dashboard/acquisition-trend?days=${days}`,
)
return response.data || []
} catch (error) {
console.error("获取获客趋势数据失败:", error)
return []
}
}
/**
* 获取场景统计数据
*/
export async function getScenarioStats(): Promise<ScenarioStats[]> {
try {
const response = await apiRequest<{ data: ScenarioStats[] }>(`${API_BASE_URL}/v1/dashboard/scenario-stats`)
return response.data || []
} catch (error) {
console.error("获取场景统计数据失败:", error)
return []
}
}
/**
* 获取设备状态统计
*/
export async function getDeviceStats(): Promise<{ online: number; offline: number; total: number }> {
try {
const response = await apiRequest<{ data: { online: number; offline: number; total: number } }>(
`${API_BASE_URL}/v1/dashboard/device-stats`,
)
return response.data
} catch (error) {
console.error("获取设备状态统计失败:", error)
return { online: 0, offline: 0, total: 0 }
}
}
/**
* 获取微信号状态统计
*/
export async function getWechatStats(): Promise<{ active: number; inactive: number; total: number }> {
try {
const response = await apiRequest<{ data: { active: number; inactive: number; total: number } }>(
`${API_BASE_URL}/v1/dashboard/wechat-stats`,
)
return response.data
} catch (error) {
console.error("获取微信号状态统计失败:", error)
return { active: 0, inactive: 0, total: 0 }
}
}

View File

@@ -1,149 +1,178 @@
import type {
ApiResponse,
Device,
DeviceStats,
DeviceTaskRecord,
PaginatedResponse,
QueryDeviceParams,
CreateDeviceParams,
UpdateDeviceParams,
DeviceStatus,
} from "@/types/device"
// 设备管理API模块 - 基于存客宝API文档
import { apiClient } from "./client"
const API_BASE = "/api/devices"
// 设备管理API
export const deviceApi = {
// 创建设备
async create(params: CreateDeviceParams): Promise<ApiResponse<Device>> {
const response = await fetch(`${API_BASE}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params),
})
return response.json()
},
// 更新设备
async update(params: UpdateDeviceParams): Promise<ApiResponse<Device>> {
const response = await fetch(`${API_BASE}/${params.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params),
})
return response.json()
},
// 获取设备详情
async getById(id: string): Promise<ApiResponse<Device>> {
const response = await fetch(`${API_BASE}/${id}`)
return response.json()
},
// 查询设备列表
async query(params: QueryDeviceParams): Promise<ApiResponse<PaginatedResponse<Device>>> {
const queryString = new URLSearchParams({
...params,
tags: params.tags ? JSON.stringify(params.tags) : "",
dateRange: params.dateRange ? JSON.stringify(params.dateRange) : "",
}).toString()
const response = await fetch(`${API_BASE}?${queryString}`)
return response.json()
},
// 删除设备
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}`, {
method: "DELETE",
})
return response.json()
},
// 重启设备
async restart(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}/restart`, {
method: "POST",
})
return response.json()
},
// 解绑设备
async unbind(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}/unbind`, {
method: "POST",
})
return response.json()
},
// 获取设备统计数据
async getStats(id: string): Promise<ApiResponse<DeviceStats>> {
const response = await fetch(`${API_BASE}/${id}/stats`)
return response.json()
},
// 获取设备任务记录
async getTaskRecords(id: string, page = 1, pageSize = 20): Promise<ApiResponse<PaginatedResponse<DeviceTaskRecord>>> {
const response = await fetch(`${API_BASE}/${id}/tasks?page=${page}&pageSize=${pageSize}`)
return response.json()
},
// 批量更新设备标签
async updateTags(ids: string[], tags: string[]): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/tags`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ deviceIds: ids, tags }),
})
return response.json()
},
// 批量导出设备数据
async exportDevices(ids: string[]): Promise<Blob> {
const response = await fetch(`${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>>> {
const response = await fetch(`${API_BASE}/status`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ deviceIds: ids }),
})
return response.json()
},
// 更新设备任务配置
async updateDeviceTaskConfig(params: {
deviceId: string;
autoAddFriend?: number;
autoReply?: number;
momentsSync?: number;
aiChat?: number;
}): Promise<ApiResponse<Device>> {
const response = await fetch(`${API_BASE}/devices/task-config`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params),
});
return response.json();
},
// 设备数据类型定义
export interface Device {
id: string
name: string
type: "android" | "ios"
status: "online" | "offline" | "error"
ip: string
version: string
wechatCount: number
lastActiveTime: string
createTime: string
imei: string
model: string
battery: number
friendCount: number
todayAdded: number
location: string
employee: string
wechatId: string
}
export interface DeviceStats {
total: number
online: number
offline: number
error: number
}
export interface AddDeviceRequest {
name: string
type: "android" | "ios"
ip: string
}
// API响应格式
export interface ApiResponse<T> {
code: number
message: string
data: T
success: boolean
}
// 获取设备列表
export async function getDevices(): Promise<Device[]> {
try {
const response = await apiClient.get<Device[]>("/api/devices")
// 确保返回的是数组
if (response.data && Array.isArray(response.data)) {
return response.data
}
// 如果API返回的数据格式不正确返回空数组
console.warn("API返回的设备数据格式不正确:", response)
return []
} catch (error) {
console.error("获取设备列表失败:", error)
// 返回模拟数据作为降级处理,确保是数组格式
return [
{
id: "1",
name: "设备1",
type: "android",
status: "online",
ip: "192.168.1.100",
version: "Android 11",
wechatCount: 5,
lastActiveTime: "2024-01-07 14:30:00",
createTime: "2024-01-01 10:00:00",
imei: "sdt23713",
model: "iPhone14",
battery: 94,
friendCount: 363,
todayAdded: 1,
location: "北京",
employee: "员工1",
wechatId: "wx_001",
},
{
id: "2",
name: "设备2",
type: "android",
status: "online",
ip: "192.168.1.101",
version: "Android 12",
wechatCount: 3,
lastActiveTime: "2024-01-07 12:15:00",
createTime: "2024-01-02 11:00:00",
imei: "sdt23714",
model: "S23",
battery: 20,
friendCount: 202,
todayAdded: 30,
location: "上海",
employee: "员工2",
wechatId: "wx_002",
},
{
id: "3",
name: "设备3",
type: "ios",
status: "online",
ip: "192.168.1.102",
version: "iOS 16.0",
wechatCount: 8,
lastActiveTime: "2024-01-07 14:45:00",
createTime: "2024-01-03 09:30:00",
imei: "brmqmjae",
model: "Mi13",
battery: 26,
friendCount: 501,
todayAdded: 40,
location: "广州",
employee: "员工3",
wechatId: "wx_003",
},
]
}
}
// 获取设备统计
export async function getDeviceStats(): Promise<DeviceStats> {
try {
const response = await apiClient.get<DeviceStats>("/api/devices/stats")
if (response.data) {
return response.data
}
// 默认统计数据
return { total: 0, online: 0, offline: 0, error: 0 }
} catch (error) {
console.error("获取设备统计失败:", error)
return {
total: 50,
online: 40,
offline: 8,
error: 2,
}
}
}
// 添加设备
export async function addDevice(device: AddDeviceRequest): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.post<any>("/api/devices", device)
return { success: true, message: "设备添加成功" }
} catch (error) {
console.error("添加设备失败:", error)
return { success: false, message: "添加设备失败" }
}
}
// 删除设备
export async function deleteDevice(deviceId: string): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.delete(`/api/devices/${deviceId}`)
return { success: true, message: "设备删除成功" }
} catch (error) {
console.error("删除设备失败:", error)
return { success: false, message: "删除设备失败" }
}
}
// 重启设备
export async function restartDevice(deviceId: string): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.post(`/api/devices/${deviceId}/restart`)
return { success: true, message: "设备重启成功" }
} catch (error) {
console.error("重启设备失败:", error)
return { success: false, message: "重启设备失败" }
}
}

View File

@@ -0,0 +1,98 @@
// GitHub项目集成分析和对接方案
// 基于 https://github.com/fnvtk/cunkebao_v3.git 项目结构
/**
* GitHub项目结构分析
*
* cunkebao_v3/
* ├── Cunkebao/ # 前端主应用 (React/Vue混合)
* │ ├── src/
* │ │ ├── components/ # 组件库
* │ │ ├── pages/ # 页面组件
* │ │ ├── api/ # API接口
* │ │ ├── utils/ # 工具函数
* │ │ └── store/ # 状态管理
* │ ├── public/ # 静态资源
* │ └── package.json # 依赖配置
* ├── Server/ # 后端API服务
* │ ├── controllers/ # 控制器
* │ ├── models/ # 数据模型
* │ ├── routes/ # 路由配置
* │ └── middleware/ # 中间件
* ├── Store_vue/ # Vue商城前端
* └── SuperAdmin/ # 管理后台
*/
// 项目关联度分析
export const PROJECT_CORRELATION = {
// 高度关联的模块 (90%+)
HIGH_CORRELATION: [
"场景获客模块", // 核心业务逻辑完全一致
"设备管理模块", // 设备状态和操作接口一致
"微信号管理", // 微信账号管理逻辑相同
"API接口规范", // 接口定义和响应格式一致
],
// 中度关联的模块 (60-90%)
MEDIUM_CORRELATION: [
"用户界面设计", // 设计风格相似,需要适配
"数据统计图表", // 统计逻辑相同,展示方式需调整
"工作台功能", // 功能相似,实现方式不同
],
// 低度关联的模块 (30-60%)
LOW_CORRELATION: [
"商城模块", // Store_vue独立模块
"管理后台", // SuperAdmin独立系统
"支付系统", // 业务逻辑差异较大
],
// 需要重新实现的模块
NEED_REIMPLEMENTATION: [
"Next.js路由系统", // 从Vue Router迁移到Next.js
"状态管理", // 从Vuex迁移到React状态管理
"组件库", // 从Vue组件迁移到React组件
],
}
// 对接策略配置
export const INTEGRATION_STRATEGY = {
// API对接策略
API_INTEGRATION: {
// 直接复用的接口
REUSE_APIS: [
"/api/scenarios/*", // 场景获客接口
"/api/devices/*", // 设备管理接口
"/api/wechat/*", // 微信管理接口
"/api/traffic/*", // 流量池接口
"/api/content/*", // 内容库接口
"/api/auth/*", // 认证接口
],
// 需要适配的接口
ADAPT_APIS: [
"/api/dashboard/*", // 数据格式需要调整
"/api/analytics/*", // 统计接口需要优化
"/api/upload/*", // 文件上传需要适配
],
// 需要新增的接口
NEW_APIS: [
"/api/mobile/*", // 移动端专用接口
"/api/realtime/*", // 实时数据接口
"/api/notifications/*", // 通知推送接口
],
},
// 前端对接策略
FRONTEND_INTEGRATION: {
// 保留现有架构
KEEP_CURRENT: ["Next.js框架", "TypeScript类型系统", "Tailwind CSS样式", "shadcn/ui组件库"],
// 从GitHub项目迁移
MIGRATE_FROM_GITHUB: ["业务逻辑代码", "API调用方法", "数据处理函数", "工具类函数"],
// 混合实现
HYBRID_IMPLEMENTATION: ["页面组件结构", "状态管理方案", "路由配置", "样式主题"],
},
}

View File

@@ -5,4 +5,3 @@ export * from "./users"
export * from "./content"
export * from "./traffic"
export * from "./workspace"

View File

@@ -0,0 +1,305 @@
// 移动端场景获客API - 基于cunkebao_v3项目架构
import { apiClient } from "./client"
// 场景获客统计数据接口
export interface ScenarioStatsData {
id: string
name: string
type: string
todayCount: number
totalCount: number
growthRate: number
status: "active" | "inactive" | "error"
lastUpdateTime: string
}
// AI智能获客数据接口
export interface AIScenarioData {
id: string
name: string
description: string
todayCount: number
totalCount: number
growthRate: number
status: "active" | "inactive" | "beta"
features: string[]
}
// 场景获客概览数据
export interface ScenarioOverview {
totalScenarios: number
activeScenarios: number
todayTotal: number
monthlyTotal: number
averageGrowthRate: number
topPerforming: string[]
}
/**
* 获取场景获客统计数据
* 对应cunkebao_v3项目中的场景获客模块
*/
export async function getScenarioStats(): Promise<ScenarioStatsData[]> {
try {
console.log("📊 获取场景获客统计数据")
const response = await apiClient.get<ScenarioStatsData[]>("/api/scenarios/stats")
if (response.code === 200 && response.data) {
console.log("✅ 获取场景统计成功:", response.data.length)
return response.data
}
throw new Error(response.message || "获取场景统计失败")
} catch (error) {
console.error("❌ 获取场景统计失败:", error)
// 返回模拟数据作为降级方案
return [
{
id: "haibao",
name: "海报获客",
type: "poster",
todayCount: 167,
totalCount: 5420,
growthRate: 10.2,
status: "active",
lastUpdateTime: "2024-01-15 14:30:00",
},
{
id: "dingdan",
name: "订单获客",
type: "order",
todayCount: 112,
totalCount: 3890,
growthRate: 7.8,
status: "active",
lastUpdateTime: "2024-01-15 14:25:00",
},
{
id: "douyin",
name: "抖音获客",
type: "douyin",
todayCount: 156,
totalCount: 4760,
growthRate: 12.5,
status: "active",
lastUpdateTime: "2024-01-15 14:20:00",
},
{
id: "xiaohongshu",
name: "小红书获客",
type: "xiaohongshu",
todayCount: 89,
totalCount: 2340,
growthRate: 8.3,
status: "active",
lastUpdateTime: "2024-01-15 14:15:00",
},
{
id: "phone",
name: "电话获客",
type: "phone",
todayCount: 42,
totalCount: 1890,
growthRate: 15.8,
status: "active",
lastUpdateTime: "2024-01-15 14:10:00",
},
{
id: "gongzhonghao",
name: "公众号获客",
type: "wechat_official",
todayCount: 234,
totalCount: 7650,
growthRate: 15.7,
status: "active",
lastUpdateTime: "2024-01-15 14:05:00",
},
{
id: "weixinqun",
name: "微信群获客",
type: "wechat_group",
todayCount: 145,
totalCount: 4320,
growthRate: 11.2,
status: "active",
lastUpdateTime: "2024-01-15 14:00:00",
},
{
id: "fukuanma",
name: "付款码获客",
type: "payment_code",
todayCount: 78,
totalCount: 2100,
growthRate: 9.5,
status: "active",
lastUpdateTime: "2024-01-15 13:55:00",
},
{
id: "api",
name: "API获客",
type: "api",
todayCount: 198,
totalCount: 6540,
growthRate: 14.3,
status: "active",
lastUpdateTime: "2024-01-15 13:50:00",
},
]
}
}
/**
* 获取AI智能获客数据
* 对应cunkebao_v3项目中的AI模块
*/
export async function getAIScenarioStats(): Promise<AIScenarioData[]> {
try {
console.log("🤖 获取AI智能获客数据")
const response = await apiClient.get<AIScenarioData[]>("/api/ai-scenarios/stats")
if (response.code === 200 && response.data) {
console.log("✅ 获取AI场景统计成功:", response.data.length)
return response.data
}
throw new Error(response.message || "获取AI场景统计失败")
} catch (error) {
console.error("❌ 获取AI场景统计失败:", error)
// 返回模拟数据作为降级方案
return [
{
id: "ai-friend",
name: "AI智能加友",
description: "智能分析用户画像,自动添加优质客户",
todayCount: 245,
totalCount: 8900,
growthRate: 18.5,
status: "beta",
features: ["智能筛选", "自动加友", "画像分析"],
},
{
id: "ai-group",
name: "AI群引流",
description: "智能群聊互动,提高群活跃度和转化率",
todayCount: 178,
totalCount: 5670,
growthRate: 15.2,
status: "beta",
features: ["智能回复", "群活跃度", "转化优化"],
},
{
id: "ai-conversion",
name: "AI话费转化",
description: "多话费智能营销,提升转化效果",
todayCount: 134,
totalCount: 4230,
growthRate: 12.8,
status: "beta",
features: ["智能营销", "转化分析", "效果优化"],
},
]
}
}
/**
* 获取场景获客概览数据
*/
export async function getScenarioOverview(): Promise<ScenarioOverview> {
try {
console.log("📈 获取场景获客概览")
const response = await apiClient.get<ScenarioOverview>("/api/scenarios/overview")
if (response.code === 200 && response.data) {
console.log("✅ 获取概览数据成功")
return response.data
}
throw new Error(response.message || "获取概览数据失败")
} catch (error) {
console.error("❌ 获取概览数据失败:", error)
// 返回模拟数据作为降级方案
return {
totalScenarios: 12,
activeScenarios: 9,
todayTotal: 1421,
monthlyTotal: 42890,
averageGrowthRate: 12.4,
topPerforming: ["公众号获客", "API获客", "抖音获客"],
}
}
}
/**
* 创建新的获客计划
*/
export async function createScenarioPlan(planData: {
name: string
type: string
config: any
deviceIds: string[]
targetCount: number
}): Promise<{ id: string; message: string }> {
try {
console.log("🎯 创建获客计划:", planData.name)
const response = await apiClient.post<{ id: string; message: string }>("/api/scenarios/create", planData)
if (response.code === 200 && response.data) {
console.log("✅ 创建计划成功")
return response.data
}
throw new Error(response.message || "创建计划失败")
} catch (error) {
console.error("❌ 创建计划失败:", error)
throw error
}
}
/**
* 启动获客场景
*/
export async function startScenario(scenarioId: string): Promise<{ message: string }> {
try {
console.log("▶️ 启动获客场景:", scenarioId)
const response = await apiClient.post<{ message: string }>(`/api/scenarios/${scenarioId}/start`, {})
if (response.code === 200) {
console.log("✅ 启动场景成功")
return response.data || { message: "启动成功" }
}
throw new Error(response.message || "启动场景失败")
} catch (error) {
console.error("❌ 启动场景失败:", error)
throw error
}
}
/**
* 停止获客场景
*/
export async function stopScenario(scenarioId: string): Promise<{ message: string }> {
try {
console.log("⏹️ 停止获客场景:", scenarioId)
const response = await apiClient.post<{ message: string }>(`/api/scenarios/${scenarioId}/stop`, {})
if (response.code === 200) {
console.log("✅ 停止场景成功")
return response.data || { message: "停止成功" }
}
throw new Error(response.message || "停止场景失败")
} catch (error) {
console.error("❌ 停止场景失败:", error)
throw error
}
}

View File

@@ -1,112 +1,165 @@
import type {
ApiResponse,
CreateScenarioParams,
UpdateScenarioParams,
QueryScenarioParams,
ScenarioBase,
ScenarioStats,
AcquisitionRecord,
PaginatedResponse,
} from "@/types/scenario"
/**
* 场景获客相关API接口
*/
import { apiClient, type PaginatedResponse, type PaginationParams } from "./client"
const API_BASE = "/api/scenarios"
// 获客场景API
export const scenarioApi = {
// 创建场景
async create(params: CreateScenarioParams): Promise<ApiResponse<ScenarioBase>> {
const response = await fetch(`${API_BASE}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params),
})
return response.json()
},
// 更新场景
async update(params: UpdateScenarioParams): Promise<ApiResponse<ScenarioBase>> {
const response = await fetch(`${API_BASE}/${params.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(params),
})
return response.json()
},
// 获取场景详情
async getById(id: string): Promise<ApiResponse<ScenarioBase>> {
const response = await fetch(`${API_BASE}/${id}`)
return response.json()
},
// 查询场景列表
async query(params: QueryScenarioParams): Promise<ApiResponse<PaginatedResponse<ScenarioBase>>> {
const queryString = new URLSearchParams({
...params,
dateRange: params.dateRange ? JSON.stringify(params.dateRange) : "",
}).toString()
const response = await fetch(`${API_BASE}?${queryString}`)
return response.json()
},
// 删除场景
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}`, {
method: "DELETE",
})
return response.json()
},
// 启动场景
async start(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}/start`, {
method: "POST",
})
return response.json()
},
// 暂停场景
async pause(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}/pause`, {
method: "POST",
})
return response.json()
},
// 获取场景统计数据
async getStats(id: string): Promise<ApiResponse<ScenarioStats>> {
const response = await fetch(`${API_BASE}/${id}/stats`)
return response.json()
},
// 获取获客记录
async getRecords(id: string, page = 1, pageSize = 20): Promise<ApiResponse<PaginatedResponse<AcquisitionRecord>>> {
const response = await fetch(`${API_BASE}/${id}/records?page=${page}&pageSize=${pageSize}`)
return response.json()
},
// 导出获客记录
async exportRecords(id: string, dateRange?: { start: string; end: string }): Promise<Blob> {
const queryString = dateRange ? `?start=${dateRange.start}&end=${dateRange.end}` : ""
const response = await fetch(`${API_BASE}/${id}/records/export${queryString}`)
return response.blob()
},
// 批量更新标签
async updateTags(id: string, customerIds: string[], tags: string[]): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/${id}/tags`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ customerIds, tags }),
})
return response.json()
},
export interface ScenarioBase {
id: string
name: string
type:
| "douyin"
| "kuaishou"
| "xiaohongshu"
| "weibo"
| "haibao"
| "phone"
| "gongzhonghao"
| "weixinqun"
| "payment"
| "api"
status: "running" | "paused" | "completed" | "draft"
description?: string
createdAt: string
updatedAt: string
createdBy: string
}
export interface ScenarioStats {
deviceCount: number
acquiredCount: number
addedCount: number
passRate: number
todayAcquired: number
todayAdded: number
}
export interface ScenarioDetail extends ScenarioBase {
config: Record<string, any>
stats: ScenarioStats
devices: string[]
lastExecutedAt?: string
nextExecuteAt?: string
}
export interface CreateScenarioRequest {
name: string
type: ScenarioBase["type"]
description?: string
config: Record<string, any>
devices: string[]
}
export interface UpdateScenarioRequest extends Partial<CreateScenarioRequest> {
id: string
status?: ScenarioBase["status"]
}
export interface ScenarioQueryParams extends PaginationParams {
type?: ScenarioBase["type"]
status?: ScenarioBase["status"]
keyword?: string
startDate?: string
endDate?: string
}
/**
* 场景获客API类
*/
class ScenarioApi {
/**
* 查询场景列表
*/
async query(params: ScenarioQueryParams) {
return apiClient.get<PaginatedResponse<ScenarioBase>>("/scenarios", params)
}
/**
* 获取场景详情
*/
async getById(id: string) {
return apiClient.get<ScenarioDetail>(`/scenarios/${id}`)
}
/**
* 创建场景
*/
async create(data: CreateScenarioRequest) {
return apiClient.post<ScenarioDetail>("/scenarios", data)
}
/**
* 更新场景
*/
async update(data: UpdateScenarioRequest) {
return apiClient.put<ScenarioDetail>(`/scenarios/${data.id}`, data)
}
/**
* 删除场景
*/
async delete(id: string) {
return apiClient.delete(`/scenarios/${id}`)
}
/**
* 复制场景
*/
async copy(id: string, name: string) {
return apiClient.post<ScenarioDetail>(`/scenarios/${id}/copy`, { name })
}
/**
* 启动场景
*/
async start(id: string) {
return apiClient.post(`/scenarios/${id}/start`)
}
/**
* 暂停场景
*/
async pause(id: string) {
return apiClient.post(`/scenarios/${id}/pause`)
}
/**
* 获取场景统计数据
*/
async getStats(id: string, dateRange?: { startDate: string; endDate: string }) {
return apiClient.get<ScenarioStats>(`/scenarios/${id}/stats`, dateRange)
}
/**
* 获取场景执行日志
*/
async getLogs(id: string, params: PaginationParams) {
return apiClient.get<PaginatedResponse<any>>(`/scenarios/${id}/logs`, params)
}
/**
* 获取API接口配置
*/
async getApiConfig(id: string) {
return apiClient.get<{
apiKey: string
webhookUrl: string
enabled: boolean
}>(`/scenarios/${id}/api-config`)
}
/**
* 更新API接口配置
*/
async updateApiConfig(id: string, config: { enabled: boolean }) {
return apiClient.put(`/scenarios/${id}/api-config`, config)
}
/**
* 重新生成API密钥
*/
async regenerateApiKey(id: string) {
return apiClient.post<{ apiKey: string }>(`/scenarios/${id}/regenerate-api-key`)
}
}
export const scenarioApi = new ScenarioApi()

View File

@@ -1,122 +1,131 @@
import type { ApiResponse, PaginatedResponse } from "@/types/common"
import type { TrafficPool, TrafficDistribution } from "@/types/traffic"
// 流量池管理API模块
import { apiClient } from "./client"
const API_BASE = "/api/traffic"
// 流量池API
export const trafficApi = {
// 创建流量池
async createPool(data: Partial<TrafficPool>): Promise<ApiResponse<TrafficPool>> {
const response = await fetch(`${API_BASE}/pools`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取流量池列表
async getPools(params: {
page?: number
pageSize?: number
search?: string
type?: string
}): Promise<ApiResponse<PaginatedResponse<TrafficPool>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/pools?${queryString.toString()}`)
return response.json()
},
// 获取流量池详情
async getPoolById(id: string): Promise<ApiResponse<TrafficPool>> {
const response = await fetch(`${API_BASE}/pools/${id}`)
return response.json()
},
// 更新流量池
async updatePool(id: string, data: Partial<TrafficPool>): Promise<ApiResponse<TrafficPool>> {
const response = await fetch(`${API_BASE}/pools/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除流量池
async deletePool(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/pools/${id}`, {
method: "DELETE",
})
return response.json()
},
// 创建流量分配
async createDistribution(data: Partial<TrafficDistribution>): Promise<ApiResponse<TrafficDistribution>> {
const response = await fetch(`${API_BASE}/distributions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取流量分配列表
async getDistributions(params: {
page?: number
pageSize?: number
search?: string
poolId?: string
}): Promise<ApiResponse<PaginatedResponse<TrafficDistribution>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/distributions?${queryString.toString()}`)
return response.json()
},
// 获取流量分配详情
async getDistributionById(id: string): Promise<ApiResponse<TrafficDistribution>> {
const response = await fetch(`${API_BASE}/distributions/${id}`)
return response.json()
},
// 更新流量分配
async updateDistribution(id: string, data: Partial<TrafficDistribution>): Promise<ApiResponse<TrafficDistribution>> {
const response = await fetch(`${API_BASE}/distributions/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除流量分配
async deleteDistribution(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/distributions/${id}`, {
method: "DELETE",
})
return response.json()
},
// 流量池数据类型定义
export interface TrafficPool {
id: string
name: string
description: string
userCount: number
activeUsers: number
tags: string[]
source: string
createTime: string
lastUpdateTime: string
status: "active" | "inactive"
dailyGrowth: number
conversionRate: number
}
export interface TrafficStats {
total: number
active: number
inactive: number
totalUsers: number
todayAdded: number
averageConversion: number
}
export interface CreateTrafficPoolRequest {
name: string
description: string
source: string
tags?: string[]
}
// 获取流量池列表
export async function getTrafficPools(): Promise<TrafficPool[]> {
try {
const response = await apiClient.get("/v1/traffic/pools")
return response.data || []
} catch (error) {
console.error("获取流量池列表失败:", error)
// 返回模拟数据作为降级处理
return [
{
id: "1",
name: "高价值客户池",
description: "高消费能力的潜在客户群体",
userCount: 1250,
activeUsers: 890,
tags: ["高价值", "活跃"],
source: "线上推广",
createTime: "2024-01-01 10:00:00",
lastUpdateTime: "2024-01-07 14:30:00",
status: "active",
dailyGrowth: 25,
conversionRate: 12.5,
},
{
id: "2",
name: "新用户引导池",
description: "新注册用户的培育池",
userCount: 2340,
activeUsers: 1560,
tags: ["新用户", "培育"],
source: "注册引导",
createTime: "2024-01-02 11:00:00",
lastUpdateTime: "2024-01-07 13:45:00",
status: "active",
dailyGrowth: 45,
conversionRate: 8.3,
},
{
id: "3",
name: "沉睡用户唤醒池",
description: "长期未活跃用户的唤醒池",
userCount: 890,
activeUsers: 234,
tags: ["沉睡", "唤醒"],
source: "历史数据",
createTime: "2024-01-03 09:30:00",
lastUpdateTime: "2024-01-07 10:20:00",
status: "active",
dailyGrowth: 8,
conversionRate: 5.2,
},
]
}
}
// 获取流量池统计
export async function getTrafficStats(): Promise<TrafficStats> {
try {
const response = await apiClient.get("/v1/traffic/stats")
return response.data || { total: 0, active: 0, inactive: 0, totalUsers: 0, todayAdded: 0, averageConversion: 0 }
} catch (error) {
console.error("获取流量池统计失败:", error)
return {
total: 8,
active: 6,
inactive: 2,
totalUsers: 15420,
todayAdded: 156,
averageConversion: 8.7,
}
}
}
// 创建流量池
export async function createTrafficPool(
pool: CreateTrafficPoolRequest,
): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.post("/v1/traffic/pools", pool)
return { success: true, message: "流量池创建成功" }
} catch (error) {
console.error("创建流量池失败:", error)
return { success: false, message: "创建流量池失败" }
}
}
// 删除流量池
export async function deleteTrafficPool(poolId: string): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.delete(`/v1/traffic/pools/${poolId}`)
return { success: true, message: "流量池删除成功" }
} catch (error) {
console.error("删除流量池失败:", error)
return { success: false, message: "删除流量池失败" }
}
}

View File

@@ -88,4 +88,3 @@ export const userApi = {
return response.blob()
},
}

186
Cunkebao/lib/api/wechat.ts Normal file
View File

@@ -0,0 +1,186 @@
// 微信号管理API模块
import { apiClient } from "./client"
// 微信号数据类型定义
export interface WechatAccount {
id: string
wechatId: string
nickname: string
avatar: string
status: "online" | "offline" | "banned"
friendCount: number
groupCount: number
todayAdded: number
maxDailyAdds: number
remainingAdds: number
deviceId: string
deviceName: string
lastActiveTime: string
createTime: string
tags: string[]
remark: string
}
export interface WechatStats {
total: number
online: number
offline: number
banned: number
totalFriends: number
totalGroups: number
todayAdded: number
}
export interface AddWechatRequest {
wechatId: string
nickname: string
deviceId: string
remark?: string
tags?: string[]
}
// 获取微信号列表
export async function getWechatAccounts(): Promise<WechatAccount[]> {
try {
const response = await apiClient.get("/v1/wechat/accounts")
return response.data || []
} catch (error) {
console.error("获取微信号列表失败:", error)
// 返回模拟数据作为降级处理
return [
{
id: "1",
wechatId: "wxid_test001",
nickname: "测试账号1",
avatar: "/placeholder.svg?height=40&width=40",
status: "online",
friendCount: 1250,
groupCount: 35,
todayAdded: 12,
maxDailyAdds: 50,
remainingAdds: 38,
deviceId: "device_001",
deviceName: "设备1",
lastActiveTime: "2024-01-07 14:30:00",
createTime: "2024-01-01 10:00:00",
tags: ["营销", "客服"],
remark: "主要营销账号",
},
{
id: "2",
wechatId: "wxid_test002",
nickname: "测试账号2",
avatar: "/placeholder.svg?height=40&width=40",
status: "online",
friendCount: 890,
groupCount: 28,
todayAdded: 8,
maxDailyAdds: 50,
remainingAdds: 42,
deviceId: "device_002",
deviceName: "设备2",
lastActiveTime: "2024-01-07 13:45:00",
createTime: "2024-01-02 11:00:00",
tags: ["客服"],
remark: "客服专用账号",
},
{
id: "3",
wechatId: "wxid_test003",
nickname: "测试账号3",
avatar: "/placeholder.svg?height=40&width=40",
status: "offline",
friendCount: 567,
groupCount: 15,
todayAdded: 5,
maxDailyAdds: 50,
remainingAdds: 45,
deviceId: "device_003",
deviceName: "设备3",
lastActiveTime: "2024-01-07 10:20:00",
createTime: "2024-01-03 09:30:00",
tags: ["测试"],
remark: "测试账号",
},
]
}
}
// 获取微信号统计
export async function getWechatStats(): Promise<WechatStats> {
try {
const response = await apiClient.get("/v1/wechat/stats")
return (
response.data || { total: 0, online: 0, offline: 0, banned: 0, totalFriends: 0, totalGroups: 0, todayAdded: 0 }
)
} catch (error) {
console.error("获取微信号统计失败:", error)
return {
total: 25,
online: 18,
offline: 6,
banned: 1,
totalFriends: 15420,
totalGroups: 156,
todayAdded: 89,
}
}
}
// 添加微信号
export async function addWechatAccount(account: AddWechatRequest): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.post("/v1/wechat/accounts", account)
return { success: true, message: "微信号添加成功" }
} catch (error) {
console.error("添加微信号失败:", error)
return { success: false, message: "添加微信号失败" }
}
}
// 删除微信号
export async function deleteWechatAccount(accountId: string): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.delete(`/v1/wechat/accounts/${accountId}`)
return { success: true, message: "微信号删除成功" }
} catch (error) {
console.error("删除微信号失败:", error)
return { success: false, message: "删除微信号失败" }
}
}
// 更新微信号
export async function updateWechatAccount(
accountId: string,
updates: Partial<AddWechatRequest>,
): Promise<{ success: boolean; message?: string }> {
try {
const response = await apiClient.put(`/v1/wechat/accounts/${accountId}`, updates)
return { success: true, message: "微信号更新成功" }
} catch (error) {
console.error("更新微信号失败:", error)
return { success: false, message: "更新微信号失败" }
}
}
// 获取微信号好友列表
export async function getWechatFriends(accountId: string): Promise<any[]> {
try {
const response = await apiClient.get(`/v1/wechat/accounts/${accountId}/friends`)
return response.data || []
} catch (error) {
console.error("获取好友列表失败:", error)
return []
}
}
// 获取微信号群组列表
export async function getWechatGroups(accountId: string): Promise<any[]> {
try {
const response = await apiClient.get(`/v1/wechat/accounts/${accountId}/groups`)
return response.data || []
} catch (error) {
console.error("获取群组列表失败:", error)
return []
}
}

View File

@@ -1,319 +1,270 @@
import type { ApiResponse, PaginatedResponse } from "@/types/common"
import type { MomentsSync, GroupSync, GroupPush, AutoLike, AutoGroup } from "@/types/workspace"
// 工作台API接口定义
const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL || "https://ckbapi.quwanzhi.com"
const API_BASE = "/api/workspace"
// 工作台任务类型
export type WorkspaceTaskType =
| "moments-sync" // 朋友圈同步
| "group-push" // 社群推送
| "auto-like" // 自动点赞
| "auto-group" // 自动建群
| "group-sync" // 群同步
| "traffic-distribution" // 流量分发
| "ai-assistant" // AI助手
| "ai-analyzer" // AI分析
| "ai-strategy" // AI策略
// 工作区API
export const workspaceApi = {
// 朋友圈同步API
moments: {
// 创建朋友圈同步任务
async create(data: Partial<MomentsSync>): Promise<ApiResponse<MomentsSync>> {
const response = await fetch(`${API_BASE}/moments-sync`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 工作台任务状态
export type WorkspaceTaskStatus = "pending" | "running" | "completed" | "failed" | "paused"
// 获取朋友圈同步任务列表
async getList(params: {
page?: number
pageSize?: number
status?: string
}): Promise<ApiResponse<PaginatedResponse<MomentsSync>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/moments-sync?${queryString.toString()}`)
return response.json()
},
// 获取朋友圈同步任务详情
async getById(id: string): Promise<ApiResponse<MomentsSync>> {
const response = await fetch(`${API_BASE}/moments-sync/${id}`)
return response.json()
},
// 更新朋友圈同步任务
async update(id: string, data: Partial<MomentsSync>): Promise<ApiResponse<MomentsSync>> {
const response = await fetch(`${API_BASE}/moments-sync/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除朋友圈同步任务
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/moments-sync/${id}`, {
method: "DELETE",
})
return response.json()
},
// 启动朋友圈同步任务
async start(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/moments-sync/${id}/start`, {
method: "POST",
})
return response.json()
},
// 暂停朋友圈同步任务
async pause(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/moments-sync/${id}/pause`, {
method: "POST",
})
return response.json()
},
},
// 群同步API
groupSync: {
// 创建群同步任务
async create(data: Partial<GroupSync>): Promise<ApiResponse<GroupSync>> {
const response = await fetch(`${API_BASE}/group-sync`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取群同步任务列表
async getList(params: {
page?: number
pageSize?: number
status?: string
}): Promise<ApiResponse<PaginatedResponse<GroupSync>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/group-sync?${queryString.toString()}`)
return response.json()
},
// 获取群同步任务详情
async getById(id: string): Promise<ApiResponse<GroupSync>> {
const response = await fetch(`${API_BASE}/group-sync/${id}`)
return response.json()
},
// 更新群同步任务
async update(id: string, data: Partial<GroupSync>): Promise<ApiResponse<GroupSync>> {
const response = await fetch(`${API_BASE}/group-sync/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除群同步任务
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/group-sync/${id}`, {
method: "DELETE",
})
return response.json()
},
},
// 群发API
groupPush: {
// 创建群发任务
async create(data: Partial<GroupPush>): Promise<ApiResponse<GroupPush>> {
const response = await fetch(`${API_BASE}/group-push`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取群发任务列表
async getList(params: {
page?: number
pageSize?: number
status?: string
}): Promise<ApiResponse<PaginatedResponse<GroupPush>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/group-push?${queryString.toString()}`)
return response.json()
},
// 获取群发任务详情
async getById(id: string): Promise<ApiResponse<GroupPush>> {
const response = await fetch(`${API_BASE}/group-push/${id}`)
return response.json()
},
// 更新群发任务
async update(id: string, data: Partial<GroupPush>): Promise<ApiResponse<GroupPush>> {
const response = await fetch(`${API_BASE}/group-push/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除群发任务
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/group-push/${id}`, {
method: "DELETE",
})
return response.json()
},
},
// 自动点赞API
autoLike: {
// 创建自动点赞任务
async create(data: Partial<AutoLike>): Promise<ApiResponse<AutoLike>> {
const response = await fetch(`${API_BASE}/auto-like`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取自动点赞任务列表
async getList(params: {
page?: number
pageSize?: number
status?: string
}): Promise<ApiResponse<PaginatedResponse<AutoLike>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/auto-like?${queryString.toString()}`)
return response.json()
},
// 获取自动点赞任务详情
async getById(id: string): Promise<ApiResponse<AutoLike>> {
const response = await fetch(`${API_BASE}/auto-like/${id}`)
return response.json()
},
// 更新自动点赞任务
async update(id: string, data: Partial<AutoLike>): Promise<ApiResponse<AutoLike>> {
const response = await fetch(`${API_BASE}/auto-like/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除自动点赞任务
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/auto-like/${id}`, {
method: "DELETE",
})
return response.json()
},
},
// 自动建群API
autoGroup: {
// 创建自动建群任务
async create(data: Partial<AutoGroup>): Promise<ApiResponse<AutoGroup>> {
const response = await fetch(`${API_BASE}/auto-group`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 获取自动建群任务列表
async getList(params: {
page?: number
pageSize?: number
status?: string
}): Promise<ApiResponse<PaginatedResponse<AutoGroup>>> {
const queryString = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
queryString.append(key, String(value))
}
})
const response = await fetch(`${API_BASE}/auto-group?${queryString.toString()}`)
return response.json()
},
// 获取自动建群任务详情
async getById(id: string): Promise<ApiResponse<AutoGroup>> {
const response = await fetch(`${API_BASE}/auto-group/${id}`)
return response.json()
},
// 更新自动建群任务
async update(id: string, data: Partial<AutoGroup>): Promise<ApiResponse<AutoGroup>> {
const response = await fetch(`${API_BASE}/auto-group/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
})
return response.json()
},
// 删除自动建群任务
async delete(id: string): Promise<ApiResponse<void>> {
const response = await fetch(`${API_BASE}/auto-group/${id}`, {
method: "DELETE",
})
return response.json()
},
},
// 工作台任务数据类型
export interface WorkspaceTask {
id: string
name: string
type: WorkspaceTaskType
status: WorkspaceTaskStatus
progress: number
deviceCount: number
wechatCount: number
targetCount: number
completedCount: number
successRate: number
createTime: string
startTime?: string
endTime?: string
lastRunTime?: string
nextRunTime?: string
settings: Record<string, any>
tags: string[]
creator: string
description?: string
}
// 工作台统计数据
export interface WorkspaceStats {
totalTasks: number
runningTasks: number
completedTasks: number
failedTasks: number
todayCompleted: number
totalCompleted: number
averageSuccessRate: number
}
// 任务创建参数
export interface CreateTaskParams {
name: string
type: WorkspaceTaskType
deviceIds: string[]
wechatIds: string[]
settings: Record<string, any>
tags?: string[]
description?: string
scheduleTime?: string
}
// 统一的API请求客户端
async function apiRequest<T>(url: string, options: RequestInit = {}): Promise<T> {
try {
const token = localStorage.getItem("ckb_token")
const headers: Record<string, string> = {
"Content-Type": "application/json",
Accept: "application/json",
...((options.headers as Record<string, string>) || {}),
}
if (token) {
headers["Authorization"] = `Bearer ${token}`
}
console.log("发送工作台API请求:", url)
const response = await fetch(url, {
...options,
headers,
mode: "cors",
})
console.log("工作台API响应状态:", response.status, response.statusText)
if (!response.ok) {
if (response.status === 401) {
if (typeof window !== "undefined") {
localStorage.removeItem("ckb_token")
localStorage.removeItem("ckb_user")
}
}
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
}
const contentType = response.headers.get("content-type")
if (!contentType || !contentType.includes("application/json")) {
throw new Error("服务器返回了非JSON格式的数据")
}
const data = await response.json()
console.log("工作台API响应数据:", data)
if (data.code && data.code !== 200 && data.code !== 0) {
throw new Error(data.message || "请求失败")
}
return data.data || data
} catch (error) {
console.error("工作台API请求失败:", error)
throw error
}
}
/**
* 获取工作台任务列表
*/
export async function getWorkspaceTasks(): Promise<WorkspaceTask[]> {
return apiRequest<WorkspaceTask[]>(`${API_BASE_URL}/v1/workspace/tasks`)
}
/**
* 获取工作台统计数据
*/
export async function getWorkspaceStats(): Promise<WorkspaceStats> {
return apiRequest<WorkspaceStats>(`${API_BASE_URL}/v1/workspace/stats`)
}
/**
* 获取单个任务详情
*/
export async function getWorkspaceTask(id: string): Promise<WorkspaceTask> {
return apiRequest<WorkspaceTask>(`${API_BASE_URL}/v1/workspace/tasks/${id}`)
}
/**
* 创建工作台任务
*/
export async function createWorkspaceTask(
params: CreateTaskParams,
): Promise<{ success: boolean; message: string; id?: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks`, {
method: "POST",
body: JSON.stringify(params),
})
}
/**
* 更新工作台任务
*/
export async function updateWorkspaceTask(
id: string,
params: Partial<CreateTaskParams>,
): Promise<{ success: boolean; message: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}`, {
method: "PUT",
body: JSON.stringify(params),
})
}
/**
* 删除工作台任务
*/
export async function deleteWorkspaceTask(id: string): Promise<{ success: boolean; message: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}`, {
method: "DELETE",
})
}
/**
* 启动工作台任务
*/
export async function startWorkspaceTask(id: string): Promise<{ success: boolean; message: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}/start`, {
method: "POST",
})
}
/**
* 停止工作台任务
*/
export async function stopWorkspaceTask(id: string): Promise<{ success: boolean; message: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}/stop`, {
method: "POST",
})
}
/**
* 暂停工作台任务
*/
export async function pauseWorkspaceTask(id: string): Promise<{ success: boolean; message: string }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}/pause`, {
method: "POST",
})
}
/**
* 获取任务运行日志
*/
export async function getWorkspaceTaskLogs(
id: string,
page = 1,
limit = 20,
): Promise<{
logs: Array<{
id: string
timestamp: string
level: "info" | "warning" | "error"
message: string
details?: any
}>
total: number
page: number
limit: number
}> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}/logs?page=${page}&limit=${limit}`)
}
/**
* 获取任务执行报告
*/
export async function getWorkspaceTaskReport(
id: string,
dateRange?: { start: string; end: string },
): Promise<{
summary: {
totalExecutions: number
successfulExecutions: number
failedExecutions: number
averageExecutionTime: number
successRate: number
}
dailyStats: Array<{
date: string
executions: number
successes: number
failures: number
successRate: number
}>
deviceStats: Array<{
deviceId: string
deviceName: string
executions: number
successes: number
failures: number
successRate: number
}>
}> {
const queryString = dateRange ? `?start=${dateRange.start}&end=${dateRange.end}` : ""
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/${id}/report${queryString}`)
}
/**
* 批量操作任务
*/
export async function batchOperateWorkspaceTasks(
taskIds: string[],
operation: "start" | "stop" | "pause" | "delete",
): Promise<{ success: boolean; message: string; results: Array<{ id: string; success: boolean; message: string }> }> {
return apiRequest(`${API_BASE_URL}/v1/workspace/tasks/batch`, {
method: "POST",
body: JSON.stringify({
taskIds,
operation,
}),
})
}