ai动态报表

This commit is contained in:
李鹏宇
2026-05-29 14:49:10 +08:00
parent 0cfa751878
commit 534e955cc7
+28 -50
View File
@@ -1,65 +1,43 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.osv import expression
import pypinyin
import re
class IrUiMenu(models.Model):
_inherit = 'ir.ui.menu'
name_pinyin = fields.Char(
string='菜单名拼音',
compute='_compute_name_pinyin',
store=True,
index=True,
)
@api.depends('name')
def _compute_name_pinyin(self):
for menu in self:
if menu.name:
# 全拼:如 "通知公告" → "tongzhigonggao"
full_pinyin = ''.join(pypinyin.lazy_pinyin(menu.name)).lower()
# 首字母:如 "通知公告" → "tzgg"
first_letters = ''.join([
p[0] for p in pypinyin.pinyin(menu.name)
]).lower()
menu.name_pinyin = f"{full_pinyin} {first_letters}"
else:
menu.name_pinyin = False
def name_search(self, name='', args=None, operator='ilike', limit=100):
"""
重写 name_search 支持全拼/首字母模糊搜索菜单
"""
"""支持全拼/首字母模糊搜索菜单(Ctrl+K)"""
if args is None:
args = []
if name and operator in ('ilike', 'like', '=', '=like'):
# 清理输入:去掉空格、转小写
search_term = name.strip().lower().replace(' ', '')
if not search_term:
return super().name_search(name=name, args=args, operator=operator, limit=limit)
if not name or operator not in ('ilike', 'like', '=', '=like'):
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()
search_term = name.strip().lower().replace(' ', '')
if not search_term:
return super().name_search(name=name, args=args, operator=operator, limit=limit)
# 构建拼音搜索域:匹配 name_pinyin 字段
pinyin_domain = [
'|',
('name_pinyin', 'ilike', search_term), # 直接搜索词
('name_pinyin', 'ilike', search_pinyin), # 全拼搜索
]
# 如果首字母不同,也加上
if search_first != search_pinyin:
pinyin_domain = ['|'] + pinyin_domain + [('name_pinyin', 'ilike', search_first)]
# 生成搜索词的拼音和首字母
search_pinyin = ''.join(pypinyin.lazy_pinyin(search_term)).lower()
search_first = ''.join([p[0] for p in pypinyin.pinyin(search_term)]).lower()
# 组合:原名搜索 OR 拼音搜索
full_domain = ['|'] + expression.AND([args, [('name', operator, name)]]) + expression.AND([args, pinyin_domain])
# 原名搜索
name_domain = expression.AND([args, [('name', operator, name)]])
name_ids = self.search(name_domain, limit=limit).ids
# 去重:用 browse 把结果合并(优先按原名匹配排序)
name_results = self.search(expression.AND([args, [('name', operator, name)]]), limit=limit)
pinyin_results = self.search(expression.AND([args, pinyin_domain]), limit=limit)
all_ids = list(dict.fromkeys(name_results.ids + pinyin_results.ids))[:limit]
return self.browse(all_ids).name_get()
return super().name_search(name=name, args=args, operator=operator, limit=limit)
# 拼音搜索:拿到所有菜单,在 Python 层过滤
all_menus = self.search(args, limit=limit * 3)
pinyin_ids = []
for menu in all_menus:
if not menu.name:
continue
menu_pinyin = ''.join(pypinyin.lazy_pinyin(menu.name)).lower()
menu_first = ''.join([p[0] for p in pypinyin.pinyin(menu.name)]).lower()
search_key = f"{menu_pinyin} {menu_first}"
if search_term in search_key or search_pinyin in search_key or search_first in search_key:
pinyin_ids.append(menu.id)
# 合并,原名匹配优先
all_ids = list(dict.fromkeys(name_ids + pinyin_ids))[:limit]
return self.browse(all_ids).name_get()