School Panda 智胜诟皋衚

à¹‚àž£àž‡à¹€àž£àžµàž¢àž™àžªàž­àž™àž àž²àž©àž²àžˆàžµàž™à¹àžžàž™àž”à¹‰àž² · 五月诟皋衚

📅 诟皋衚
📋 列衚
🔍 空䜍
📱 家长回应
👩‍🏫 老垈
⚙ 讟眮
☁ 云同步

🖚 打印诟皋衚

星期时闎孊生诟皋老垈教宀类型状态操䜜

🔍 新孊生空䜍查扟

⚠ 时闎冲突检查

📱 家长回应

已毕䞚/停诟的孊生䞍䌚出现圚列衚里。

👩‍🏫 老垈管理

🏫 教宀列衚 可自由添加删陀

添加诟皋时教宀栏䌚星瀺这里的选项也可以盎接蟓入新名称。

📚 诟皋类型 可自由添加删陀

添加诟皋时类型栏䌚星瀺这里的选项也可以盎接蟓入新类型。

🗑 数据管理

☁ 云同步状态

状态未配眮
䞊次同步—
本地修改—
云端修改—
讟倇 ID—

⚙ 同步配眮

Worker URLhttps://spring-disk-2255.schoolpanda-520.workers.dev
Sync Keyschoolpanda8888sync

莝莝老垈那蟹填䞀样的配眮䞀蟹自劚同步。

🔧 Worker 曎新代码

把䞋面代码莎到 Cloudflare Workers 猖蟑噚点 Deploy。

// ================================================================ // School Panda 统䞀云同步 Worker // 同时支持诟时系统 + 诟皋衚系统 // 绑定 KV: SP_KV环境变量: SYNC_KEY // // 数据 key // 诟时系统 → school_panda_data (原有䞍变) // 诟皋衚 → school_panda_timetable_data (新增) // ================================================================ const ALLOWED_KEYS = ["school_panda_data", "school_panda_timetable_data"]; export default { async fetch(request, env) { const cors = { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, X-Sync-Key, X-Device-Id, X-Data-Key", "Access-Control-Max-Age": "86400", }; if (request.method === "OPTIONS") { return new Response(null, { headers: cors }); } // 密钥验证 const key = request.headers.get("X-Sync-Key"); if (!key || key !== env.SYNC_KEY) { return new Response(JSON.stringify({ error: "unauthorized" }), { status: 401, headers: { ...cors, "Content-Type": "application/json" }, }); } // 读取 dataKey由客户端指定默讀兌容诟时系统 const url = new URL(request.url); const dataKey = request.headers.get("X-Data-Key") || url.searchParams.get("dataKey") || "school_panda_data"; // 安党癜名单防止乱写 KV if (!ALLOWED_KEYS.includes(dataKey)) { return new Response(JSON.stringify({ error: "invalid dataKey" }), { status: 400, headers: { ...cors, "Content-Type": "application/json" }, }); } try { if (request.method === "GET") { const stored = await env.SP_KV.get(dataKey, "json"); return new Response(JSON.stringify(stored || { data: null, modified: 0 }), { headers: { ...cors, "Content-Type": "application/json" }, }); } if (request.method === "POST") { const body = await request.json(); if (!body || !body.data) { return new Response(JSON.stringify({ error: "invalid body" }), { status: 400, headers: { ...cors, "Content-Type": "application/json" }, }); } const payload = { data: body.data, modified: body.modified || Date.now(), device: body.device || "unknown", updatedAt: Date.now(), }; await env.SP_KV.put(dataKey, JSON.stringify(payload)); return new Response(JSON.stringify({ ok: true, modified: payload.modified }), { headers: { ...cors, "Content-Type": "application/json" }, }); } return new Response(JSON.stringify({ error: "method not allowed" }), { status: 405, headers: { ...cors, "Content-Type": "application/json" }, }); } catch (e) { return new Response(JSON.stringify({ error: e.message }), { status: 500, headers: { ...cors, "Content-Type": "application/json" }, }); } }, };