效果图:

实现代码:js:view的类型原来1个js给拆分成了4个: view, controller, renderer, model

1、viewAbstractView的子类,这是工厂类:类需要解析 arch字段并设置其它3个类

2、Renderer 渲染器,来自 AbstractRenderer:负责在用户界面中展示数据;

3、Controller一个控制器 (来看AbstractController):用于协调、与网页客户端对话

4、Model一个模型 (来自 AbstractModel):用于和服务端对话、加载数据并处理数据

步骤:一、二、三、四案例

一、MVCR:

var MapController = AbstractController.extend({});
var MapRenderer = AbstractRenderer.extend({});
var MapModel = AbstractModel.extend({});

var MapView = AbstractView.extend({
  config: {
    Model: MapModel,
    Controller: MapController,
    Renderer: MapRenderer,
  },
});

二、告知网页客户端视图名称和实际类之间的映射。
var viewRegistry = require('web.view_registry');
viewRegistry.add('helpdesk_dashboard', HelpdeskDashboardView);

三、现在我们需要告知网页客户端指定的 ir.ui.view需要使用我们的新类。注意这是一个网页客户端的具体考虑。

从服务端的视角来看,我们还是对应看板视图。这么做的相应方式是通过对框架的根节点使用特殊属性js_class

<record id="helpdesk_team_view_kanban" model="ir.ui.view" >
...
  <field name="arch" type="xml">
  <kanban js_class="helpdesk_dashboard">
...
</kanban>
</field>
</record>

案例:

odoo.define('purchase.dashboard', function (require) {
"use strict"; /**
* This file defines the Purchase Dashboard view (alongside its renderer, model
* and controller). This Dashboard is added to the top of list and kanban Purchase
* views, it extends both views with essentially the same code except for
* _onDashboardActionClicked function so we can apply filters without changing our
* current view.
*/ var core = require('web.core');

//这里是列表视图上的扩展:导入的模块
var ListController = require('web.ListController');
var ListModel = require('web.ListModel');
var ListRenderer = require('web.ListRenderer');
var ListView = require('web.ListView');

//这里是kanban视图上的扩展:
var KanbanController = require('web.KanbanController');
var KanbanModel = require('web.KanbanModel');
var KanbanRenderer = require('web.KanbanRenderer');
var KanbanView = require('web.KanbanView');

var SampleServer = require('web.SampleServer');
//注册模块
var view_registry = require('web.view_registry'); var QWeb = core.qweb; // Add mock of method 'retrieve_dashboard' in SampleServer, so that we can have
// the sample data in empty purchase kanban and list view
let dashboardValues;
SampleServer.mockRegistry.add('purchase.order/retrieve_dashboard', () => {
return Object.assign({}, dashboardValues);
}); //--------------------------------------------------------------------------
// List View
//--------------------------------------------------------------------------
//渲染renderer
var PurchaseListDashboardRenderer = ListRenderer.extend({
events:_.extend({}, ListRenderer.prototype.events, {
'click .o_dashboard_action': '_onDashboardActionClicked',
}),
/**
* @override
* @private
* @returns {Promise}
*/
_renderView: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
var values = self.state.dashboardValues;
var purchase_dashboard = QWeb.render('purchase.PurchaseDashboard', {
values: values,
});
self.$el.prepend(purchase_dashboard);
});
}, /**
* @private
* @param {MouseEvent}
*/
_onDashboardActionClicked: function (e) {
e.preventDefault();
var $action = $(e.currentTarget);
this.trigger_up('dashboard_open_action', {
action_name: $action.attr('name')+"_list",
action_context: $action.attr('context'),
});
},
});


//模型 model
var PurchaseListDashboardModel = ListModel.extend({
/**
* @override
*/
init: function () {
this.dashboardValues = {};
this._super.apply(this, arguments);
}, /**
* @override
*/
__get: function (localID) {
var result = this._super.apply(this, arguments);
if (_.isObject(result)) {
result.dashboardValues = this.dashboardValues[localID];
}
return result;
},
/**
* @override
* @returns {Promise}
*/
__load: function () {
return this._loadDashboard(this._super.apply(this, arguments));
},
/**
* @override
* @returns {Promise}
*/
__reload: function () {
return this._loadDashboard(this._super.apply(this, arguments));
}, /**
* @private
* @param {Promise} super_def a promise that resolves with a dataPoint id
* @returns {Promise -> string} resolves to the dataPoint id
*/
_loadDashboard: function (super_def) {
var self = this;
var dashboard_def = this._rpc({
model: 'purchase.order',
method: 'retrieve_dashboard',
});
return Promise.all([super_def, dashboard_def]).then(function(results) {
var id = results[0];
dashboardValues = results[1];
self.dashboardValues[id] = dashboardValues;
return id;
});
},
});

