注册数据
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
{
|
||||
'name': '宇森游戏基础数据',
|
||||
'summary': '宇森游戏基础数据:图鉴 / 规则 / 论坛 / 公告',
|
||||
'version': '1.2',
|
||||
'summary': '宇森游戏基础数据:图鉴 / 规则 / 论坛 / 公告 / 玩家员工',
|
||||
'version': '1.3',
|
||||
'category': 'Game',
|
||||
'sequence': 10,
|
||||
'depends': ['base'],
|
||||
'depends': ['base', 'hr'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/game_base_data.xml',
|
||||
'data/game_achievement_data.xml',
|
||||
'views/codex_views.xml',
|
||||
'views/rule_category_views.xml',
|
||||
'views/rule_views.xml',
|
||||
@@ -15,10 +16,13 @@
|
||||
'views/forum_views.xml',
|
||||
'views/announcement_views.xml',
|
||||
'views/story_views.xml',
|
||||
'views/game_employee_views.xml',
|
||||
'views/game_achievement_views.xml',
|
||||
'views/game_mail_views.xml',
|
||||
'views/menu.xml',
|
||||
],
|
||||
'application': True,
|
||||
'license': 'LGPL-3',
|
||||
'pre_init_hook': 'pre_init_hook',
|
||||
'description': '基于官网内容沉淀的游戏基础数据模型,供后台维护、前端经 /game/api/* 读取;并提供与 Odoo 用户打通的登录/注册接口。',
|
||||
'description': '基于官网内容沉淀的游戏基础数据模型,供后台维护、前端经 /game/api/* 读取;并提供与 Odoo 用户打通的登录/注册接口。注册时自动创建 hr.employee 并初始化游戏数据。',
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
from odoo import http
|
||||
from odoo import http, fields
|
||||
from odoo.http import request, Response
|
||||
|
||||
|
||||
@@ -309,12 +309,52 @@ class GameApiController(http.Controller):
|
||||
'groups_id': [(6, 0, [portal.id])],
|
||||
})
|
||||
request.env.cr.commit() # 让新用户立即对其他游标可见,便于随后自动登录
|
||||
# === 自动创建 hr.employee 并初始化游戏数据 ===
|
||||
Emp = request.env['hr.employee'].sudo()
|
||||
emp = Emp.create({
|
||||
'name': name or login,
|
||||
'user_id': user.id,
|
||||
'work_email': email or False,
|
||||
'game_title': '萌新',
|
||||
'game_level': 1,
|
||||
'game_exp': 0,
|
||||
'game_exp_max': 100,
|
||||
'game_coins': 0,
|
||||
'game_energy': 0,
|
||||
'game_wood': 0,
|
||||
'game_stone': 0,
|
||||
'game_reg_date': fields.Date.today(),
|
||||
})
|
||||
# 生成游戏 UID(格式 10086 + 4位员工ID)
|
||||
emp.game_uid = '10086%04d' % emp.id
|
||||
# 给新玩家解锁第一个成就"开天辟地"
|
||||
tmpl = request.env['game.achievement.template'].sudo().search(
|
||||
[('code', '=', 'first_land')], limit=1)
|
||||
if tmpl:
|
||||
request.env['game.player.achievement'].sudo().create({
|
||||
'employee_id': emp.id,
|
||||
'template_id': tmpl.id,
|
||||
'progress': tmpl.target,
|
||||
'unlocked': True,
|
||||
'unlock_date': fields.Datetime.now(),
|
||||
})
|
||||
# 给新玩家发一封欢迎邮件
|
||||
request.env['game.player.mail'].sudo().create({
|
||||
'employee_id': emp.id,
|
||||
'category': 'system',
|
||||
'subject': '欢迎来到宇森',
|
||||
'sender': '系统',
|
||||
'body': '<p>欢迎来到宇森!请查收新手礼包与世界探索指南。</p>',
|
||||
})
|
||||
request.env.cr.commit()
|
||||
db = request.session.db or 'game'
|
||||
auth_info = request.session.authenticate(db, {'type': 'password', 'login': login, 'password': password})
|
||||
uid = auth_info['uid']
|
||||
if uid:
|
||||
return _json({'ok': True, 'uid': uid, 'name': user.name, 'login': user.login})
|
||||
return _json({'ok': True, 'uid': user.id, 'name': user.name, 'login': user.login})
|
||||
return _json({'ok': True, 'uid': uid, 'name': user.name, 'login': user.login,
|
||||
'emp_id': emp.id, 'game_uid': emp.game_uid})
|
||||
return _json({'ok': True, 'uid': user.id, 'name': user.name, 'login': user.login,
|
||||
'emp_id': emp.id, 'game_uid': emp.game_uid})
|
||||
except Exception as e:
|
||||
return _json({'ok': False, 'error': '注册失败:%s' % str(e)})
|
||||
|
||||
@@ -324,9 +364,123 @@ class GameApiController(http.Controller):
|
||||
if uid:
|
||||
user = request.env['res.users'].sudo().browse(uid)
|
||||
if user.exists():
|
||||
return _json({'uid': uid, 'name': user.name, 'login': user.login})
|
||||
data = {'uid': uid, 'name': user.name, 'login': user.login,
|
||||
'email': user.email or ''}
|
||||
emp = request.env['hr.employee'].sudo().search(
|
||||
[('user_id', '=', uid)], limit=1)
|
||||
if emp:
|
||||
data.update(emp.export_game_data())
|
||||
return _json(data)
|
||||
return _json({'uid': None})
|
||||
|
||||
@http.route('/game/api/achievements', type='http', auth='public',
|
||||
methods=['GET'], csrf=False)
|
||||
def achievements(self, **kw):
|
||||
"""返回当前登录玩家的成就列表(含模板+进度)。"""
|
||||
uid = request.session.uid
|
||||
if not uid:
|
||||
return _json({'error': '未登录'})
|
||||
emp = request.env['hr.employee'].sudo().search(
|
||||
[('user_id', '=', uid)], limit=1)
|
||||
if not emp:
|
||||
return _json({'error': '玩家不存在', 'items': [], 'total_points': 0})
|
||||
# 取所有启用的成就模板
|
||||
tmpl_model = request.env['game.achievement.template'].sudo()
|
||||
tier_labels = dict(tmpl_model._fields['tier'].selection)
|
||||
templates = tmpl_model.search_read(
|
||||
[('active', '=', True)],
|
||||
['id', 'name', 'icon', 'tier', 'desc', 'points', 'target', 'sequence'],
|
||||
order='sequence, id')
|
||||
# 取该玩家已解锁的成就
|
||||
player_recs = request.env['game.player.achievement'].sudo().search_read(
|
||||
[('employee_id', '=', emp.id)],
|
||||
['template_id', 'progress', 'unlocked', 'unlock_date'])
|
||||
progress_map = {
|
||||
r['template_id'][0]: r for r in player_recs
|
||||
}
|
||||
items = []
|
||||
total_points = 0
|
||||
unlocked_count = 0
|
||||
for t in templates:
|
||||
pr = progress_map.get(t['id'])
|
||||
unlocked = pr and pr['unlocked']
|
||||
progress = pr['progress'] if pr else 0
|
||||
if unlocked:
|
||||
total_points += t['points']
|
||||
unlocked_count += 1
|
||||
items.append({
|
||||
'id': t['id'],
|
||||
'name': t['name'],
|
||||
'icon': t.get('icon') or '',
|
||||
'tier': t['tier'],
|
||||
'tier_label': tier_labels.get(t['tier'], t['tier']),
|
||||
'desc': t.get('desc') or '',
|
||||
'points': t['points'],
|
||||
'target': t['target'],
|
||||
'progress': progress,
|
||||
'unlocked': bool(unlocked),
|
||||
'unlock_date': str(pr['unlock_date']) if pr and pr['unlock_date'] else None,
|
||||
})
|
||||
return _json({
|
||||
'items': items,
|
||||
'total_points': total_points,
|
||||
'unlocked_count': unlocked_count,
|
||||
'total_count': len(items),
|
||||
})
|
||||
|
||||
@http.route('/game/api/mails', type='http', auth='public',
|
||||
methods=['GET'], csrf=False)
|
||||
def mails(self, **kw):
|
||||
"""返回当前登录玩家的邮件列表。"""
|
||||
uid = request.session.uid
|
||||
if not uid:
|
||||
return _json({'error': '未登录', 'items': []})
|
||||
emp = request.env['hr.employee'].sudo().search(
|
||||
[('user_id', '=', uid)], limit=1)
|
||||
if not emp:
|
||||
return _json({'error': '玩家不存在', 'items': []})
|
||||
cat_labels = dict(
|
||||
request.env['game.player.mail'].sudo()._fields['category'].selection)
|
||||
recs = request.env['game.player.mail'].sudo().search_read(
|
||||
[('employee_id', '=', emp.id)],
|
||||
['id', 'category', 'subject', 'body', 'date', 'is_read',
|
||||
'is_pinned', 'sender'],
|
||||
order='is_pinned desc, date desc')
|
||||
items = [{
|
||||
'id': r['id'],
|
||||
'category': r['category'],
|
||||
'category_label': cat_labels.get(r['category'], r['category']),
|
||||
'subject': r['subject'],
|
||||
'body': r.get('body') or '',
|
||||
'date': str(r['date']) if r['date'] else '',
|
||||
'is_read': r['is_read'],
|
||||
'is_pinned': r['is_pinned'],
|
||||
'sender': r.get('sender') or '',
|
||||
} for r in recs]
|
||||
unread = len([r for r in items if not r['is_read']])
|
||||
return _json({'items': items, 'unread': unread})
|
||||
|
||||
@http.route('/game/api/mail/read', type='http', auth='public',
|
||||
methods=['POST', 'OPTIONS'], csrf=False)
|
||||
def mail_read(self, **kw):
|
||||
"""标记邮件为已读。"""
|
||||
uid = request.session.uid
|
||||
if not uid:
|
||||
return _json({'ok': False, 'error': '未登录'})
|
||||
data = _post_body()
|
||||
mail_id = data.get('mail_id')
|
||||
if not mail_id:
|
||||
return _json({'ok': False, 'error': '缺少 mail_id'})
|
||||
emp = request.env['hr.employee'].sudo().search(
|
||||
[('user_id', '=', uid)], limit=1)
|
||||
if not emp:
|
||||
return _json({'ok': False, 'error': '玩家不存在'})
|
||||
mail = request.env['game.player.mail'].sudo().browse(mail_id)
|
||||
if not mail.exists() or mail.employee_id != emp:
|
||||
return _json({'ok': False, 'error': '邮件不存在或无权操作'})
|
||||
mail.write({'is_read': True})
|
||||
return _json({'ok': True})
|
||||
|
||||
@http.route('/game/api/logout', type='http', auth='public',
|
||||
methods=['POST', 'OPTIONS'], csrf=False)
|
||||
def logout(self, **kw):
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- 成就模板初始数据 -->
|
||||
<record model="game.achievement.template" id="ach_first_land">
|
||||
<field name="code">first_land</field>
|
||||
<field name="sequence">10</field>
|
||||
<field name="name">开天辟地</field>
|
||||
<field name="icon">star</field>
|
||||
<field name="tier">gold</field>
|
||||
<field name="points">50</field>
|
||||
<field name="target">1</field>
|
||||
<field name="desc">已点亮第一块领土,文明之火开始燃烧。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_civilization_cradle">
|
||||
<field name="code">civilization_cradle</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="name">文明摇篮</field>
|
||||
<field name="icon">sprout</field>
|
||||
<field name="tier">silver</field>
|
||||
<field name="points">30</field>
|
||||
<field name="target">5</field>
|
||||
<field name="desc">建立 5 个聚落,文明初步成形。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_sky_tower">
|
||||
<field name="code">sky_tower</field>
|
||||
<field name="sequence">30</field>
|
||||
<field name="name">通天塔</field>
|
||||
<field name="icon">lock</field>
|
||||
<field name="tier">platinum</field>
|
||||
<field name="points">100</field>
|
||||
<field name="target">10</field>
|
||||
<field name="desc">建造 10 座奇观,文明疆域遍布穹苍。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_world_explorer">
|
||||
<field name="code">world_explorer</field>
|
||||
<field name="sequence">40</field>
|
||||
<field name="name">世界探索者</field>
|
||||
<field name="icon">compass</field>
|
||||
<field name="tier">bronze</field>
|
||||
<field name="points">10</field>
|
||||
<field name="target">10</field>
|
||||
<field name="desc">探索 10 块未知领土。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_resource_master">
|
||||
<field name="code">resource_master</field>
|
||||
<field name="sequence">50</field>
|
||||
<field name="name">资源大亨</field>
|
||||
<field name="icon">gem</field>
|
||||
<field name="tier">silver</field>
|
||||
<field name="points">30</field>
|
||||
<field name="target">1000</field>
|
||||
<field name="desc">累计获得 1000 金币。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_spirit_awakening">
|
||||
<field name="code">spirit_awakening</field>
|
||||
<field name="sequence">60</field>
|
||||
<field name="name">灵气觉醒</field>
|
||||
<field name="icon">sparkle</field>
|
||||
<field name="tier">gold</field>
|
||||
<field name="points">50</field>
|
||||
<field name="target">1</field>
|
||||
<field name="desc">世界阶段跃迁至「灵启」。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_mystic_realm">
|
||||
<field name="code">mystic_realm</field>
|
||||
<field name="sequence">70</field>
|
||||
<field name="name">玄界之主</field>
|
||||
<field name="icon">crown</field>
|
||||
<field name="tier">legend</field>
|
||||
<field name="points">200</field>
|
||||
<field name="target">1</field>
|
||||
<field name="desc">世界阶段跃迁至「玄界」。</field>
|
||||
</record>
|
||||
|
||||
<record model="game.achievement.template" id="ach_eternal">
|
||||
<field name="code">eternal</field>
|
||||
<field name="sequence">80</field>
|
||||
<field name="name">永恒之锚</field>
|
||||
<field name="icon">infinity</field>
|
||||
<field name="tier">legend</field>
|
||||
<field name="points">500</field>
|
||||
<field name="target">1</field>
|
||||
<field name="desc">世界阶段达到「溯元」,触及世界本源。</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -6,3 +6,6 @@ from . import rule
|
||||
from . import page
|
||||
from . import story
|
||||
from . import ir_http
|
||||
from . import game_employee
|
||||
from . import game_achievement
|
||||
from . import game_mail
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class GameAchievementTemplate(models.Model):
|
||||
"""全局成就模板:后台定义,所有玩家共用同一套成就定义。"""
|
||||
_name = 'game.achievement.template'
|
||||
_description = '成就模板'
|
||||
_order = 'sequence, id'
|
||||
_rec_name = 'name'
|
||||
|
||||
TIER = [
|
||||
('bronze', '铜'),
|
||||
('silver', '银'),
|
||||
('gold', '金'),
|
||||
('platinum', '铂金'),
|
||||
('legend', '传奇'),
|
||||
]
|
||||
|
||||
sequence = fields.Integer('排序', default=10, index=True)
|
||||
code = fields.Char('标识', index=True,
|
||||
help='唯一标识,用于代码引用,如 first_land')
|
||||
name = fields.Char('成就名称', required=True, translate=True)
|
||||
icon = fields.Char('图标', help='emoji 或符号,如 star / sprout / lock')
|
||||
tier = fields.Selection(TIER, '品质', default='bronze', index=True)
|
||||
desc = fields.Text('描述', help='解锁条件/说明')
|
||||
target = fields.Integer('目标值', default=1,
|
||||
help='解锁所需进度值,如 10 表示需完成 10 次')
|
||||
points = fields.Integer('成就点数', default=10)
|
||||
active = fields.Boolean('启用', default=True)
|
||||
player_achievement_ids = fields.One2many(
|
||||
'game.player.achievement', 'template_id', '玩家解锁记录')
|
||||
|
||||
|
||||
class GamePlayerAchievement(models.Model):
|
||||
"""玩家已解锁/进行中的成就,关联到 hr.employee。"""
|
||||
_name = 'game.player.achievement'
|
||||
_description = '玩家成就'
|
||||
_order = 'template_id, id'
|
||||
_rec_name = 'name'
|
||||
|
||||
template_id = fields.Many2one(
|
||||
'game.achievement.template', '成就模板',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
employee_id = fields.Many2one(
|
||||
'hr.employee', '所属玩家',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
name = fields.Char('名称', related='template_id.name', store=True)
|
||||
icon = fields.Char('图标', related='template_id.icon')
|
||||
tier = fields.Selection(
|
||||
related='template_id.tier', store=True)
|
||||
desc = fields.Text('描述', related='template_id.desc')
|
||||
points = fields.Integer('点数', related='template_id.points')
|
||||
progress = fields.Integer('进度', default=0)
|
||||
target = fields.Integer('目标值', related='template_id.target')
|
||||
unlocked = fields.Boolean('已解锁', default=False)
|
||||
unlock_date = fields.Datetime('解锁时间')
|
||||
|
||||
@api.model
|
||||
def _update_progress(self, employee_id, template_key, progress):
|
||||
"""更新某玩家某成就的进度,达标自动解锁。"""
|
||||
tmpl = self.env['game.achievement.template'].search(
|
||||
[('id', '=', template_key)], limit=1)
|
||||
if not tmpl:
|
||||
return False
|
||||
rec = self.search([
|
||||
('employee_id', '=', employee_id),
|
||||
('template_id', '=', tmpl.id),
|
||||
], limit=1)
|
||||
if not rec:
|
||||
rec = self.create({
|
||||
'employee_id': employee_id,
|
||||
'template_id': tmpl.id,
|
||||
'progress': min(progress, tmpl.target),
|
||||
'unlocked': progress >= tmpl.target,
|
||||
'unlock_date': fields.Datetime.now() if progress >= tmpl.target else False,
|
||||
})
|
||||
elif not rec.unlocked:
|
||||
rec.write({
|
||||
'progress': min(progress, tmpl.target),
|
||||
'unlocked': progress >= tmpl.target,
|
||||
})
|
||||
if rec.unlocked:
|
||||
rec.unlock_date = fields.Datetime.now()
|
||||
return True
|
||||
@@ -0,0 +1,74 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class GameEmployee(models.Model):
|
||||
"""在 hr.employee 上扩展游戏数据字段。"""
|
||||
_inherit = 'hr.employee'
|
||||
|
||||
# === 等级系统 ===
|
||||
game_level = fields.Integer('游戏等级', default=1)
|
||||
game_exp = fields.Integer('经验值', default=0)
|
||||
game_exp_max = fields.Integer('升级经验', default=100)
|
||||
game_title = fields.Char('称号', default='萌新')
|
||||
|
||||
# === 资源系统 ===
|
||||
game_coins = fields.Integer('金币', default=0)
|
||||
game_energy = fields.Integer('灵气', default=0)
|
||||
game_wood = fields.Integer('木材', default=0)
|
||||
game_stone = fields.Integer('石料', default=0)
|
||||
|
||||
# === 世界数据 ===
|
||||
game_world_name = fields.Char('世界名')
|
||||
game_era = fields.Char('历元', default='星元1年·春')
|
||||
game_tiles = fields.Integer('疆域地块', default=0)
|
||||
game_population = fields.Integer('人口', default=0)
|
||||
game_civ_level = fields.Integer('文明度', default=0)
|
||||
|
||||
# === 身份 ===
|
||||
game_uid = fields.Char('游戏UID', index=True)
|
||||
game_reg_date = fields.Date('注册日期', default=fields.Date.today)
|
||||
|
||||
# === 关联 ===
|
||||
achievement_ids = fields.One2many('game.player.achievement', 'employee_id', '成就')
|
||||
mail_ids = fields.One2many('game.player.mail', 'employee_id', '邮件')
|
||||
game_achievement_count = fields.Integer(
|
||||
'已解锁成就数', compute='_compute_achievement_count')
|
||||
game_unread_mail = fields.Integer(
|
||||
'未读邮件数', compute='_compute_unread_mail')
|
||||
|
||||
@api.depends('achievement_ids.unlocked')
|
||||
def _compute_achievement_count(self):
|
||||
for rec in self:
|
||||
rec.game_achievement_count = len(
|
||||
rec.achievement_ids.filtered('unlocked'))
|
||||
|
||||
@api.depends('mail_ids.is_read')
|
||||
def _compute_unread_mail(self):
|
||||
for rec in self:
|
||||
rec.game_unread_mail = len(
|
||||
rec.mail_ids.filtered(lambda m: not m.is_read))
|
||||
|
||||
def export_game_data(self):
|
||||
"""将游戏数据导出为前端可用的字典。"""
|
||||
self.ensure_one()
|
||||
return {
|
||||
'emp_id': self.id,
|
||||
'level': self.game_level,
|
||||
'exp': self.game_exp,
|
||||
'exp_max': self.game_exp_max,
|
||||
'title': self.game_title,
|
||||
'coins': self.game_coins,
|
||||
'energy': self.game_energy,
|
||||
'wood': self.game_wood,
|
||||
'stone': self.game_stone,
|
||||
'world_name': self.game_world_name or '',
|
||||
'era': self.game_era or '',
|
||||
'tiles': self.game_tiles,
|
||||
'population': self.game_population,
|
||||
'civ_level': self.game_civ_level,
|
||||
'game_uid': self.game_uid or '',
|
||||
'reg_date': str(self.game_reg_date) if self.game_reg_date else None,
|
||||
'achievement_count': self.game_achievement_count,
|
||||
'unread_mail': self.game_unread_mail,
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class GamePlayerMail(models.Model):
|
||||
"""玩家邮件:后台可发送系统邮件给指定玩家(员工)。"""
|
||||
_name = 'game.player.mail'
|
||||
_description = '玩家邮件'
|
||||
_order = 'date desc, id desc'
|
||||
_rec_name = 'subject'
|
||||
|
||||
CATEGORY = [
|
||||
('system', '系统'),
|
||||
('activity', '活动'),
|
||||
('reward', '奖励'),
|
||||
('announcement', '公告'),
|
||||
]
|
||||
|
||||
employee_id = fields.Many2one(
|
||||
'hr.employee', '收件人',
|
||||
required=True, ondelete='cascade', index=True)
|
||||
category = fields.Selection(CATEGORY, '分类', default='system', index=True)
|
||||
subject = fields.Char('标题', required=True)
|
||||
body = fields.Html('正文')
|
||||
date = fields.Datetime('发送时间', default=fields.Datetime.now)
|
||||
is_read = fields.Boolean('已读', default=False)
|
||||
is_pinned = fields.Boolean('置顶', default=False)
|
||||
sender = fields.Char('发件人', default='系统')
|
||||
@@ -19,3 +19,9 @@ access_game_story_volume,game.story.volume public,model_game_story_volume,base.g
|
||||
access_game_story_volume_user,game.story.volume user,model_game_story_volume,base.group_user,1,1,1,1
|
||||
access_game_story_chapter,game.story.chapter public,model_game_story_chapter,base.group_public,1,0,0,0
|
||||
access_game_story_chapter_user,game.story.chapter user,model_game_story_chapter,base.group_user,1,1,1,1
|
||||
access_game_achievement_template,game.achievement.template public,model_game_achievement_template,base.group_public,1,0,0,0
|
||||
access_game_achievement_template_user,game.achievement.template user,model_game_achievement_template,base.group_user,1,1,1,1
|
||||
access_game_player_achievement,game.player.achievement public,model_game_player_achievement,base.group_public,1,0,0,0
|
||||
access_game_player_achievement_user,game.player.achievement user,model_game_player_achievement,base.group_user,1,1,1,1
|
||||
access_game_player_mail,game.player.mail public,model_game_player_mail,base.group_public,1,0,0,0
|
||||
access_game_player_mail_user,game.player.mail user,model_game_player_mail,base.group_user,1,1,1,1
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
</group>
|
||||
<field name="body_html"/>
|
||||
<field name="post_ids">
|
||||
<tree><field name="author_name"/><field name="create_date"/></tree>
|
||||
<list><field name="author_name"/><field name="create_date"/></list>
|
||||
<form><field name="author_name"/><field name="body_html"/></form>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- 成就模板列表 -->
|
||||
<record model="ir.ui.view" id="view_game_achievement_template_tree">
|
||||
<field name="name">game.achievement.template.tree</field>
|
||||
<field name="model">game.achievement.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="icon"/>
|
||||
<field name="tier"/>
|
||||
<field name="points"/>
|
||||
<field name="target"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 成就模板表单 -->
|
||||
<record model="ir.ui.view" id="view_game_achievement_template_form">
|
||||
<field name="name">game.achievement.template.form</field>
|
||||
<field name="model">game.achievement.template</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="icon" placeholder="emoji 或符号"/>
|
||||
<field name="tier"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="points"/>
|
||||
<field name="target"/>
|
||||
<field name="sequence"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="desc" placeholder="解锁条件/说明"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 动作 -->
|
||||
<record model="ir.actions.act_window" id="action_game_achievement_template">
|
||||
<field name="name">成就模板</field>
|
||||
<field name="res_model">game.achievement.template</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
<!-- 玩家成就列表(只读查看) -->
|
||||
<record model="ir.ui.view" id="view_game_player_achievement_tree">
|
||||
<field name="name">game.player.achievement.tree</field>
|
||||
<field name="model">game.player.achievement</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="tier"/>
|
||||
<field name="points"/>
|
||||
<field name="progress"/>
|
||||
<field name="unlocked"/>
|
||||
<field name="unlock_date"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_game_player_achievement">
|
||||
<field name="name">玩家成就</field>
|
||||
<field name="res_model">game.player.achievement</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- 继承 hr.employee 表单视图,添加「游戏数据」页签 -->
|
||||
<record model="ir.ui.view" id="view_employee_game_form">
|
||||
<field name="name">hr.employee.game.form</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook" position="inside">
|
||||
<page string="游戏数据" name="game_data">
|
||||
<group>
|
||||
<group string="等级系统">
|
||||
<field name="game_uid"/>
|
||||
<field name="game_level"/>
|
||||
<field name="game_exp"/>
|
||||
<field name="game_exp_max"/>
|
||||
<field name="game_title"/>
|
||||
<field name="game_reg_date"/>
|
||||
</group>
|
||||
<group string="资源">
|
||||
<field name="game_coins"/>
|
||||
<field name="game_energy"/>
|
||||
<field name="game_wood"/>
|
||||
<field name="game_stone"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="世界数据">
|
||||
<field name="game_world_name"/>
|
||||
<field name="game_era"/>
|
||||
<field name="game_tiles"/>
|
||||
<field name="game_population"/>
|
||||
<field name="game_civ_level"/>
|
||||
</group>
|
||||
<group string="统计">
|
||||
<field name="game_achievement_count"/>
|
||||
<field name="game_unread_mail"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 员工列表:增加游戏 UID/等级/称号 列 -->
|
||||
<record model="ir.ui.view" id="view_employee_game_tree">
|
||||
<field name="name">hr.employee.game.tree</field>
|
||||
<field name="model">hr.employee</field>
|
||||
<field name="inherit_id" ref="hr.view_employee_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="game_uid" string="游戏UID"/>
|
||||
<field name="game_level" string="等级"/>
|
||||
<field name="game_title" string="称号"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- 玩家邮件列表 -->
|
||||
<record model="ir.ui.view" id="view_game_player_mail_tree">
|
||||
<field name="name">game.player.mail.tree</field>
|
||||
<field name="model">game.player.mail</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="is_pinned" widget="boolean_toggle"/>
|
||||
<field name="subject"/>
|
||||
<field name="employee_id" string="收件人"/>
|
||||
<field name="category"/>
|
||||
<field name="sender"/>
|
||||
<field name="date"/>
|
||||
<field name="is_read" widget="boolean_toggle"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 玩家邮件表单 -->
|
||||
<record model="ir.ui.view" id="view_game_player_mail_form">
|
||||
<field name="name">game.player.mail.form</field>
|
||||
<field name="model">game.player.mail</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="employee_id" string="收件人"/>
|
||||
<field name="category"/>
|
||||
<field name="sender"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="is_pinned"/>
|
||||
<field name="is_read"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="subject"/>
|
||||
<field name="body" widget="html"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 动作 -->
|
||||
<record model="ir.actions.act_window" id="action_game_player_mail">
|
||||
<field name="name">玩家邮件</field>
|
||||
<field name="res_model">game.player.mail</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -26,6 +26,11 @@
|
||||
<!-- 公告 -->
|
||||
<menuitem id="menu_game_announcement" name="公告" parent="menu_game_root" action="action_game_announcement" sequence="40"/>
|
||||
|
||||
<!-- 玩家 -->
|
||||
<menuitem id="menu_game_player" name="玩家" parent="menu_game_root" sequence="45"/>
|
||||
<menuitem id="menu_game_player_achievement" name="玩家成就" parent="menu_game_player" action="action_game_player_achievement" sequence="46"/>
|
||||
<menuitem id="menu_game_player_mail" name="玩家邮件" parent="menu_game_player" action="action_game_player_mail" sequence="47"/>
|
||||
|
||||
<!-- 小说(剧情) -->
|
||||
<menuitem id="menu_game_story" name="小说" parent="menu_game_root" sequence="35"/>
|
||||
<menuitem id="menu_game_story_volume" name="卷" parent="menu_game_story" action="action_game_story_volume" sequence="36"/>
|
||||
@@ -37,5 +42,6 @@
|
||||
<field name="action" eval="False"/>
|
||||
</record>
|
||||
<menuitem id="menu_game_rule_category" name="规则类别" parent="menu_game_config" action="action_game_rule_category" sequence="51"/>
|
||||
<menuitem id="menu_game_achievement_template" name="成就模板" parent="menu_game_config" action="action_game_achievement_template" sequence="52"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user