97054a9699
- user 端:课程/活动/报名/测评/政策/调研 - 后端已并入 server-core/app/training,/api/* 走 opc.pinesound.cn
119 lines
4.7 KiB
JavaScript
119 lines
4.7 KiB
JavaScript
/**
|
||
* 运营 / 管理 API 服务(ops service)
|
||
* -------------------------------------------------------------
|
||
* 管理端点(/pine 后台)需要登录 token;公开端点(当期排期)无需。
|
||
* 对接 server/mock-api.mjs。
|
||
*/
|
||
const API_BASE = 'https://opc.pinesound.cn'; // 云超服 FastAPI 后端
|
||
const TOKEN_KEY = 'pine_token';
|
||
import { cached } from './cache';
|
||
|
||
function authHeaders() {
|
||
const t = localStorage.getItem(TOKEN_KEY);
|
||
return { 'Content-Type': 'application/json', ...(t ? { Authorization: `Bearer ${t}` } : {}) };
|
||
}
|
||
|
||
async function api(method, path, body) {
|
||
const res = await fetch(`${API_BASE}${path}`, {
|
||
method,
|
||
headers: authHeaders(),
|
||
body: body === undefined ? undefined : JSON.stringify(body)
|
||
});
|
||
const data = await res.json().catch(() => ({}));
|
||
if (!res.ok || data.ok === false) throw new Error(data.error || '请求失败');
|
||
return data;
|
||
}
|
||
|
||
/* ---------- 后台管理 API(需登录) ---------- */
|
||
export const ops = {
|
||
stats: () => api('GET', '/api/ops/stats'),
|
||
bookings: () => api('GET', '/api/bookings'),
|
||
updateBooking: (id, status) => api('PATCH', `/api/bookings/${id}`, { status }),
|
||
updateBookingAudit: (id, auditStatus) => api('PATCH', `/api/bookings/${id}`, { auditStatus }),
|
||
deleteBooking: (id) => api('DELETE', `/api/bookings/${id}`),
|
||
bookAudit: (audit) => api('GET', `/api/bookings?audit=${audit}`),
|
||
events: () => api('GET', '/api/events'),
|
||
createEvent: (data) => api('POST', '/api/events', data),
|
||
updateEvent: (id, data) => api('PUT', `/api/events/${id}`, data),
|
||
deleteEvent: (id) => api('DELETE', `/api/events/${id}`),
|
||
tests: () => api('GET', '/api/tests'),
|
||
policyLogs: () => api('GET', '/api/policy-logs'),
|
||
planLogs: () => api('GET', '/api/plan-logs'),
|
||
surveyLogs: () => api('GET', '/api/survey-logs')
|
||
};
|
||
|
||
/* ---------- 公开:上报政策测评 / 启动流程结果(失败不影响用户) ---------- */
|
||
export async function reportPolicyLog(data) {
|
||
try { await api('POST', '/api/policy-logs', data); } catch { /* noop */ }
|
||
}
|
||
export async function reportPlanLog(data) {
|
||
try { await api('POST', '/api/plan-logs', data); } catch { /* noop */ }
|
||
}
|
||
/* 公开:上报 OPC 创业伙伴调研(匿名可提交;失败不影响用户) */
|
||
export async function reportSurveyLog(data) {
|
||
try { await api('POST', '/api/survey-logs', data); } catch { /* noop */ }
|
||
}
|
||
/* 管理端:查看调研记录 */
|
||
export async function getSurveyLogs() {
|
||
return api('GET', '/api/survey-logs');
|
||
}
|
||
|
||
/* ---------- 公开:当期排期(无后端时返回 null,前端降级静态排期) ---------- */
|
||
export async function getCurrentEvents() {
|
||
return cached('events:current', 30000, async () => {
|
||
try {
|
||
const res = await fetch(`${API_BASE}/api/events?current=1`);
|
||
const data = await res.json().catch(() => ({}));
|
||
if (!res.ok || !data.ok) return null;
|
||
return data;
|
||
} catch {
|
||
return null;
|
||
}
|
||
});
|
||
}
|
||
|
||
/* ---------- 图像上传(管理端,multipart) ---------- */
|
||
export async function uploadImage(file) {
|
||
const token = localStorage.getItem(TOKEN_KEY);
|
||
const fd = new FormData();
|
||
fd.append('file', file);
|
||
const res = await fetch(`${API_BASE}/api/upload`, {
|
||
method: 'POST',
|
||
headers: { Authorization: `Bearer ${token}` },
|
||
body: fd
|
||
});
|
||
const data = await res.json().catch(() => ({}));
|
||
if (!res.ok || !data.ok) throw new Error(data.error || '上传失败');
|
||
return data; // { ok, url }
|
||
}
|
||
|
||
/* ---------- 公开:政策测评(题目下发 + 结果生成,后端驱动) ---------- */
|
||
export async function getPolicyQuestions() {
|
||
return cached('policy:questions', 30000, async () => {
|
||
try { const r = await api('GET', '/api/policy/questions'); return r.questions || []; } catch { return []; }
|
||
});
|
||
}
|
||
export async function calcPolicy(answers) {
|
||
try { const r = await api('POST', '/api/policy/calculate', { answers }); return r.result; } catch { return null; }
|
||
}
|
||
|
||
/* ---------- 公开:启动流程(配置 + 生成,后端驱动) ---------- */
|
||
export async function getPlanConfig() {
|
||
return cached('plan:config', 30000, async () => {
|
||
try { const r = await api('GET', '/api/plan/config'); return r; } catch { return { regions: [], status: [] }; }
|
||
});
|
||
}
|
||
export async function genPlan(opt) {
|
||
try { const r = await api('POST', '/api/plan/generate', opt); return r.plan || []; } catch { return []; }
|
||
}
|
||
|
||
/* ---------- 公开:调研(题目下发 + 提交,后端驱动) ---------- */
|
||
export async function getSurveyQuestions() {
|
||
return cached('survey:questions', 30000, async () => {
|
||
try { const r = await api('GET', '/api/survey/questions'); return r; } catch { return null; }
|
||
});
|
||
}
|
||
export async function submitSurvey(data) {
|
||
try { return await api('POST', '/api/survey/submit', data); } catch { return null; }
|
||
}
|