diff --git a/addons/game_base/controllers/game_api.py b/addons/game_base/controllers/game_api.py index 9d6ed42..debd622 100644 --- a/addons/game_base/controllers/game_api.py +++ b/addons/game_base/controllers/game_api.py @@ -203,8 +203,10 @@ class GameApiController(http.Controller): password = data.get('password') or '' if not login or not password: return _json({'ok': False, 'error': '账号和密码必填'}) - if len(password) < 6: - return _json({'ok': False, 'error': '密码至少 6 位'}) + if len(password) < 8: + return _json({'ok': False, 'error': '密码至少 8 位'}) + if not any(c.isalpha() for c in password) or not any(c.isdigit() for c in password): + return _json({'ok': False, 'error': '密码必须同时包含字母和数字'}) User = request.env['res.users'].sudo() if User.search([('login', '=', login)]): return _json({'ok': False, 'error': '该账号已存在'}) diff --git a/addons/game_base/models/page.py b/addons/game_base/models/page.py new file mode 100644 index 0000000..6b59a2c --- /dev/null +++ b/addons/game_base/models/page.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +from odoo import models, fields + + +class GamePage(models.Model): + """页面板块:官网单页(特色 / 背景 / 致玩家等)的容器。""" + _name = 'game.page' + _description = '页面板块' + _order = 'sequence asc' + _rec_name = 'title' + + key = fields.Char(string='标识', required=True, index=True, + help='前端按 key 取板块,如 features / background / letter') + title = fields.Char(string='标题', required=True) + subtitle = fields.Char(string='副标题') + sequence = fields.Integer(string='排序', default=10) + body_html = fields.Html(string='正文', sanitize=True) + active = fields.Boolean(string='生效', default=True) + item_ids = fields.One2many('game.page.item', 'page_id', string='条目') + + +class GamePageItem(models.Model): + """页面板块下的条目(卡片)。""" + _name = 'game.page.item' + _description = '页面条目' + _order = 'sequence asc' + _rec_name = 'title' + + page_id = fields.Many2one('game.page', string='所属板块', + required=True, ondelete='cascade', index=True) + sequence = fields.Integer(string='排序', default=10) + icon = fields.Char(string='图标', help='emoji 或符号,如 🌐 / ✦') + title = fields.Char(string='标题', required=True) + desc = fields.Text(string='描述') diff --git a/addons/yt_world/models/yt_world_tile.py b/addons/yt_world/models/yt_world_tile.py index 1937f30..04ade8f 100644 --- a/addons/yt_world/models/yt_world_tile.py +++ b/addons/yt_world/models/yt_world_tile.py @@ -31,11 +31,11 @@ class YtWorldTile(models.Model): for t in self: t.coord = "%s,%s" % (t.q, t.r) - @api.model - def create(self, vals): - rec = super(YtWorldTile, self).create(vals) - rec._ensure_micro() - return rec + @api.model_create_multi + def create(self, vals_list): + records = super(YtWorldTile, self).create(vals_list) + records._ensure_micro() + return records def _ensure_micro(self): """新建地块时同步建 1:1 微观世界占位。""" @@ -44,7 +44,6 @@ class YtWorldTile(models.Model): m = self.env['yt.world.tile.micro'].create({'tile_id': t.id}) t.micro_world_id = m - @api.model def write(self, vals): # 任何编辑都刷新 updated_at if 'updated_at' not in vals: diff --git a/addons/yt_world/security/ir.model.access.csv b/addons/yt_world/security/ir.model.access.csv index 3cbaddd..bd1c97f 100644 --- a/addons/yt_world/security/ir.model.access.csv +++ b/addons/yt_world/security/ir.model.access.csv @@ -1,5 +1,13 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_yt_world,yt.world,model_yt_world,base.group_user,1,1,1,1 -access_yt_world_tile,yt.world.tile,model_yt_world_tile,base.group_user,1,1,1,1 -access_yt_world_tile_micro,yt.world.tile.micro,model_yt_world_tile_micro,base.group_user,1,1,1,1 -access_yt_resource,yt.resource,model_yt_resource,base.group_user,1,1,1,1 +access_yt_world_user,yt.world user,model_yt_world,base.group_user,1,1,1,1 +access_yt_world_public,yt.world public,model_yt_world,base.group_public,1,1,1,1 +access_yt_world_portal,yt.world portal,model_yt_world,base.group_portal,1,1,1,1 +access_yt_world_tile_user,yt.world.tile user,model_yt_world_tile,base.group_user,1,1,1,1 +access_yt_world_tile_public,yt.world.tile public,model_yt_world_tile,base.group_public,1,1,1,1 +access_yt_world_tile_portal,yt.world.tile portal,model_yt_world_tile,base.group_portal,1,1,1,1 +access_yt_world_tile_micro_user,yt.world.tile.micro user,model_yt_world_tile_micro,base.group_user,1,1,1,1 +access_yt_world_tile_micro_public,yt.world.tile.micro public,model_yt_world_tile_micro,base.group_public,1,1,1,1 +access_yt_world_tile_micro_portal,yt.world.tile.micro portal,model_yt_world_tile_micro,base.group_portal,1,1,1,1 +access_yt_resource_user,yt.resource user,model_yt_resource,base.group_user,1,1,1,1 +access_yt_resource_public,yt.resource public,model_yt_resource,base.group_public,1,1,1,1 +access_yt_resource_portal,yt.resource portal,model_yt_resource,base.group_portal,1,1,1,1 diff --git a/addons/yt_world/views/yt_world_views.xml b/addons/yt_world/views/yt_world_views.xml index 92aa1b9..1890677 100644 --- a/addons/yt_world/views/yt_world_views.xml +++ b/addons/yt_world/views/yt_world_views.xml @@ -1,13 +1,6 @@ - - - 玩家世界 @@ -62,9 +55,6 @@ - - 地表地块 yt.world.tile @@ -108,4 +98,92 @@ + + + 微观世界 + yt.world.tile.micro + list,form + + + + yt.world.tile.micro.list + yt.world.tile.micro + + + + + + + + + + yt.world.tile.micro.form + yt.world.tile.micro + +
+ + + + + + +
+
+
+ + + + 资源 + yt.resource + list,form + + + + yt.resource.list + yt.resource + + + + + + + + + + + + + yt.resource.form + yt.resource + +
+ + + + + + + + + +
+
+
+ + + + + + + + + +
diff --git a/deploy_server.sh b/deploy_server.sh new file mode 100644 index 0000000..d88b1ca --- /dev/null +++ b/deploy_server.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# 宇森游戏 · 线上服务器一键更新(请在 81.70.146.51 上执行) +# 用法:sudo bash deploy_server.sh +set -e + +# ===== 按实际情况修改这几个变量 ===== +REPO_DIR="/opt/yuthon/game" # git 仓库目录(含 world.html 与 addons/) +ODOO_CONF="/etc/odoo/odoo.conf" # odoo.conf 路径 +ODOO_DB="game" # 线上数据库名(务必与前端 ?db= 一致) +ODOO_SERVICE="odoo" # systemctl 服务名 +ODOO_BIN="/usr/bin/odoo" # odoo-bin 路径(或 which odoo) +# =================================== + +echo "== [1/5] 拉取最新代码 ==" +cd "$REPO_DIR" +git pull --ff-only origin main + +echo "== [2/5] 钉死 odoo.conf 数据库 ==" +if grep -q "^[[:space:]]*db_name" "$ODOO_CONF"; then + sed -i "s/^[[:space:]]*db_name.*/db_name = $ODOO_DB/" "$ODOO_CONF" +else + echo "db_name = $ODOO_DB" >> "$ODOO_CONF" +fi +if ! grep -q "^[[:space:]]*dbfilter" "$ODOO_CONF"; then + echo "dbfilter = ^$ODOO_DB\$" >> "$ODOO_CONF" +fi +echo "当前 db_name=$(grep '^db_name' "$ODOO_CONF")" + +echo "== [3/5] 升级模块(数据库 $ODOO_DB)==" +"$ODOO_BIN" -c "$ODOO_CONF" -d "$ODOO_DB" -u game_base,yt_world --stop-after-init +# 若模块从未安装过,把上行的 -u 改成 -i 执行一次即可 + +echo "== [4/5] 重启 Odoo ==" +systemctl restart "$ODOO_SERVICE" +sleep 3 +systemctl is-active "$ODOO_SERVICE" || { echo "Odoo 未起来,检查: journalctl -u $ODOO_SERVICE -n 50"; exit 1; } + +echo "== [5/5] 冒烟验证 ==" +curl -s -o /dev/null -w "codex 接口 HTTP %{http_code}\n" "https://game.pengyuthon.cn/game/api/codex?db=game" +echo "完成。前端为静态文件,nginx 指向 $REPO_DIR 即可,无需构建。" diff --git a/login.html b/login.html index ced9638..98926fc 100644 --- a/login.html +++ b/login.html @@ -81,7 +81,7 @@
- +
diff --git a/world.html b/world.html index bb1f115..2207ba5 100644 --- a/world.html +++ b/world.html @@ -3323,22 +3323,42 @@ init();