feat: 锁定边界环、聊天框改版、锁定遮罩覆盖侧面

This commit is contained in:
李鹏宇 2026-07-27 08:51:27 +08:00
parent 931b0dbe31
commit bc9b9411d7
2 changed files with 1076 additions and 312 deletions

View File

@ -1,27 +1,41 @@
// 宇森游戏 · 前端与 Odoo 通信层 // 宇森游戏 · 前端与 Odoo 通信层
// 本地调试:前端 8888 -> Odoo 8069跨域带调试 CORS 头) // 本地调试:前端 8080/8888 -> Odoo 8069跨域带调试 CORS 头)
// 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。 // 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。
// 库名说明:本地 Odoo 用 odoo.conf 钉死 yt_game线上游戏库名为 gamedbfilter 不含 yt_game // 库名说明:本地 Odoo 用 odoo.conf 钉死 yt_game线上游戏库名为 gamedbfilter 不含 yt_game
// game/* 走统一 API_CONFIG.dbyt_world/* 单独带 ?db=,按 WORLD_DB 区分本地/线上,避免 git 同步互相覆盖。 // game/* 走统一 API_CONFIG.dbyt_world/* 单独带 ?db=,按 WORLD_DB 区分本地/线上,避免 git 同步互相覆盖。
const _isLocalDev = () =>
location.hostname === '127.0.0.1' || location.hostname === 'localhost';
const _isDevPort = (port) =>
location.port === String(port) ||
// 某些环境(如 Python http.server可能不设 port默认 80或用空串
(port === 80 && (location.port === '' || location.port === '80'));
const API_CONFIG = { const API_CONFIG = {
base: (location.hostname === '127.0.0.1' && location.port === '8888') base: (_isLocalDev() && (_isDevPort(8080) || _isDevPort(8888)))
? 'http://127.0.0.1:8069' ? `http://${location.hostname}:8069`
: (location.hostname === 'localhost' && location.port === '8888') : '',
? 'http://127.0.0.1:8069' db: (_isLocalDev() && (_isDevPort(8080) || _isDevPort(8888))) ? 'study' : 'game',
: '',
db: (location.hostname === '127.0.0.1' && location.port === '8888') ? 'study' : 'game',
}; };
// 世界(yt_world)所在库:本地 Odoo 钉 yt_game线上游戏库名为 game。按域名自适应git 同步不冲突。 // 世界(yt_world)所在库:本地 Odoo 钉 yt_game线上游戏库名为 game。按域名自适应git 同步不冲突。
const WORLD_DB = (location.hostname === '127.0.0.1' || location.hostname === 'localhost') ? 'yt_game' : 'game'; const WORLD_DB = _isLocalDev() ? 'yt_game' : 'game';
// Odoo 后端基础 URL世界 API 专用,兼容本地跨域 / 生产同域)
const WORLD_BASE = API_CONFIG.base || '';
const _cred = API_CONFIG.base ? 'include' : 'same-origin'; const _cred = API_CONFIG.base ? 'include' : 'same-origin';
const _wcred = WORLD_BASE ? 'include' : 'same-origin';
function _url(path) { function _url(path) {
return `${API_CONFIG.base}${path}?db=${API_CONFIG.db}`; return `${API_CONFIG.base}${path}?db=${API_CONFIG.db}`;
} }
function _worldUrl(path) {
return `${WORLD_BASE}${path}?db=${WORLD_DB}`;
}
const API = { const API = {
async me() { async me() {
return (await fetch(_url('/game/api/me'), { credentials: _cred })).json(); return (await fetch(_url('/game/api/me'), { credentials: _cred })).json();
@ -71,25 +85,25 @@ const API = {
}, },
// ---------- 沙盘记忆yt_world 模块) ---------- // ---------- 沙盘记忆yt_world 模块) ----------
async world() { async world() {
return (await fetch('/yt_world/api/world?db=' + WORLD_DB, { credentials: 'same-origin' })).json(); return (await fetch(_worldUrl('/yt_world/api/world'), { credentials: _wcred })).json();
}, },
async saveTiles(tiles) { async saveTiles(tiles) {
return (await fetch('/yt_world/api/tiles/save?db=' + WORLD_DB, { return (await fetch(_worldUrl('/yt_world/api/tiles/save'), {
method: 'POST', credentials: 'same-origin', method: 'POST', credentials: _wcred,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tiles }), body: JSON.stringify({ tiles }),
})).json(); })).json();
}, },
async saveSettings(settings) { async saveSettings(settings) {
return (await fetch('/yt_world/api/settings?db=' + WORLD_DB, { return (await fetch(_worldUrl('/yt_world/api/settings'), {
method: 'POST', credentials: 'same-origin', method: 'POST', credentials: _wcred,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ settings }), body: JSON.stringify({ settings }),
})).json(); })).json();
}, },
async renameWorld(name) { async renameWorld(name) {
return (await fetch('/yt_world/api/world/rename?db=' + WORLD_DB, { return (await fetch(_worldUrl('/yt_world/api/world/rename'), {
method: 'POST', credentials: 'same-origin', method: 'POST', credentials: _wcred,
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name }), body: JSON.stringify({ name }),
})).json(); })).json();
@ -97,14 +111,14 @@ const API = {
// ---------- 世界数据 / 包裹后端接口预留yt_world 暂未实现路由,前端 mock 兜底) ---------- // ---------- 世界数据 / 包裹后端接口预留yt_world 暂未实现路由,前端 mock 兜底) ----------
async worldData() { async worldData() {
try { try {
const r = await fetch('/yt_world/api/data?db=' + WORLD_DB, { credentials: 'same-origin' }); const r = await fetch(_worldUrl('/yt_world/api/data'), { credentials: _wcred });
if (!r.ok) return null; if (!r.ok) return null;
return await r.json(); return await r.json();
} catch (e) { return null; } } catch (e) { return null; }
}, },
async inventory() { async inventory() {
try { try {
const r = await fetch('/yt_world/api/inventory?db=' + WORLD_DB, { credentials: 'same-origin' }); const r = await fetch(_worldUrl('/yt_world/api/inventory'), { credentials: _wcred });
if (!r.ok) return null; if (!r.ok) return null;
return await r.json(); return await r.json();
} catch (e) { return null; } } catch (e) { return null; }

1338
world.html

File diff suppressed because it is too large Load Diff