//控制器:controller
var PurchaseListDashboardController = ListController.extend({
custom_events: _.extend({}, ListController.prototype.custom_events, {
dashboard_open_action: '_onDashboardOpenAction',
}), /**
* @private
* @param {OdooEvent} e
*/
_onDashboardOpenAction: function (e) {
return this.do_action(e.data.action_name,
{additional_context: JSON.parse(e.data.action_context)});
},
});

//视图 view
var PurchaseListDashboardView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Model: PurchaseListDashboardModel,
Renderer: PurchaseListDashboardRenderer,
Controller: PurchaseListDashboardController,
}),
});

//--------------------------------------------------------------------------
// Kanban View
//-------------------------------------------------------------------------- var PurchaseKanbanDashboardRenderer = KanbanRenderer.extend({
events:_.extend({}, KanbanRenderer.prototype.events, {
'click .o_dashboard_action': '_onDashboardActionClicked',
}),
/**
* @override
* @private
* @returns {Promise}
*/
_render: function () {
var self = this;
return this._super.apply(this, arguments).then(function () {
var values = self.state.dashboardValues;
var purchase_dashboard = QWeb.render('purchase.PurchaseDashboard', {
values: values,
});
self.$el.prepend(purchase_dashboard);
});
}, /**
* @private
* @param {MouseEvent}
*/
_onDashboardActionClicked: function (e) {
e.preventDefault();
var $action = $(e.currentTarget);
this.trigger_up('dashboard_open_action', {
action_name: $action.attr('name')+"_kanban",
action_context: $action.attr('context'),
});
},
}); var = KanbanModel.extend({
/**
* @override
*/
init: function () {
this.dashboardValues = {};
this._super.apply(this, arguments);
}, /**
* @override
*/
__get: function (localID) {
var result = this._super.apply(this, arguments);
if (_.isObject(result)) {
result.dashboardValues = this.dashboardValues[localID];
}
return result;
},
/**
* @override
* @returns {Promise}
*/
__load: function () {
return this._loadDashboard(this._super.apply(this, arguments));
},
/**
* @override
* @returns {Promise}
*/
__reload: function () {
return this._loadDashboard(this._super.apply(this, arguments));
}, /**
* @private
* @param {Promise} super_def a promise that resolves with a dataPoint id
* @returns {Promise -> string} resolves to the dataPoint id
*/
_loadDashboard: function (super_def) {
var self = this;
var dashboard_def = this._rpc({
model: 'purchase.order',
method: 'retrieve_dashboard',
});
return Promise.all([super_def, dashboard_def]).then(function(results) {
var id = results[0];
dashboardValues = results[1];
self.dashboardValues[id] = dashboardValues;
return id;
});
},
}); var PurchaseKanbanDashboardController = KanbanController.extend({
custom_events: _.extend({}, KanbanController.prototype.custom_events, {
dashboard_open_action: '_onDashboardOpenAction',
}), /**
* @private
* @param {OdooEvent} e
*/
_onDashboardOpenAction: function (e) {
return this.do_action(e.data.action_name,
{additional_context: JSON.parse(e.data.action_context)});
},
});

通过VIEW来设置它
var PurchaseKanbanDashboardView = KanbanView.extend({
config: _.extend({}, KanbanView.prototype.config, {
Model: PurchaseKanbanDashboardModel,
Renderer: PurchaseKanbanDashboardRenderer,
Controller: PurchaseKanbanDashboardController,
}),
});

//视图类型和实际类之间的映射需要进行更新
view_registry.add('purchase_list_dashboard', PurchaseListDashboardView);
view_registry.add('purchase_kanban_dashboard', PurchaseKanbanDashboardView); return {
PurchaseListDashboardModel: PurchaseListDashboardModel,
PurchaseListDashboardRenderer: PurchaseListDashboardRenderer,
PurchaseListDashboardController: PurchaseListDashboardController,
PurchaseKanbanDashboardModel: PurchaseKanbanDashboardModel,
PurchaseKanbanDashboardRenderer: PurchaseKanbanDashboardRenderer,
PurchaseKanbanDashboardController: PurchaseKanbanDashboardController
}; });

