- 新增 game.story.volume / game.story.chapter 模型 + 后台菜单视图 - 新增 /game/api/story(目录) 与 /game/api/story/chapter/<id>(正文) 接口 - 三块补充 Odoo 默认种子数据(剧情 2 卷 5 章、论坛 5 帖、公告 4 条) - 前端:剧情改造为左目录 + 右正文的小说阅读器;论坛改为登录后可见(auth-only);论坛/公告调整为竖排阅读布局
103 lines
3.7 KiB
JavaScript
103 lines
3.7 KiB
JavaScript
// 宇森游戏 · 前端与 Odoo 通信层
|
||
// 本地调试:前端 8888 -> Odoo 8069(跨域,带调试 CORS 头)
|
||
// 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。
|
||
// 说明:odoo.conf 已 db_name=yt_game 钉死库,URL 上的 ?db= 形同虚设,
|
||
// 请求一律落到 yt_game;下列 game/* 沿用统一 API_CONFIG,yt_world/* 单独带 ?db=yt_game。
|
||
|
||
const API_CONFIG = {
|
||
base: (location.hostname === '127.0.0.1' && location.port === '8888')
|
||
? 'http://127.0.0.1:8069'
|
||
: (location.hostname === 'localhost' && location.port === '8888')
|
||
? 'http://127.0.0.1:8069'
|
||
: '',
|
||
db: (location.hostname === '127.0.0.1' && location.port === '8888') ? 'study' : 'game',
|
||
};
|
||
|
||
const _cred = API_CONFIG.base ? 'include' : 'same-origin';
|
||
|
||
function _url(path) {
|
||
return `${API_CONFIG.base}${path}?db=${API_CONFIG.db}`;
|
||
}
|
||
|
||
const API = {
|
||
async me() {
|
||
return (await fetch(_url('/game/api/me'), { credentials: _cred })).json();
|
||
},
|
||
async login(login, password) {
|
||
return (await fetch(_url('/game/api/login'), {
|
||
method: 'POST', credentials: _cred,
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ login, password }),
|
||
})).json();
|
||
},
|
||
async register(payload) {
|
||
return (await fetch(_url('/game/api/register'), {
|
||
method: 'POST', credentials: _cred,
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(payload),
|
||
})).json();
|
||
},
|
||
async logout() {
|
||
return (await fetch(_url('/game/api/logout'), {
|
||
method: 'POST', credentials: _cred,
|
||
})).json();
|
||
},
|
||
async codex() {
|
||
return (await fetch(_url('/game/api/codex'), { credentials: _cred })).json();
|
||
},
|
||
async rules() {
|
||
return (await fetch(_url('/game/api/rules'), { credentials: _cred })).json();
|
||
},
|
||
async currencies() {
|
||
return (await fetch(_url('/game/api/currencies'), { credentials: _cred })).json();
|
||
},
|
||
async pages() {
|
||
return (await fetch(_url('/game/api/pages'), { credentials: _cred })).json();
|
||
},
|
||
async threads() {
|
||
return (await fetch(_url('/game/api/threads'), { credentials: _cred })).json();
|
||
},
|
||
async announcements() {
|
||
return (await fetch(_url('/game/api/announcements'), { credentials: _cred })).json();
|
||
},
|
||
async story() {
|
||
return (await fetch(_url('/game/api/story'), { credentials: _cred })).json();
|
||
},
|
||
async storyChapter(cid) {
|
||
return (await fetch(_url('/game/api/story/chapter/' + cid), { credentials: _cred })).json();
|
||
},
|
||
// ---------- 沙盘记忆(yt_world 模块) ----------
|
||
async world() {
|
||
return (await fetch('/yt_world/api/world?db=yt_game', { credentials: 'same-origin' })).json();
|
||
},
|
||
async saveTiles(tiles) {
|
||
return (await fetch('/yt_world/api/tiles/save?db=yt_game', {
|
||
method: 'POST', credentials: 'same-origin',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ tiles }),
|
||
})).json();
|
||
},
|
||
async saveSettings(settings) {
|
||
return (await fetch('/yt_world/api/settings?db=yt_game', {
|
||
method: 'POST', credentials: 'same-origin',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ settings }),
|
||
})).json();
|
||
},
|
||
// ---------- 世界数据 / 包裹(后端接口预留:yt_world 暂未实现路由,前端 mock 兜底) ----------
|
||
async worldData() {
|
||
try {
|
||
const r = await fetch('/yt_world/api/data?db=yt_game', { credentials: 'same-origin' });
|
||
if (!r.ok) return null;
|
||
return await r.json();
|
||
} catch (e) { return null; }
|
||
},
|
||
async inventory() {
|
||
try {
|
||
const r = await fetch('/yt_world/api/inventory?db=yt_game', { credentials: 'same-origin' });
|
||
if (!r.ok) return null;
|
||
return await r.json();
|
||
} catch (e) { return null; }
|
||
},
|
||
};
|