fix: 注册页昵称随机生成 + 去园丁文案 + 后端校验昵称重复
- login.html: 移除副标题'你不是玩家,你是园丁。'
- login.html: 昵称输入框增加随机按钮(🎲),点击生成随机昵称
- login.html: 账号输入时不再自动同步昵称
- login.html: 提交按钮'创建园丁账号'改为'创建账号'
- game_api.py: 注册时校验 res.users.name 重复,返回'该昵称已被使用'
- assets/game-api.js: 沙盘/世界数据接口按本地/线上自适应 WORLD_DB
This commit is contained in:
parent
146da5e8e4
commit
f12cab0b53
@ -297,6 +297,8 @@ class GameApiController(http.Controller):
|
|||||||
User = request.env['res.users'].sudo()
|
User = request.env['res.users'].sudo()
|
||||||
if User.search([('login', '=', login)]):
|
if User.search([('login', '=', login)]):
|
||||||
return _json({'ok': False, 'error': '该账号已存在'})
|
return _json({'ok': False, 'error': '该账号已存在'})
|
||||||
|
if name and User.search([('name', '=', name)]):
|
||||||
|
return _json({'ok': False, 'error': '该昵称已被使用'})
|
||||||
try:
|
try:
|
||||||
portal = request.env.ref('base.group_portal')
|
portal = request.env.ref('base.group_portal')
|
||||||
user = User.create({
|
user = User.create({
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// 宇森游戏 · 前端与 Odoo 通信层
|
// 宇森游戏 · 前端与 Odoo 通信层
|
||||||
// 本地调试:前端 8888 -> Odoo 8069(跨域,带调试 CORS 头)
|
// 本地调试:前端 8888 -> Odoo 8069(跨域,带调试 CORS 头)
|
||||||
// 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。
|
// 生产部署:前端与 Odoo 同域,由 nginx 代理 /game/*。
|
||||||
// 说明:odoo.conf 已 db_name=yt_game 钉死库,URL 上的 ?db= 形同虚设,
|
// 库名说明:本地 Odoo 用 odoo.conf 钉死 yt_game;线上游戏库名为 game(dbfilter 不含 yt_game)。
|
||||||
// 请求一律落到 yt_game;下列 game/* 沿用统一 API_CONFIG,yt_world/* 单独带 ?db=yt_game。
|
// game/* 走统一 API_CONFIG.db;yt_world/* 单独带 ?db=,按 WORLD_DB 区分本地/线上,避免 git 同步互相覆盖。
|
||||||
|
|
||||||
const API_CONFIG = {
|
const API_CONFIG = {
|
||||||
base: (location.hostname === '127.0.0.1' && location.port === '8888')
|
base: (location.hostname === '127.0.0.1' && location.port === '8888')
|
||||||
@ -13,6 +13,9 @@ const API_CONFIG = {
|
|||||||
db: (location.hostname === '127.0.0.1' && location.port === '8888') ? 'study' : 'game',
|
db: (location.hostname === '127.0.0.1' && location.port === '8888') ? 'study' : 'game',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 世界(yt_world)所在库:本地 Odoo 钉 yt_game;线上游戏库名为 game。按域名自适应,git 同步不冲突。
|
||||||
|
const WORLD_DB = (location.hostname === '127.0.0.1' || location.hostname === 'localhost') ? 'yt_game' : 'game';
|
||||||
|
|
||||||
const _cred = API_CONFIG.base ? 'include' : 'same-origin';
|
const _cred = API_CONFIG.base ? 'include' : 'same-origin';
|
||||||
|
|
||||||
function _url(path) {
|
function _url(path) {
|
||||||
@ -68,17 +71,17 @@ const API = {
|
|||||||
},
|
},
|
||||||
// ---------- 沙盘记忆(yt_world 模块) ----------
|
// ---------- 沙盘记忆(yt_world 模块) ----------
|
||||||
async world() {
|
async world() {
|
||||||
return (await fetch('/yt_world/api/world?db=yt_game', { credentials: 'same-origin' })).json();
|
return (await fetch('/yt_world/api/world?db=' + WORLD_DB, { credentials: 'same-origin' })).json();
|
||||||
},
|
},
|
||||||
async saveTiles(tiles) {
|
async saveTiles(tiles) {
|
||||||
return (await fetch('/yt_world/api/tiles/save?db=yt_game', {
|
return (await fetch('/yt_world/api/tiles/save?db=' + WORLD_DB, {
|
||||||
method: 'POST', credentials: 'same-origin',
|
method: 'POST', credentials: 'same-origin',
|
||||||
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=yt_game', {
|
return (await fetch('/yt_world/api/settings?db=' + WORLD_DB, {
|
||||||
method: 'POST', credentials: 'same-origin',
|
method: 'POST', credentials: 'same-origin',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ settings }),
|
body: JSON.stringify({ settings }),
|
||||||
@ -87,14 +90,14 @@ const API = {
|
|||||||
// ---------- 世界数据 / 包裹(后端接口预留:yt_world 暂未实现路由,前端 mock 兜底) ----------
|
// ---------- 世界数据 / 包裹(后端接口预留:yt_world 暂未实现路由,前端 mock 兜底) ----------
|
||||||
async worldData() {
|
async worldData() {
|
||||||
try {
|
try {
|
||||||
const r = await fetch('/yt_world/api/data?db=yt_game', { credentials: 'same-origin' });
|
const r = await fetch('/yt_world/api/data?db=' + WORLD_DB, { credentials: 'same-origin' });
|
||||||
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=yt_game', { credentials: 'same-origin' });
|
const r = await fetch('/yt_world/api/inventory?db=' + WORLD_DB, { credentials: 'same-origin' });
|
||||||
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; }
|
||||||
|
|||||||
33
login.html
33
login.html
@ -45,8 +45,9 @@
|
|||||||
.field input:focus{border-color:var(--violet);box-shadow:0 0 0 3px rgba(139,92,246,.18);}
|
.field input:focus{border-color:var(--violet);box-shadow:0 0 0 3px rgba(139,92,246,.18);}
|
||||||
.pw-wrap{position:relative;}
|
.pw-wrap{position:relative;}
|
||||||
.pw-wrap input{padding-right:40px;}
|
.pw-wrap input{padding-right:40px;}
|
||||||
.pw-toggle{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:16px;line-height:1;padding:4px 6px;border-radius:6px;transition:.2s;}
|
.pw-toggle,.random-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:16px;line-height:1;padding:4px 6px;border-radius:6px;transition:.2s;}
|
||||||
.pw-toggle:hover{color:#fff;background:rgba(255,255,255,.08);}
|
.pw-toggle:hover,.random-btn:hover{color:#fff;background:rgba(255,255,255,.08);}
|
||||||
|
.random-btn{font-size:15px;}
|
||||||
|
|
||||||
.submit{width:100%;margin-top:6px;font-size:15px;font-weight:700;color:#0b1020;background:linear-gradient(120deg,var(--gold),#f0d49a);padding:12px;border-radius:11px;cursor:pointer;border:none;letter-spacing:2px;transition:.22s;box-shadow:0 0 18px rgba(231,184,92,.35);}
|
.submit{width:100%;margin-top:6px;font-size:15px;font-weight:700;color:#0b1020;background:linear-gradient(120deg,var(--gold),#f0d49a);padding:12px;border-radius:11px;cursor:pointer;border:none;letter-spacing:2px;transition:.22s;box-shadow:0 0 18px rgba(231,184,92,.35);}
|
||||||
.submit:hover{filter:brightness(1.08);}
|
.submit:hover{filter:brightness(1.08);}
|
||||||
@ -75,7 +76,6 @@
|
|||||||
<div class="brand">
|
<div class="brand">
|
||||||
<div class="cn">宇森</div>
|
<div class="cn">宇森</div>
|
||||||
<div class="en">YUSEN · GARDEN OF CIVILIZATION</div>
|
<div class="en">YUSEN · GARDEN OF CIVILIZATION</div>
|
||||||
<div class="tag">你不是玩家,你是园丁。</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -108,7 +108,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>昵称</label>
|
<label>昵称</label>
|
||||||
<input id="rName" type="text" placeholder="默认与账号一致,可改" />
|
<div class="pw-wrap">
|
||||||
|
<input id="rName" type="text" placeholder="可随机生成,也可自定义" />
|
||||||
|
<button type="button" class="random-btn" id="randomNameBtn" aria-label="随机昵称">🎲</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>密码</label>
|
<label>密码</label>
|
||||||
@ -124,7 +127,7 @@
|
|||||||
<button type="button" class="pw-toggle" data-target="rPwd2" aria-label="显示密码">👁</button>
|
<button type="button" class="pw-toggle" data-target="rPwd2" aria-label="显示密码">👁</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="submit" type="submit">创建园丁账号</button>
|
<button class="submit" type="submit">创建账号</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div class="msg" id="msg"></div>
|
<div class="msg" id="msg"></div>
|
||||||
@ -181,14 +184,18 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 昵称默认 = 账号:账号变更时若昵称仍空/等于上次账号值,则同步;用户改过昵称则保留
|
// 随机昵称生成
|
||||||
const rLogin = document.getElementById('rLogin');
|
|
||||||
const rName = document.getElementById('rName');
|
const rName = document.getElementById('rName');
|
||||||
let lastLoginVal = '';
|
const ADJ = ['云游','星尘','微光','风吟','夜语','深海','荒原','天穹','逐风','灵叶','虚境','晨星','暮雨','浮世','苍穹'];
|
||||||
rLogin.addEventListener('input', () => {
|
const NOUN = ['旅者','观察者','行者','拾光人','园丁','筑梦师','游侠','学者','守夜人','引路人','浪人','渡鸦','白鹿'];
|
||||||
const v = rLogin.value.trim();
|
function randomName() {
|
||||||
if (rName.value === '' || rName.value === lastLoginVal) rName.value = v;
|
const a = ADJ[Math.floor(Math.random() * ADJ.length)];
|
||||||
lastLoginVal = v;
|
const n = NOUN[Math.floor(Math.random() * NOUN.length)];
|
||||||
|
const num = String(Math.floor(Math.random() * 9000) + 1000);
|
||||||
|
return a + n + num;
|
||||||
|
}
|
||||||
|
document.getElementById('randomNameBtn').addEventListener('click', () => {
|
||||||
|
rName.value = randomName();
|
||||||
});
|
});
|
||||||
|
|
||||||
loginForm.addEventListener('submit', async (e) => {
|
loginForm.addEventListener('submit', async (e) => {
|
||||||
@ -230,7 +237,7 @@
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
showMsg('网络错误,请稍后重试', 'err');
|
showMsg('网络错误,请稍后重试', 'err');
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false; btn.textContent = '创建园丁账号';
|
btn.disabled = false; btn.textContent = '创建账号';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user