diff --git a/yuthon_ai_agent/data/demo_report_template.xml b/yuthon_ai_agent/data/demo_report_template.xml index 14f3430da..e22bdc95f 100644 --- a/yuthon_ai_agent/data/demo_report_template.xml +++ b/yuthon_ai_agent/data/demo_report_template.xml @@ -12,7 +12,7 @@ {"name":"订单号","partner_id":"客户","date_order":"下单日期","amount_total":"金额","state":"状态","user_id":"销售员"} date_order desc 5 - + =","description":"查询起始日期"},{"name":"date_to","label":"结束日期","type":"date","domain_field":"date_order","op":"<=","description":"查询截止日期"}]]]> 当用户查询销售订单列表或销售业绩时使用此模板。支持按日期范围筛选。 10 @@ -26,7 +26,7 @@ {"name":"线索名称","partner_name":"客户","expected_revenue":"预期收入","probability":"赢单率","stage_id":"阶段","create_date":"创建时间","user_id":"负责人"} create_date desc 6 - + 当用户查询销售线索列表或销售管道时使用此模板。 20 diff --git a/yuthon_ai_agent/models/ai_report_template.py b/yuthon_ai_agent/models/ai_report_template.py index e157524e1..cae02896b 100644 --- a/yuthon_ai_agent/models/ai_report_template.py +++ b/yuthon_ai_agent/models/ai_report_template.py @@ -69,6 +69,8 @@ class AiReportTemplate(models.Model): help='列定义中已配置的字段,用于限制分组/筛选器的可选范围') param_def_ids = fields.One2many('ai.report.template.param.def', 'template_id', string='AI 参数定义', copy=True) + chart_ids = fields.One2many('ai.report.template.chart', 'template_id', + string='图表配置', copy=True) default_visible = fields.Integer('默认可见列数', default=10) @@ -88,7 +90,7 @@ class AiReportTemplate(models.Model): # ===== Computed: report_config ===== @api.depends('column_ids', 'card_ids', 'group_by_ids', - 'filter_ids', 'default_visible') + 'filter_ids', 'default_visible', 'chart_ids') def _compute_report_config(self): for t in self: cfg = {} @@ -162,6 +164,23 @@ class AiReportTemplate(models.Model): cfg['filters'] = flt if t.default_visible: cfg['defaultVisible'] = t.default_visible + charts = [] + for ch in t.chart_ids: + lf_name = ch.label_field_name or (ch.label_field_id.name if ch.label_field_id else '') + vf_name = ch.value_field_name or (ch.value_field_id.name if ch.value_field_id else '') + if not lf_name: + continue + cd = { + 'type': ch.chart_type, + 'labelField': lf_name, + 'calc': ch.calc_method, + 'title': ch.title or '', + } + if vf_name: + cd['valueField'] = vf_name + charts.append(cd) + if charts: + cfg['charts'] = charts t.report_config = json.dumps(cfg, ensure_ascii=False) if cfg else '{}' def _inverse_report_config(self): diff --git a/yuthon_ai_agent/models/ai_report_template_config.py b/yuthon_ai_agent/models/ai_report_template_config.py index cdd6ceb10..105a2cac8 100644 --- a/yuthon_ai_agent/models/ai_report_template_config.py +++ b/yuthon_ai_agent/models/ai_report_template_config.py @@ -200,6 +200,51 @@ class AiReportTemplateParamDef(models.Model): self.label = self.field_id.field_description +class AiReportTemplateChart(models.Model): + """报表模板 - 图表配置""" + _name = 'ai.report.template.chart' + _description = '图表配置' + _order = 'sequence, id' + + template_id = fields.Many2one('ai.report.template', string='模板', + required=True, ondelete='cascade') + model_id = fields.Many2one('ir.model', related='template_id.model_id', store=True) + chart_type = fields.Selection([ + ('bar', '柱状图'), + ('line', '折线图'), + ('pie', '饼图'), + ('doughnut', '环形图'), + ('polarArea', '玫瑰图'), + ], string='图表类型', default='bar', required=True) + label_field_id = fields.Many2one('ir.model.fields', string='分组字段', + domain="[('model_id', '=', model_id)]", required=True, + help='作为图表分类轴的字段') + label_field_name = fields.Char('分组字段名', + compute='_compute_label_field_name', store=True) + value_field_id = fields.Many2one('ir.model.fields', string='数值字段', + domain="[('model_id', '=', model_id), ('ttype', 'in', ('integer', 'float', 'monetary'))]", + help='留空则使用计数') + value_field_name = fields.Char('数值字段名', + compute='_compute_value_field_name', store=True) + calc_method = fields.Selection([ + ('count', '计数'), + ('sum', '求和'), + ('avg', '平均值'), + ], string='计算方式', default='count') + title = fields.Char('图表标题') + sequence = fields.Integer('排序', default=10) + + @api.depends('label_field_id') + def _compute_label_field_name(self): + for r in self: + r.label_field_name = r.label_field_id.name if r.label_field_id else '' + + @api.depends('value_field_id') + def _compute_value_field_name(self): + for r in self: + r.value_field_name = r.value_field_id.name if r.value_field_id else '' + + class AiReportTemplateDomainLine(models.Model): _name = 'ai.report.template.domain.line' _description = '报表模板-查询条件行' diff --git a/yuthon_ai_agent/security/ir.model.access.csv b/yuthon_ai_agent/security/ir.model.access.csv index 45c15f221..9ba8e3f2c 100644 --- a/yuthon_ai_agent/security/ir.model.access.csv +++ b/yuthon_ai_agent/security/ir.model.access.csv @@ -29,3 +29,5 @@ access_ai_report_template_param_def_user,参数定义-用户只读,model_ai_repo access_ai_report_template_param_def_admin,参数定义-管理员,model_ai_report_template_param_def,yuthon_ai_agent.group_ai_agent_admin,1,1,1,1 access_ai_report_template_domain_line_user,查询条件行-用户只读,model_ai_report_template_domain_line,yuthon_ai_agent.group_ai_agent_user,1,0,0,0 access_ai_report_template_domain_line_admin,查询条件行-管理员,model_ai_report_template_domain_line,yuthon_ai_agent.group_ai_agent_admin,1,1,1,1 +access_ai_report_template_chart_user,图表配置-用户只读,model_ai_report_template_chart,yuthon_ai_agent.group_ai_agent_user,1,0,0,0 +access_ai_report_template_chart_admin,图表配置-管理员,model_ai_report_template_chart,yuthon_ai_agent.group_ai_agent_admin,1,1,1,1 diff --git a/yuthon_ai_agent/static/src/html/report_template.html b/yuthon_ai_agent/static/src/html/report_template.html index 51c3c2191..f48f1c702 100644 --- a/yuthon_ai_agent/static/src/html/report_template.html +++ b/yuthon_ai_agent/static/src/html/report_template.html @@ -5,6 +5,7 @@ {{REPORT_TITLE}} · 动态报表 +