diff --git a/yuthon_base/models/ir_ui_menu.py b/yuthon_base/models/ir_ui_menu.py index 24aff0855..a7fafea95 100644 --- a/yuthon_base/models/ir_ui_menu.py +++ b/yuthon_base/models/ir_ui_menu.py @@ -7,40 +7,36 @@ import pypinyin class IrUiMenu(models.Model): _inherit = 'ir.ui.menu' - name_pinyin = fields.Char( - string='菜单名拼音', - compute='_compute_name_pinyin', - store=True, - ) + def _get_menu_pinyin(self, name): + """计算菜单名的全拼+首字母,不存库""" + if not name: + return '' + full_pinyin = ''.join(pypinyin.lazy_pinyin(name)).lower() + first_letters = ''.join([p[0] for p in pypinyin.pinyin(name)]).lower() + return f"{full_pinyin} {first_letters}" - @api.depends('name') - def _compute_name_pinyin(self): - for menu in self: - if not menu.name: - menu.name_pinyin = False - continue - full_pinyin = ''.join(pypinyin.lazy_pinyin(menu.name)).lower() - first_letters = ''.join([p[0] for p in pypinyin.pinyin(menu.name)]).lower() - menu.name_pinyin = f"{full_pinyin} {first_letters}" + def _name_has_pinyin(self, name, search_term): + """检查菜单名(含拼音后缀)是否匹配搜索词""" + if not name or not search_term: + return False + name_str = f"{name} [{self._get_menu_pinyin(name)}]".lower() + return search_term in name_str def load_menus(self, debug): """重写 load_menus,把拼音拼到菜单名后面,让 Ctrl+K 能搜到""" menus = super().load_menus(debug) - # menus 是 dict 结构 {id: {name, parent_id, children, ...}} - # 遍历所有菜单,把拼音追加到 name 后面 for menu_id, menu_data in menus.items(): if not isinstance(menu_data, dict) or not menu_data.get('name'): continue name = menu_data['name'] - # 查数据库获取 name_pinyin - if menu_id and isinstance(menu_id, int): - menu_record = self.browse(menu_id).exists() - if menu_record and menu_record.name_pinyin: - # 格式: "通知公告 [tongzhigonggao tzgg]" - menu_data['name'] = f"{name} [{menu_record.name_pinyin}]" + pinyin = self._get_menu_pinyin(name) + if pinyin: + # 格式: "通知公告 [tongzhigonggao tzgg]" + menu_data['name'] = f"{name} [{pinyin}]" return menus def name_search(self, name='', args=None, operator='ilike', limit=100): + """支持全拼/首字母搜索菜单""" if args is None: args = [] if not name or operator not in ('ilike', 'like', '=', '=like'): @@ -50,23 +46,18 @@ class IrUiMenu(models.Model): if not search_term: return super().name_search(name=name, args=args, operator=operator, limit=limit) - # 生成搜索词的拼音和首字母 - search_pinyin = ''.join(pypinyin.lazy_pinyin(search_term)).lower() - search_first = ''.join([p[0] for p in pypinyin.pinyin(search_term)]).lower() - # 原名搜索 name_domain = expression.AND([args, [('name', operator, name)]]) name_ids = self.search(name_domain, limit=limit).ids - # 拼音搜索(利用存储字段) - pinyin_domain = expression.AND([args, [ - '|', '|', - ('name_pinyin', 'ilike', search_term), - ('name_pinyin', 'ilike', search_pinyin), - ('name_pinyin', 'ilike', search_first), - ]]) - pinyin_ids = self.search(pinyin_domain, limit=limit).ids + # Python 层拼音匹配 + all_menus = self.search(args, limit=limit * 3) + pinyin_ids = [] + for menu in all_menus: + if menu.id in name_ids: + continue # 已经原名匹配了 + if self._name_has_pinyin(menu.name, search_term): + pinyin_ids.append(menu.id) - # 合并,原名匹配优先 all_ids = list(dict.fromkeys(name_ids + pinyin_ids))[:limit] return self.browse(all_ids).name_get()