Dashboard的page的xml

<?xml version="1.0" encoding="UTF-8"?>
<templates>
<!-- This template is for a table at the top of purchase views that shows some KPIs. -->
<t t-name="purchase.PurchaseDashboard">
<div class="o_purchase_dashboard container">
<div class="row">
<div class="col-sm-5">
<table class="table table-sm">
<!-- thead needed to avoid list view rendering error for some reason -->
<thead>
<tr>
<!-- can't use th tag due to list rendering error when no values in list... -->
<td class="o_text">
<div>All RFQs</div>
</td>

<td class="o_main o_dashboard_action" title="All Draft RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_draft_rfqs": true}'>
<a href="#"><t t-esc="values['all_to_send']"/><br/>To Send</a>
</td>
<td class="o_main o_dashboard_action" title="All Waiting RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_waiting_rfqs": true}'>
<a href="#"><t t-esc="values['all_waiting']"/><br/>Waiting</a>
</td>
<td class="o_main o_dashboard_action" title="All Late RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_late_rfqs": true}'>
<a href="#"><t t-esc="values['all_late']"/><br/>Late</a>
</td>
</tr>
</thead>
<tbody>
<tr>
<td class="o_text">
<div>My RFQs</div>
</td>
<td class="o_main o_dashboard_action" title="My Draft RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_draft_rfqs": true, "search_default_my_purchases": true}'>
<a href="#"><t t-esc="values['my_to_send']"/></a>
</td>
<td class="o_main o_dashboard_action" title="My Waiting RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_waiting_rfqs": true, "search_default_my_purchases": true}'>
<a href="#"><t t-esc="values['my_waiting']"/></a>
</td>
<td class="o_main o_dashboard_action" title="My Late RFQs" name="purchase.purchase_action_dashboard" context='{"search_default_late_rfqs": true, "search_default_my_purchases": true}'>
<a href="#"><t t-esc="values['my_late']"/></a>
</td>
</tr>
</tbody>
</table></div> <div class="col-sm-7">
<table class="table table-sm">
<!-- thead needed to avoid list view rendering error for some reason -->
<thead>
<tr>
<!-- can't use th tag due to list rendering error when no values in list... -->
<td class="o_text">Avg Order Value (<t t-esc="values['company_currency_symbol']"/>)</td>
<td><span><t t-esc="values['all_avg_order_value']"/></span></td>
<td class="o_text">Purchased Last 7 Days (<t t-esc="values['company_currency_symbol']"/>)</td>
<td><span><t t-esc="values['all_total_last_7_days']"/></span></td>
</tr>
</thead>
<tbody>
<tr>
<td class="o_text">Lead Time to Purchase</td>
<td><span><t t-esc="values['all_avg_days_to_purchase']"/>  Days</span></td>
<td class="o_text">RFQs Sent Last 7 Days</td>
<td><span><t t-esc="values['all_sent_rfqs']"/></span></td>
</tr>
</tbody>
</table></div>
</div></div>
</t>
</templates>

导入js

<?xml version="1.0"?>
<odoo>
<template id="assets_backend" name="purchase assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" type="text/scss" href="/purchase/static/src/scss/purchase.scss"/>
<script type="text/javascript" src="/purchase/static/src/js/purchase_dashboard.js"></script>
</xpath> </template> </odoo>

最后引用:

                <kanban class="o_kanban_mobile" js_class="purchase_kanban_dashboard" sample="1"></kanban>


          <tree  class="o_kanban_mobile" js_class="purchase_kanban_dashboard" sample="1"></tree>
 

