当前位置: 首页 > article >正文

【odoo17】odoo前端视图的结构分析及新增视图类型的实现

odoo前端视图加载的架构分析

1.视图入口

用F12定位到比如tree视图的地方,可以看到odoo的最顶层定义了一个view组件,然后根据视图类型到了各自的视图结构中。
在这里插入图片描述
可以看到,在view视图中,odoo已经通过load方法加载了不少参数,主要是action中的参数。
在这里插入图片描述

2.视图结构

对比各种视图的代码目录,结构都是相同的。以tree视图为例,进入list代码目录中,看到代码目录。
在这里插入图片描述
这里介绍主要的组成部分,每个视图主要由ArchParser、Controller、Renderer、Model组成。

2.1.ArchParser

ArchParser是用于解析view的xml代码,在list视图中,需要解析的是tree视图,解析结果:
在这里插入图片描述

2.2.Controller

Controller中的分为两部分,上半部分主要由操作按钮、搜索框等组成,下半部分通过props.Renderer在Renderer中实现。
在这里插入图片描述

2.3.Renderer

Renderer在list视图中实现controller中的下半部分,在controller中通过props.Renderer在Renderer调用。
在这里插入图片描述

2.4.Model

Model用于从数据库读取数据,并且会根据视图需要进行相应的处理,odoo对常用数据通过@web/model/relational_model/relational_model中进行处理,如有特殊需求,可以自行构建Model。
model的创建是在Controller的setup中完成,在controller的template中调用。
在这里插入图片描述
在这里插入图片描述

3.视图实现

最终view中通过调用t-component="Controller"来完成对controller中的调用。
在这里插入图片描述

4.新增视图report

4.1.需求描述

在上一章《在报表上方增加搜索视图》中,实现了报表上方增加搜索视图,这种方式由于没有controller,导致searchModel等一系列的组件无法获取,实现麻烦、可扩展性差。因此通过新增视图类型report来实现。

4.2.新增视图类型report

class ActWindowView(models.Model):
    _inherit = 'ir.actions.act_window.view'

    view_mode = fields.Selection(selection_add=[('report', "Report")], ondelete={'report': 'cascade'})


class View(models.Model):
    _inherit = 'ir.ui.view'

    type = fields.Selection(selection_add=[('report', "Report")])

在report中指定props.Renderer

<?xml version="1.0" encoding="utf-8"?>
<odoo>
    <data>
        <record id="view_asset_liabilities_report_report" model="ir.ui.view">
            <field name="name">Asset Liabilities Report</field>
            <field name="model">asset.liabilities.report</field>
            <field name="arch" type="xml">
                <report string="资产负债表" template_id="jcerp_account_ledger.AssetLiabilitiesReport"/>
            </field>
        </record>

        <record id="action_asset_liabilities_report_test" model="ir.actions.act_window">
            <field name="name">资产负债表</field>
            <field name="res_model">asset.liabilities.report</field>
            <field name="view_mode">report</field>
            <field name="view_id" ref="view_asset_liabilities_report_report"/>
        </record>
    </data>
</odoo>

4.3.ArchParser

在ArchParser需要获取report视图传过来的template名称。

export class ReportArchParser {
    parse(arch, fields = {}) {
        const archInfo = { fields, fieldAttrs: {}};
        visitXML(arch, (node) => {
            switch (node.tagName) {
                case "report": {
                    if (node.hasAttribute("template_id")) {
                        archInfo.template_id = node.getAttribute("template_id");
                    }
                    const title = node.getAttribute("string");
                    if (title) {
                        archInfo.title = title;
                    }
                    break;
                }
            }
        });
        return archInfo;
    }
}

4.4.Renderer

由于Renderer是根据template_id生成,因此这里不需要实现Renderer

4.5.Model

根据search传过来的参数获取并解析字段

    /**
     * @param {SearchParams} searchParams
     */
    async load(searchParams) {
        this.searchParams = searchParams;
        if (!this.initialGroupBy) {
            this.initialGroupBy = searchParams.context.graph_groupbys || this.metaData.groupBy; // = arch groupBy --> change that
        }
        this.data = {'value': '测试'}
        // const metaData = this._buildMetaData();
        // await this._fetchDataPoints(metaData);
    }

4.6.Controller

在useEffect中用传过来的template_xmlid,model中的解析数据生成template页面,并且替换o_content。

export class ReportController extends Component {
    setup() {
        this.archInfo = this.props.archInfo;
        this.model = useModelWithSampleData(this.props.Model, this.props.modelParams);
        useSetupView({
            rootRef: useRef("root"),
            getLocalState: () => {
                return { metaData: this.model.metaData };
            }
        });
        this.rootRef = useRef("root");
        this.searchBarToggler = useSearchBarToggler();
        useEffect(() => this.renderReport());
    }
    renderReport() {
        const innerHTML = renderToString(this.archInfo.template_xmlid, {
            model: this.model
        });
        const template = Object.assign(document.createElement("template"), { innerHTML });
        const tooltip = template.content.firstChild;
        // 将o_content替换为tooltip
        this.rootRef.el.querySelector('.o_content').replaceWith(tooltip);
    }
}

4.6.实现效果

在这里插入图片描述

5.总结

通过新增视图类型的方式
1、实现了controller的上半部分统一的效果,比如搜索的多选,新增数字筛选等
2、减少了report开发人员的工作量,开发人员可以专注于template的实现,真正做到组件化。


http://www.kler.cn/a/582227.html

相关文章:

  • C++竞赛级输入输出优化实战
  • 通过Golang的container/list实现LRU缓存算法
  • 大数据任务调度:DolphinScheduler、Airflow 实战(调度策略、任务依赖)
  • Python基于深度学习的电影评论情感分析可视化系统(全新升级版)【附源码、参考文档】
  • 【每日学点HarmonyOS Next知识】拖拽调整列表顺序、tab回弹、自定义弹窗this、状态变量修饰枚举
  • 工作中,当遇到要把http请求变成https时 怎么处理
  • spring 的model repository service controller的功能
  • Yashan DB 文件管理
  • 《深度剖析架构蒸馏与逻辑蒸馏:探寻知识迁移的差异化路径》
  • 【音视频】ffmpeg命令提取像素格式
  • 20250212:linux系统DNS解析卡顿5秒的bug
  • 在 Spring Boot 2.7.x 中引入 Kafka-0.9 的实践
  • vscode 好用插件
  • MySQL-储存引擎
  • 深度解析:如何在 Vue 3 中安全访问子组件实例
  • 使用STM32CubeMX配置定时器中断实现LED每秒闪烁一次(STM32G070CBT6)
  • windows上传uniapp打包的ipa文件到app store构建版本
  • Selenium 中 ActionChains 支持的鼠标和键盘操作设置及最佳实践
  • 密码学系列 - 利用CPU指令加速
  • 高效自动化测试:打造Python+Requests+Pytest+Allure+YAML的接口测试框架