修改badge
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
<t t-name="AppIcon" owl="1">
|
||||
<t t-set="app_id" t-value="app.id" />
|
||||
<t t-set="menu_badge_count" t-value="this.getMenuBadgeCount(app)" />
|
||||
<t t-set="menu_badge_count" t-value="app.badge_count" />
|
||||
<a t-att-href="getMenuItemHref(app)" >
|
||||
<t t-if="icon_style == 'standard'">
|
||||
<img class="img" t-attf-src="/web/image?model=ir.ui.menu&field=web_icon_data&id={{app_id}}" t-att-title="app.name" t-att-alt="app.name" />
|
||||
@@ -46,7 +46,8 @@
|
||||
<t t-name="AppsTreeMenu" owl="1">
|
||||
<!-- 子菜单 -->
|
||||
<t t-set="children_menus" t-value="menu.childrenTree" />
|
||||
<t t-set="menu_badge_count" t-value="this.getMenuBadgeCount(menu)" />
|
||||
<!-- <t t-set="menu_badge_count" t-value="this.getMenuBadgeCount(menu)" />-->
|
||||
<t t-set="menu_badge_count" t-value="menu.badge_count" />
|
||||
<!-- 不存在子菜单 -->
|
||||
<t t-if="!children_menus.length">
|
||||
<div class="dropdown-header dropdown-item o_menu_header_lvl_1">
|
||||
@@ -87,7 +88,8 @@
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<t t-foreach="children_menus" t-as="children" t-key="children.id">
|
||||
<t t-set="children_sub_menus" t-value="children.childrenTree" />
|
||||
<t t-set="children_menu_badge_count" t-value="this.getMenuBadgeCount(children)" />
|
||||
<t t-set="children_menu_badge_count" t-value="children.badge_count" />
|
||||
<!-- <t t-set="children_menu_badge_count" t-value="this.getMenuBadgeCount(children)" />-->
|
||||
<t t-if="children_sub_menus.length">
|
||||
<t t-call="AppsTreeMenu">
|
||||
<t t-set="menu" t-value="children" />
|
||||
|
||||
@@ -12,12 +12,15 @@
|
||||
"base",
|
||||
"web",
|
||||
],
|
||||
"data": [],
|
||||
"data": [
|
||||
'views/webclient_templates.xml',
|
||||
'views/ir_ui_menu.xml'
|
||||
],
|
||||
"assets": {
|
||||
# "web.assets_backend": [
|
||||
# "sun_badge_menu/static/src/webclient/navbar/navbar.js",
|
||||
# "sun_badge_menu/static/src/webclient/navbar/navbar.xml"
|
||||
# ],
|
||||
"web.assets_backend": [
|
||||
"sun_badge_menu/static/src/webclient/navbar/navbar.js",
|
||||
"sun_badge_menu/static/src/webclient/navbar/navbar.xml"
|
||||
],
|
||||
},
|
||||
"installable": True,
|
||||
"application": True,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import re
|
||||
|
||||
from odoo import models
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
def compute_badge_count_recursive(web_menus, menu_id):
|
||||
@@ -29,6 +29,8 @@ def compute_badge_count_recursive(web_menus, menu_id):
|
||||
class IrUiMenu(models.Model):
|
||||
_inherit = "ir.ui.menu"
|
||||
|
||||
show_badge_count = fields.Boolean(string="显示菜单角标",default=True)
|
||||
|
||||
def load_web_menus(self, debug):
|
||||
""" Loads all menu items (all applications and their sub-menus) and
|
||||
processes them to be used by the webclient. Mainly, it associates with
|
||||
@@ -38,72 +40,76 @@ class IrUiMenu(models.Model):
|
||||
|
||||
:return: the menus (including the images in Base64)
|
||||
"""
|
||||
return super(IrUiMenu, self).load_web_menus(debug)
|
||||
# menus = self.load_menus(debug)
|
||||
#
|
||||
# web_menus = {}
|
||||
# for menu in menus.values():
|
||||
# if not menu['id']:
|
||||
# # special root menu case
|
||||
# web_menus['root'] = {
|
||||
# "id": 'root',
|
||||
# "name": menu['name'],
|
||||
# "children": menu['children'],
|
||||
# "appID": False,
|
||||
# "xmlid": "",
|
||||
# "actionID": False,
|
||||
# "actionModel": False,
|
||||
# "actionPath": False,
|
||||
# "webIcon": None,
|
||||
# "webIconData": None,
|
||||
# "webIconDataMimetype": None,
|
||||
# "backgroundImage": menu.get('backgroundImage'),
|
||||
# }
|
||||
# else:
|
||||
# action = menu['action']
|
||||
#
|
||||
# if menu['id'] == menu['app_id']:
|
||||
# # if it's an app take action of first (sub)child having one defined
|
||||
# child = menu
|
||||
# while child and not action:
|
||||
# action = child['action']
|
||||
# child = menus[child['children'][0]] if child['children'] else False
|
||||
#
|
||||
# action_model, action_id = action.split(',') if action else (False, False)
|
||||
# action_id = int(action_id) if action_id else False
|
||||
# badge_count = 0
|
||||
# res_model = False
|
||||
# if action_model and action_id:
|
||||
# action_record = self.env[action_model].browse(action_id).sudo()
|
||||
#
|
||||
# if action_model == 'ir.actions.act_window' and action_record.view_mode != 'form':
|
||||
# # 不仅仅是 form 表单,获取 model
|
||||
# res_model = action_record.res_model
|
||||
# # if res_model == 'sale.order':
|
||||
# # print(self.env[action_record.res_model].get_menu_badge_count())
|
||||
#
|
||||
# if res_model in self.env and hasattr(self.env[res_model], 'get_menu_badge_count'):
|
||||
# badge_count = self.env[res_model].get_menu_badge_count(action_record)
|
||||
#
|
||||
#
|
||||
# web_menus[menu['id']] = {
|
||||
# "id": menu['id'],
|
||||
# "name": menu['name'],
|
||||
# "children": menu['children'],
|
||||
# "appID": menu['app_id'],
|
||||
# "xmlid": menu['xmlid'],
|
||||
# "actionID": action_id,
|
||||
# "actionModel": action_model,
|
||||
# "webIcon": menu['web_icon'],
|
||||
# "webIconData": menu['web_icon_data'],
|
||||
# "webIconDataMimetype": menu['web_icon_data_mimetype'],
|
||||
# "badge_count": badge_count,
|
||||
# "res_model": res_model
|
||||
# }
|
||||
#
|
||||
# # 计算父级的菜单的徽章数
|
||||
# for k, v in web_menus.items():
|
||||
# if v['children']:
|
||||
# web_menus[k]['badge_count'] = compute_badge_count_recursive(web_menus, k)
|
||||
# # 对 root 节点重新计算
|
||||
# return web_menus
|
||||
menus = self.load_menus(debug)
|
||||
|
||||
web_menus = {}
|
||||
for menu in menus.values():
|
||||
if not menu['id']:
|
||||
# special root menu case
|
||||
web_menus['root'] = {
|
||||
"id": 'root',
|
||||
"name": menu['name'],
|
||||
"children": menu['children'],
|
||||
"appID": False,
|
||||
"xmlid": "",
|
||||
"actionID": False,
|
||||
"actionModel": False,
|
||||
"actionPath": False,
|
||||
"webIcon": None,
|
||||
"webIconData": None,
|
||||
"webIconDataMimetype": None,
|
||||
"backgroundImage": menu.get('backgroundImage')
|
||||
}
|
||||
else:
|
||||
action = menu['action']
|
||||
|
||||
if menu['id'] == menu['app_id']:
|
||||
# if it's an app take action of first (sub)child having one defined
|
||||
child = menu
|
||||
while child and not action:
|
||||
action = child['action']
|
||||
child = menus[child['children'][0]] if child['children'] else False
|
||||
|
||||
action_model, action_id = action.split(',') if action else (False, False)
|
||||
action_id = int(action_id) if action_id else False
|
||||
badge_count = 0
|
||||
res_model = False
|
||||
if action_model and action_id:
|
||||
action_record = self.env[action_model].browse(action_id).sudo()
|
||||
|
||||
if action_model == 'ir.actions.act_window' and action_record.view_mode != 'form':
|
||||
# 不仅仅是 form 表单,获取 model
|
||||
res_model = action_record.res_model
|
||||
if res_model in self.env:
|
||||
if hasattr(self.env[res_model], 'get_menu_badge_count'):
|
||||
badge_count = self.env[res_model].get_menu_badge_count(action_record)
|
||||
elif hasattr(self.env[res_model], 'get_no_read_count'):
|
||||
badge_count = self.env[res_model].get_no_read_count()
|
||||
elif hasattr(res_model, 'read_number'):
|
||||
badge_count = self.env[res_model].read_number()
|
||||
elif hasattr(res_model, 'read_coming_count'):
|
||||
badge_count = self.env[res_model].read_coming_count()
|
||||
elif hasattr(res_model, 'read_due_count'):
|
||||
badge_count = self.env[res_model].read_due_count()
|
||||
|
||||
web_menus[menu['id']] = {
|
||||
"id": menu['id'],
|
||||
"name": menu['name'],
|
||||
"children": menu['children'],
|
||||
"appID": menu['app_id'],
|
||||
"xmlid": menu['xmlid'],
|
||||
"actionID": action_id,
|
||||
"actionModel": action_model,
|
||||
"webIcon": menu['web_icon'],
|
||||
"webIconData": menu['web_icon_data'],
|
||||
"webIconDataMimetype": menu['web_icon_data_mimetype'],
|
||||
"badge_count": badge_count,
|
||||
"res_model": res_model
|
||||
}
|
||||
|
||||
# 计算父级的菜单的徽章数
|
||||
for k, v in web_menus.items():
|
||||
if v['children']:
|
||||
web_menus[k]['badge_count'] = compute_badge_count_recursive(web_menus, k)
|
||||
# 对 root 节点重新计算
|
||||
return web_menus
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-inherit="web.NavBar.SectionsMenu.Dropdown.MenuSlot" t-inherit-mode="extension">
|
||||
<xpath expr="//DropdownItem[@t-if='!item.childrenTree.length']" position="replace">
|
||||
<DropdownItem
|
||||
t-if="!item.childrenTree.length"
|
||||
class="{
|
||||
'dropdown-item': true,
|
||||
o_dropdown_menu_group_entry: decalage gt 20
|
||||
}"
|
||||
onSelected="() => this.onNavBarDropdownItemSelection(item)"
|
||||
attrs="{ style: style, href: getMenuItemHref(item), 'data-menu-xmlid': item.xmlid, 'data-section': item.id }"
|
||||
>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span t-esc="item.name"></span>
|
||||
<span class="badge text-bg-danger rounded-pill" t-esc="item.badge_count"
|
||||
t-if="item.badge_count > 0"></span>
|
||||
</div>
|
||||
</DropdownItem>
|
||||
</xpath>
|
||||
</t>
|
||||
<!--<t t-inherit="web.NavBar.SectionsMenu.Dropdown.MenuSlot" t-inherit-mode="extension">-->
|
||||
<!-- <xpath expr="//DropdownItem[@t-if='!item.childrenTree.length']" position="replace">-->
|
||||
<!-- <DropdownItem-->
|
||||
<!-- t-if="!item.childrenTree.length"-->
|
||||
<!-- href="getMenuItemHref(item)"-->
|
||||
<!-- class="{-->
|
||||
<!-- 'dropdown-item': true,-->
|
||||
<!-- o_dropdown_menu_group_entry: decalage gt 20-->
|
||||
<!-- }"-->
|
||||
<!-- style="style"-->
|
||||
<!-- dataset="{ menuXmlid: item.xmlid, section: item.id }"-->
|
||||
<!-- onSelected="() => this.onNavBarDropdownItemSelection(item)"-->
|
||||
<!-- >-->
|
||||
<!-- <div class="d-flex justify-content-between">-->
|
||||
<!-- <span t-esc="item.name"></span>-->
|
||||
<!-- <span class="badge text-bg-danger rounded-pill" t-esc="item.badge_count"-->
|
||||
<!-- t-if="item.badge_count > 0"></span>-->
|
||||
<!-- </div>-->
|
||||
<!-- </DropdownItem>-->
|
||||
<!-- </xpath>-->
|
||||
<!--</t>-->
|
||||
|
||||
<t t-inherit="web.NavBar.SectionsMenu" t-inherit-mode="extension">
|
||||
<xpath expr="//button[@t-att-data-hotkey='hotkey']" position="replace">
|
||||
<button t-att-data-hotkey="hotkey" t-att-data-menu-xmlid="section.xmlid">
|
||||
<span t-esc="section.name" t-att-data-section="section.id"/>
|
||||
<span t-if="section.badge_count > 0" t-esc="section.badge_count" class="position-absolute z-1 start-100 translate-middle badge rounded-pill text-bg-danger">
|
||||
<!--<t t-inherit="web.NavBar.SectionsMenu" t-inherit-mode="extension">-->
|
||||
<!--<xpath expr="//button[@t-att-data-hotkey='hotkey']" position="replace">-->
|
||||
<!-- <button t-att-data-hotkey="hotkey" t-att-data-menu-xmlid="section.xmlid">-->
|
||||
<!-- <span t-esc="section.name" t-att-data-section="section.id"/>-->
|
||||
<!-- <span t-if="section.badge_count > 0" t-esc="section.badge_count"-->
|
||||
<!-- class="position-absolute z-1 start-100 translate-middle badge rounded-pill text-bg-danger">-->
|
||||
|
||||
</span>
|
||||
</button>
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
||||
<!-- </span>-->
|
||||
<!-- </button>-->
|
||||
<!--</xpath>-->
|
||||
<!--</t>-->
|
||||
</templates>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="edit_menu_access" model="ir.ui.view">
|
||||
<field name="model">ir.ui.menu</field>
|
||||
<field name="inherit_id" ref="base.edit_menu_access"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='sequence']" position="after">
|
||||
<field name="show_badge_count"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<template id="webclient_bootstrap" inherit_id="web.webclient_bootstrap">
|
||||
<xpath expr="//script" position="replace">
|
||||
<script type="text/javascript">
|
||||
// Block to avoid leaking variables in the script scope
|
||||
{
|
||||
odoo.__session_info__ = <t t-out="json.dumps(session_info)"/>;
|
||||
const { user_context, cache_hashes } = odoo.__session_info__;
|
||||
const lang = new URLSearchParams(document.location.search).get("lang");
|
||||
let load_menus= new Date().getTime().toString();
|
||||
let menuURL = `/web/webclient/load_menus/${load_menus}`;
|
||||
if (lang) {
|
||||
user_context.lang = lang;
|
||||
menuURL += `?lang=${lang}`
|
||||
}
|
||||
odoo.reloadMenus = () => fetch(menuURL).then(res => res.json());
|
||||
odoo.loadMenusPromise = odoo.reloadMenus();
|
||||
// Prefetch translations to speedup webclient. This is done in JS because link rel="prefetch"
|
||||
// is not yet supported on safari.
|
||||
fetch(`/web/webclient/translations/${cache_hashes.translations}?lang=${user_context.lang}`);
|
||||
}
|
||||
</script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user