odoo14在tree、kanban视图上添加dashboard的更多相关文章

  1. iOS开发如何在一个透明视图上添加不透明的子控件

    相信很多同学都会遇到过这个问题, 当我们弹出一个半透明的遮盖层时, 又想在遮盖层上加一些子视图, 这个时候如果你的遮盖层设置了alpha属性,  你会惊讶的发现, 加载遮盖层上的所有子控件都是透明了, ...

  2. IOS 在一个透明视图上添加不透明的子控件

    环境: 在一个透明的view中添加一个tableview,tableview也变透明了. 解决: 不要这样设置view的透明度 view.backgroundColor = [UIColor clea ...

  3. iOS处理视图上同时添加单击与双击手势的冲突问题

    _bgView.userInteractionEnabled = YES; //在cell上添加 bgView,给bgView添加两个手势检测方法 UITapGestureRecognizer *do ...

  4. 在TableView上添加悬浮按钮

    如果直接在TableVIewController上贴Button的话会导致这个会随之滚动,下面解决在TableView上实现位置固定悬浮按钮的两种方法: 1.在view上贴tableView,然后将悬 ...

  5. 如何在TableView上添加悬浮按钮

    如果直接在TableVIewController上贴Button的话会导致这个会随之滚动,下面解决在TableView上实现位置固定悬浮按钮的两种方法: 1.在view上贴tableView,然后将悬 ...

  6. PDF如何设置书签,怎么在PDF上添加书签

    PDF文件现在作为我们使用最多的一种办公文件,当然我们在使用PDF文件的同时还会需要编辑PDF文件,在使用一个PDF文件页数比较多的时候就需要添加书签,不然每次使用的时候都需要从头开始查找是很麻烦又头 ...

  7. Android自定义视图一:扩展现有的视图,添加新的XML属性

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  8. ASP.NET#在设计窗口上添加了一个SqlDataSource控件后,没有显示出来?

    在设计窗口上添加了一个SqlDataSource控件后,没有显示出来,但后台代码是有的 处理的办法:菜单栏->视图->可视辅助->ASP.NET非可视控件 (我用的是VS2012)

  9. django class类即视图类添加装饰器的几种方法

    根据别人发布整理,个人爱好收集(原文:https://blog.csdn.net/mydistance/article/details/83958655 ) 第一种:定义函数装饰器,在函数,类中使用函 ...

随机推荐

  1. PAT甲级 1093 Count PAT‘s (25 分) 状态机解法

    题目 原题链接 The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the ...

  2. Windows的静态库与动态库

    Windows的静态库与动态库 1.静态库 1.1 静态库特点 运行不存在 静态库源码被链接到调用程序中 目标程序的归档 1.2 C语言静态库 C静态库的创建 创建一个静态库项目. 添加库程序,源文件 ...

  3. .NET Core/.NET5/.NET6 开源项目汇总5:权限管理系统项目

    系列目录     [已更新最新开发文章,点击查看详细] 企业管理系统一般包含后台管理UI.组织机构管理.权限管理.日志.数据访问.表单.工作流等常用必备功能.下面收集的几款优秀开源的管理系统,值得大家 ...

  4. ffmpeg-入门介绍(笔记)

    一.FFmpeg的基本组成 目前,ffmpeg有7大库,分别为AVFormat, AVCodec, AVFilteer, AVDecoder, AVUtil,Swresample, Swscale,A ...

  5. ubuntu 18.4LTS 安装12.1.6赛门铁克防病毒系统

    创建/tools/ 文件夹,并将需要的软件包上传到该目录下 # mkdir -p /tools/ && cd /tools/ # tar -xzvf chang.tar.gz # cd ...

  6. 跟我一起学Go系列:Go gRPC 安全认证机制-SSL/TLS认证

    Go gRPC 系列: 跟我一起学Go系列:gRPC 拦截器使用 跟我一起学Go系列:gRPC 入门必备 第一篇入门说过 gRPC 底层是基于 HTTP/2 协议的,HTTP 本身不带任何加密传输功能 ...

  7. Java数据库开发(三)之——补充

    一.SQL注入与防范 使用PreparedStatement替代Statement对象,它提供了参数化SQL的方式 二.事务 定义 事务是并发控制的基本单位,满足ACID特征 原子性:atomicit ...

  8. LeSS 的诞生(一):大规模团队该何去何从

    <敏捷宣言>发布后,"敏捷"被越来越多的小型开发团队认可.与此同时,另一个问题也逐渐暴露了出来:以 Scrum 为首的敏捷方法论对那些大规模的开发团队并不友好. 基于此 ...

  9. ubuntu 替换某一内核模块

    流程 方法一 以下配置仅执行一次,并以 linux kernel 3.13.0 为例 $ cd ~ $ apt-get source linux-source-3.13.0 $ cd linux-3. ...

  10. RabbitMQ重试机制

    消费端在处理消息过程中可能会报错,此时该如何重新处理消息呢?解决方案有以下两种. 在redis或者数据库中记录重试次数,达到最大重试次数以后消息进入死信队列或者其他队列,再单独针对这些消息进行处理: ...