auto_trade_sys/frontend/src/services/api.js
薇薇安 aca1cf26b7 a
2026-01-23 21:07:35 +08:00

778 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 如果设置了VITE_API_URL环境变量使用它否则在开发环境使用相对路径通过vite代理生产环境使用默认值
const API_BASE_URL = import.meta.env.VITE_API_URL || (import.meta.env.DEV ? '' : 'http://localhost:8000');
// 登录鉴权JWT tokenAuthorization: Bearer xxx
const AUTH_TOKEN_STORAGE_KEY = 'ats_auth_token';
export const getAuthToken = () => {
try {
return localStorage.getItem(AUTH_TOKEN_STORAGE_KEY) || '';
} catch (e) {
return '';
}
};
export const setAuthToken = (token) => {
try {
const t = String(token || '').trim();
if (!t) {
localStorage.removeItem(AUTH_TOKEN_STORAGE_KEY);
return;
}
localStorage.setItem(AUTH_TOKEN_STORAGE_KEY, t);
} catch (e) {
// ignore
}
};
export const clearAuthToken = () => setAuthToken('');
// 多账号:前端通过 Header 选择账号(默认 1
const ACCOUNT_ID_STORAGE_KEY = 'ats_account_id';
export const getCurrentAccountId = () => {
try {
const v = localStorage.getItem(ACCOUNT_ID_STORAGE_KEY);
const n = parseInt(v || '1', 10);
return Number.isFinite(n) && n > 0 ? n : 1;
} catch (e) {
return 1;
}
};
export const setCurrentAccountId = (accountId) => {
try {
const n = parseInt(String(accountId || '1'), 10);
localStorage.setItem(ACCOUNT_ID_STORAGE_KEY, String(Number.isFinite(n) && n > 0 ? n : 1));
} catch (e) {
// ignore
}
};
export const clearCurrentAccountId = () => {
try {
localStorage.removeItem(ACCOUNT_ID_STORAGE_KEY);
} catch (e) {
// ignore
}
};
const withAuthHeaders = (headers = {}) => {
const token = getAuthToken();
if (!token) return { ...headers };
return { ...headers, Authorization: `Bearer ${token}` };
};
// 全局变量,用于存储当前的 accountId从 Redux store 同步)
let currentAccountIdFromStore = null;
// 设置当前 accountId由 Redux store 调用)
export const setCurrentAccountIdFromStore = (accountId) => {
currentAccountIdFromStore = accountId;
// 同时更新 localStorage 保持同步
if (accountId) {
setCurrentAccountId(accountId);
}
};
const withAccountHeaders = (headers = {}, accountIdOverride = null) => {
// 优先使用传入的参数,其次使用 Redux store 的值,最后从 localStorage 读取
let aid;
if (accountIdOverride !== null) {
aid = accountIdOverride;
} else if (currentAccountIdFromStore !== null) {
aid = currentAccountIdFromStore;
} else {
// 从 localStorage 读取(兜底)
aid = getCurrentAccountId();
// 如果从 localStorage 读取到了值,同步到全局变量(避免下次再读 localStorage
if (aid) {
currentAccountIdFromStore = aid;
}
}
return withAuthHeaders({ ...headers, 'X-Account-Id': String(aid) });
};
// 构建API URL的辅助函数避免双斜杠和格式问题
const buildUrl = (path) => {
const baseUrl = API_BASE_URL.endsWith('/') ? API_BASE_URL.slice(0, -1) : API_BASE_URL;
const cleanPath = path.startsWith('/') ? path : `/${path}`;
return baseUrl ? `${baseUrl}${cleanPath}` : cleanPath;
};
export const api = {
// 登录
login: async (username, password) => {
const response = await fetch(buildUrl('/api/auth/login'), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '登录失败' }));
throw new Error(error.detail || '登录失败');
}
const data = await response.json();
if (data?.access_token) setAuthToken(data.access_token);
return data;
},
me: async () => {
const response = await fetch(buildUrl('/api/auth/me'), { headers: withAuthHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取登录信息失败' }));
throw new Error(error.detail || '获取登录信息失败');
}
return response.json();
},
// 公共状态(非管理员也可用)
getPublicStatus: async () => {
const response = await fetch(buildUrl('/api/public/status'))
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取服务状态失败' }))
throw new Error(error.detail || '获取服务状态失败')
}
return response.json()
},
// 账号管理
getAccounts: async () => {
const response = await fetch(buildUrl('/api/accounts'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取账号列表失败' }));
throw new Error(error.detail || '获取账号列表失败');
}
return response.json();
},
createAccount: async (data) => {
const response = await fetch(buildUrl('/api/accounts'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data || {}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '创建账号失败' }));
throw new Error(error.detail || '创建账号失败');
}
return response.json();
},
updateAccount: async (accountId, data) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}`), {
method: 'PUT',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data || {}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新账号失败' }));
throw new Error(error.detail || '更新账号失败');
}
return response.json();
},
updateAccountCredentials: async (accountId, data) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/credentials`), {
method: 'PUT',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data || {}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新账号密钥失败' }));
throw new Error(error.detail || '更新账号密钥失败');
}
return response.json();
},
// 交易进程(按账号;需要 owner 或 admin
getAccountTradingStatus: async (accountId) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/trading/status`), { headers: withAccountHeaders() })
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取交易进程状态失败' }))
throw new Error(error.detail || '获取交易进程状态失败')
}
return response.json()
},
startAccountTrading: async (accountId) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/trading/start`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '启动交易进程失败' }))
throw new Error(error.detail || '启动交易进程失败')
}
return response.json()
},
stopAccountTrading: async (accountId) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/trading/stop`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '停止交易进程失败' }))
throw new Error(error.detail || '停止交易进程失败')
}
return response.json()
},
restartAccountTrading: async (accountId) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/trading/restart`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '重启交易进程失败' }))
throw new Error(error.detail || '重启交易进程失败')
}
return response.json()
},
ensureAccountTradingProgram: async (accountId) => {
const response = await fetch(buildUrl(`/api/accounts/${accountId}/trading/ensure-program`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '生成/刷新 supervisor 配置失败' }))
throw new Error(error.detail || '生成/刷新 supervisor 配置失败')
}
return response.json()
},
// 配置管理
getConfigMeta: async () => {
const response = await fetch(buildUrl('/api/config/meta'), { headers: withAuthHeaders() })
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取配置元信息失败' }))
throw new Error(error.detail || '获取配置元信息失败')
}
return response.json()
},
// 全局配置:获取全局策略配置(管理员专用,独立于账户)
getGlobalConfigs: async () => {
const response = await fetch(buildUrl('/api/config/global'), {
headers: withAuthHeaders()
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取全局配置失败' }))
throw new Error(error.detail || '获取全局配置失败')
}
return response.json()
},
// 全局配置:批量更新全局策略配置(管理员专用)
updateGlobalConfigsBatch: async (configs) => {
const response = await fetch(buildUrl('/api/config/global/batch'), {
method: 'POST',
headers: withAuthHeaders({
'Content-Type': 'application/json'
}),
body: JSON.stringify(configs)
})
if (!response.ok) {
const error = await response.json()
throw new Error(error.detail || '更新全局配置失败')
}
return response.json()
},
getConfigs: async () => {
const response = await fetch(buildUrl('/api/config'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取配置失败' }));
throw new Error(error.detail || '获取配置失败');
}
return response.json();
},
getConfig: async (key) => {
const response = await fetch(buildUrl(`/api/config/${key}`), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取配置失败' }));
throw new Error(error.detail || '获取配置失败');
}
return response.json();
},
updateConfig: async (key, data) => {
const response = await fetch(buildUrl(`/api/config/${key}`), {
method: 'PUT',
headers: withAccountHeaders({'Content-Type': 'application/json'}),
body: JSON.stringify(data)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.detail || '更新配置失败');
}
return response.json();
},
updateConfigsBatch: async (configs) => {
const response = await fetch(buildUrl('/api/config/batch'), {
method: 'POST',
headers: withAccountHeaders({'Content-Type': 'application/json'}),
body: JSON.stringify(configs)
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '批量更新配置失败' }));
throw new Error(error.detail || '批量更新配置失败');
}
return response.json();
},
// 检查配置可行性
checkConfigFeasibility: async () => {
const response = await fetch(buildUrl('/api/config/feasibility-check'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '检查配置可行性失败' }));
throw new Error(error.detail || '检查配置可行性失败');
}
return response.json();
},
// 交易记录
getTrades: async (params = {}) => {
const query = new URLSearchParams(params).toString();
const url = query ? `${buildUrl('/api/trades')}?${query}` : buildUrl('/api/trades');
const response = await fetch(url, {
method: 'GET',
headers: {
...withAccountHeaders({ 'Content-Type': 'application/json' }),
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取交易记录失败' }));
throw new Error(error.detail || '获取交易记录失败');
}
return response.json();
},
getTradeStats: async (params = {}) => {
const query = new URLSearchParams(params).toString();
const url = query ? `${buildUrl('/api/trades/stats')}?${query}` : buildUrl('/api/trades/stats');
const response = await fetch(url, {
method: 'GET',
headers: {
...withAccountHeaders({ 'Content-Type': 'application/json' }),
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取交易统计失败' }));
throw new Error(error.detail || '获取交易统计失败');
}
return response.json();
},
// 统计
getPerformance: async (days = 7) => {
const response = await fetch(buildUrl(`/api/stats/performance?days=${days}`), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取性能统计失败' }));
throw new Error(error.detail || '获取性能统计失败');
}
return response.json();
},
getDashboard: async () => {
const response = await fetch(buildUrl('/api/dashboard'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取仪表板数据失败' }));
throw new Error(error.detail || '获取仪表板数据失败');
}
return response.json();
},
// 平仓操作
closePosition: async (symbol) => {
const response = await fetch(buildUrl(`/api/account/positions/${symbol}/close`), {
method: 'POST',
headers: {
...withAccountHeaders({ 'Content-Type': 'application/json' }),
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '平仓失败' }));
throw new Error(error.detail || '平仓失败');
}
return response.json();
},
// 一键全平(平仓所有持仓)
closeAllPositions: async () => {
const response = await fetch(buildUrl(`/api/account/positions/close-all`), {
method: 'POST',
headers: {
...withAccountHeaders({ 'Content-Type': 'application/json' }),
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '一键全平失败' }));
throw new Error(error.detail || '一键全平失败');
}
return response.json();
},
// 补挂止盈止损(交易所保护单)
ensurePositionSLTP: async (symbol) => {
const response = await fetch(buildUrl(`/api/account/positions/${symbol}/sltp/ensure`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '补挂止盈止损失败' }));
throw new Error(error.detail || '补挂止盈止损失败');
}
return response.json();
},
ensureAllPositionsSLTP: async (limit = 50) => {
const response = await fetch(buildUrl(`/api/account/positions/sltp/ensure-all?limit=${encodeURIComponent(limit)}`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '批量补挂止盈止损失败' }));
throw new Error(error.detail || '批量补挂止盈止损失败');
}
return response.json();
},
// 同步持仓状态
syncPositions: async () => {
const response = await fetch(buildUrl('/api/account/positions/sync'), {
method: 'POST',
headers: {
...withAccountHeaders({ 'Content-Type': 'application/json' }),
},
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '同步失败' }));
throw new Error(error.detail || '同步失败');
}
return response.json();
},
// 根据推荐信息手动开仓
openPositionFromRecommendation: async (symbol, entryPrice, stopLossPrice, direction, notionalUsdt, leverage = 10) => {
const params = new URLSearchParams({
entry_price: String(entryPrice),
stop_loss_price: String(stopLossPrice),
direction: direction,
notional_usdt: String(notionalUsdt),
leverage: String(leverage),
});
const response = await fetch(buildUrl(`/api/account/positions/${symbol}/open?${params}`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '开仓失败' }));
throw new Error(error.detail || '开仓失败');
}
return response.json();
},
// 交易推荐
getRecommendations: async (params = {}) => {
// 默认使用实时推荐
if (!params.type) {
params.type = 'realtime'
}
const query = new URLSearchParams(params).toString();
const url = query ? `${buildUrl('/api/recommendations')}?${query}` : buildUrl('/api/recommendations');
const response = await fetch(url, { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取推荐失败' }));
throw new Error(error.detail || '获取推荐失败');
}
return response.json();
},
bookmarkRecommendation: async (recommendationData) => {
const response = await fetch(buildUrl('/api/recommendations/bookmark'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(recommendationData)
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '标记推荐失败' }));
throw new Error(error.detail || '标记推荐失败');
}
return response.json();
},
getActiveRecommendations: async () => {
const response = await fetch(buildUrl('/api/recommendations/active'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取有效推荐失败' }));
throw new Error(error.detail || '获取有效推荐失败');
}
return response.json();
},
getRecommendation: async (id) => {
const response = await fetch(buildUrl(`/api/recommendations/${id}`), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取推荐详情失败' }));
throw new Error(error.detail || '获取推荐详情失败');
}
return response.json();
},
generateRecommendations: async (minSignalStrength = 5, maxRecommendations = 20) => {
const response = await fetch(
buildUrl(`/api/recommendations/generate?min_signal_strength=${minSignalStrength}&max_recommendations=${maxRecommendations}`),
{
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
}
);
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '生成推荐失败' }));
throw new Error(error.detail || '生成推荐失败');
}
return response.json();
},
markRecommendationExecuted: async (id, tradeId = null) => {
const response = await fetch(buildUrl(`/api/recommendations/${id}/execute`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ trade_id: tradeId }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '标记执行失败' }));
throw new Error(error.detail || '标记执行失败');
}
return response.json();
},
cancelRecommendation: async (id, notes = null) => {
const response = await fetch(buildUrl(`/api/recommendations/${id}/cancel`), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ notes }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '取消推荐失败' }));
throw new Error(error.detail || '取消推荐失败');
}
return response.json();
},
// 系统控制supervisor
clearSystemCache: async () => {
const response = await fetch(buildUrl('/api/system/clear-cache'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '清理缓存失败' }));
throw new Error(error.detail || '清理缓存失败');
}
return response.json();
},
getTradingSystemStatus: async () => {
const response = await fetch(buildUrl('/api/system/trading/status'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取交易系统状态失败' }));
throw new Error(error.detail || '获取交易系统状态失败');
}
return response.json();
},
startTradingSystem: async () => {
const response = await fetch(buildUrl('/api/system/trading/start'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '启动交易系统失败' }));
throw new Error(error.detail || '启动交易系统失败');
}
return response.json();
},
stopTradingSystem: async () => {
const response = await fetch(buildUrl('/api/system/trading/stop'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '停止交易系统失败' }));
throw new Error(error.detail || '停止交易系统失败');
}
return response.json();
},
restartTradingSystem: async () => {
const response = await fetch(buildUrl('/api/system/trading/restart'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '重启交易系统失败' }));
throw new Error(error.detail || '重启交易系统失败');
}
return response.json();
},
restartAllTradingSystems: async (opts = {}) => {
const params = new URLSearchParams()
if (opts?.prefix) params.set('prefix', String(opts.prefix))
if (opts?.include_default) params.set('include_default', 'true')
if (opts?.do_update === false) params.set('do_update', 'false')
const url = params.toString()
? `${buildUrl('/api/system/trading/restart-all')}?${params.toString()}`
: buildUrl('/api/system/trading/restart-all')
const response = await fetch(url, {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
})
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '批量重启失败' }))
throw new Error(error.detail || '批量重启失败')
}
return response.json()
},
// 后端控制uvicorn
getBackendStatus: async () => {
const response = await fetch(buildUrl('/api/system/backend/status'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取后端状态失败' }));
throw new Error(error.detail || '获取后端状态失败');
}
return response.json();
},
restartBackend: async () => {
const response = await fetch(buildUrl('/api/system/backend/restart'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '重启后端失败' }));
throw new Error(error.detail || '重启后端失败');
}
return response.json();
},
// 日志监控Redis List
getSystemLogs: async (params = {}) => {
const query = new URLSearchParams(params).toString();
const url = query ? `${buildUrl('/api/system/logs')}?${query}` : buildUrl('/api/system/logs');
const response = await fetch(url, { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取日志失败' }));
throw new Error(error.detail || '获取日志失败');
}
return response.json();
},
getLogsOverview: async () => {
const response = await fetch(buildUrl('/api/system/logs/overview'), { headers: withAccountHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取日志概览失败' }));
throw new Error(error.detail || '获取日志概览失败');
}
return response.json();
},
updateLogsConfig: async (data) => {
const response = await fetch(buildUrl('/api/system/logs/config'), {
method: 'PUT',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data || {}),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新日志配置失败' }));
throw new Error(error.detail || '更新日志配置失败');
}
return response.json();
},
writeLogsTest: async () => {
const response = await fetch(buildUrl('/api/system/logs/test-write'), {
method: 'POST',
headers: withAccountHeaders({ 'Content-Type': 'application/json' }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '写入测试日志失败' }));
throw new Error(error.detail || '写入测试日志失败');
}
return response.json();
},
// 管理员:获取用户列表
getUsers: async () => {
const response = await fetch(buildUrl('/api/admin/users'), { headers: withAuthHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取用户列表失败' }));
throw new Error(error.detail || '获取用户列表失败');
}
return response.json();
},
// 管理员:获取用户关联的账号列表
getUserAccounts: async (userId) => {
const response = await fetch(buildUrl(`/api/admin/users/${userId}/accounts`), { headers: withAuthHeaders() });
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '获取用户账号列表失败' }));
throw new Error(error.detail || '获取用户账号列表失败');
}
return response.json();
},
// 管理员:创建用户
createUser: async (data) => {
const response = await fetch(buildUrl('/api/admin/users'), {
method: 'POST',
headers: withAuthHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify(data),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '创建用户失败' }));
throw new Error(error.detail || '创建用户失败');
}
return response.json();
},
// 管理员:更新用户密码
updateUserPassword: async (userId, password) => {
const response = await fetch(buildUrl(`/api/admin/users/${userId}/password`), {
method: 'PUT',
headers: withAuthHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ password }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新密码失败' }));
throw new Error(error.detail || '更新密码失败');
}
return response.json();
},
// 管理员:更新用户角色
updateUserRole: async (userId, role) => {
const response = await fetch(buildUrl(`/api/admin/users/${userId}/role`), {
method: 'PUT',
headers: withAuthHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ role }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新角色失败' }));
throw new Error(error.detail || '更新角色失败');
}
return response.json();
},
// 管理员:更新用户状态
updateUserStatus: async (userId, status) => {
const response = await fetch(buildUrl(`/api/admin/users/${userId}/status`), {
method: 'PUT',
headers: withAuthHeaders({ 'Content-Type': 'application/json' }),
body: JSON.stringify({ status }),
});
if (!response.ok) {
const error = await response.json().catch(() => ({ detail: '更新状态失败' }));
throw new Error(error.detail || '更新状态失败');
}
return response.json();
},
};