模块安装
1、依赖安装,模块下载以后,需要选安装相关依赖,模块目录下有一个requirement.txt,使用
pip install -r requirement.txt

进行安装。特别注意,安装依赖的环境和你运行odoo的环境需保持一致。
2、将模块复制到odoo的模块目录,一般情况下不要和odoo自有模块混在一起,所以最好是单独建一个第三方插件目录

将第三方模块放到此目录。模块放置完成以后,重启odoo,然后更新模块列表


更新完成以后搜索

点击启用进行安装。安装完成以后,在菜单中可以看到仪表板。

由于odoo本身的表单视图并不规整,所以,还可以选择安装ylhc_form_style,以使表单更规整

安装完成以后表单样式如下

基础配置
安装完成以后,还需要一定配置,由于引入了ai,所以先要进行相关配置(特别说明,使用ai为建议项,并非强制项),打开open ai菜单(需要管理员权限,管理员才能进行配置)



填入key

注意看下模型里边有没有要使用到的模型,如果没有自行添加。设置好模型提供商以后还需要创建一个配置,用于配置到底使用哪个供应商及模型和相关参数


点击测试可以确定是否能正常链接

可以看到,此时已经正常连接,接下来要设置各个编辑器使用的配置,如果没能配置则使用默认配置


创建看板
经过前边的准备工作,这个时候便可以创建看板,点击新建按扭

弹出新建对话框,看板有两种模式,一种流式定位,一种绝对定位,这里先点normal

单击选择, 填写看板名称,选择全局时间范围,如果不需要限制时间范围则把使用时间范围取消掉

其它仪表板HTML等为系统自带的模板信息,一般情况下不用修改,只有特殊诉求时才需要进行更改,如因为错误操作导致无法进入看板等,可以在这里个复以后再进入,仪表板CSS等只有需要自定义一些特殊样式才需要在这里添加,其它一些信息也是为了让用户知道相关内容,一般情况下不需要填写。点击保存。

些时已经进入看板编辑界面。如果是已经创建的看板则从编辑看板处进入
看板概览
看板编辑界面中包含了挺多信息,现逐步介绍

样式区域如下


设置(选项)区域, 一些特殊区域,为了方便设置了一些特列属性,方便用户先择配置,如下

基础模块区域

区块中的元素拖动后到编辑区域


现在分别对每个区块进行介绍
1、图像。

拖动图像进入编辑区会自动弹出图像选择框,左侧为分类筛选,可以点击选择图像,如果没有自己需要的图像也可以在右侧上传后选择

图像选择后可以调整大小,调节手柄

2、视频。

拖动到编辑区以后,点击设置,配置源

需要选择
(1)、提供方。
html则为视频的html地址。其它为国外网视频网站。
(3)、poster,封面。


4、框架。


取得嵌入代码以后再提取地址



卡片是一个非常重要的元素,用于将区块分开,主要用于布局,拖动到页面以后效果如下

可以通过添加样式更改卡片效果

选择一个自己喜欢的样式

最终效果如下

一般情况下,为了避免重复操作,设置一个卡片之后复制多份进行布局。

自定义脚本用于一些系统功能无法满足时需要通过脚本才能控制的场景,此功能稍后详解,此处先作了解。扡动手点击铅笔

脚本图标只会在编辑模式下显示,在预览或是视图模式下会自动隐藏

特别说明,这里的表格只是用于布局的表格,并非展示数据的表格

鼠标放在元边框线上时可以拖动改变行或列的宽度或高度。同时,按住alt键和鼠鼠标左键可以弹出功能菜单,可以添加列或行

功能分别为
合并单元格需要按住alt的同时,鼠标左键拖动选中多个单元格后,点击合并单元格进行合并,效果如下


8、字体图标。


与图像一样,双击弹出对话框进行选择

9、html。

html为系统中一个强大的功能,此功能为系统引入了无限可能,拖动到编辑区以后会弹出选择对话框

左侧有分类筛选,选择需要插入的区块楚然到看板。html需要配合脚本模块才能完全发挥作用,后续再作深入介绍。
10、svg图标。


此功能主要用于设置动态边框,效果如下

在设置界面可以进行参数配置

效果如下

12、文本。

13、标题。

14、段落。

段落为多行文本。
15、链接。

链接为跳转到其它链接,在设置中进行配置,特别说明,只有在预览或是视图模式下才生效。


以下三个都用于布局,本质上是bootstrap的container, row和column。本身初始时就已经放入了容器,栏中可以嵌入窗口或行实现复杂布局。



17、警报

拖入后效果如下

设置中可以选择样式

不同样式有不同的效果。
18、徽标。

一般用于文本未尾进行强调显示,如"new"或是“活动”等。
19、按扭。

效果如下

可以通过添加样式更改显示效果

选择后效果如下

设置面版中可以设置按扭行为

20、统计。

此功能需结合数据源,暂不作介绍。主要用于统计百分比和表字段统计值,如总人数、总分数等。
21、qweb.

qweb通过模板和数据源展示数据。
22、计数器。

和统计比较类似,只是以动画的形式展示,统计也可以添加动画样式达到相同的效果。
23、图表相关。

些部份在图表部份再作详细介绍,此部份为各种类型图表。

搜索相关,此部份在搜索章节详细介绍。
24、自定义列表。

此组件本质上和qweb template是同一类型,只不过是针对列表。用于数据展示。
25、tab页

标签页是设计中常见的元素,效果如下

双击文字标签可以进行编辑,content区域可以拖动其它元素

删除顶部tabitem可以删除tab页,在设置中也可以添加新的tab页

页面布局
设计一个看板之前实际上要做的事情就是进行布局,前边我们已经讲过容器、行、栏及卡片,主要通过这几个进行布局。布局主要通过添加行

添加栏位

添加卡片

内部数据源
看板中支持内部数据源和外部数据源,数据源可以单独配置,也可以在区块中临时配置。先以内部数据源为例:
(1)、拖动一个柱图到编辑区中。点击编辑按扭

弹出配置界面

选择内部数据源类型,默认为模型,数据源共有以下几中类型
a、模型。
通过odoo系统自有模型进行配置,在odoo体系推荐的方式。需要选择模型及字段。
b、方法。
调用一个模型方法,需要返回结果数据。
c、代码。
一段python代码。
d、json。
静态json数据,主要用于测试。
e、http接口。
调用http接口获取数据
f、sql.
通过sql查询
g、无。
一般用于嵌入脚本。
下面分别进行介绍:
a、选择模型, 以partner为例:

选择以后再对字段进行配置, 选择通过city字段进行分组

配置完成以后,选择查询按扭,在结果字段中会有最终的字段信息

系统会默认选择第一个分组作为x轴,__count作为y轴,点击预览可以查看效果。也可以自己指定轴,如果还需要其它字段,则在字段中选择。searchkey,用于指定搜索的key,这个key主要和搜索的元素进行绑定,后续介绍搜索时再具体说明,分组聚合用于当分组时,这个字段的聚合方式,如统计数量(count)或是累加(sum),或是最大值(max)或是最小值(min)等。
参数用于指定一些本区块特有的数据,如指定index为1, 则这个区块的index为1,目的是为了提供给后续脚本使用。
排序用于选择排序的字段,可以一个也可以多个,多个排在前边的优先级较高。
域和上下文用于限定数据的范围,如下

可以通过域配置器进行配置

但一些复杂的情况,如动态的情况等,这个时候就需要在额外域中手动填写

上下文用于传递一些信息给脚本等,一般情况下不需要使用
限制用于限制数据返回的条数,避免过多数据操作,默认为不限制。

从上下文中获取为ODOO特定的约定,如列表等跳转过来时,这个时候会当前活动的ids,也就是在列表中选中的项,从表单跳转则有为id。这个主要用于打印报表等,需要根据用户选择动态决定数据的范围。

结果字段为最终的数据字段,如分组会有__count字段,也有__domain字段,一个是数量,一个是此分组的域。 同时在这里也可以设置x轴,只能设置一个x轴,度量对应y轴,可以选择多个度量,同时,不同的度量可以选择不同的系列,也就是可以一个度量使用柱状图,一个度量使用折线图。隐藏用于表格等显示时不显示此字段。此处,以city为x转,没有选择时以__count有y轴。配置多个轴的效果如下

如果一个度量使用折线

对于时间等,可以按年、按月、按时、按天、按小时进行分类统计,以销售为例:

可以看到最终结果按月进行分组统计。
脚本标签页为当前图表使用的脚本,将脚本开放出来的目的是为了在特定情况下可以对脚本进行修改以满足特定要求,同时,脚本集成了ai,可能通过ai对脚本进行修改。如

ai返回以后,点击预览

可以看到,很方便就对脚本进行了调整。
数据页为数据预览

事件页为图表事件,如图表点击等,默认不添加事件,注意,不同的配置需要使用不同的脚本,默认脚本只支持odoo模型方式配置数据源,其它方式无效

关联到配置为联动设置,后续联动部份再进行详细讲解。以上为通过模型方式配置数据。
b、通过sql配置数据。

sql查询完成以后,同样需要配置图表字段信息

其它操作与模型方式相同。
c、通过代码.

示便代码如下:
# 使用read_group按客户分组统计订单数量
data = env['sale.order'].read_group(
domain=[('state', 'in', ['sale', 'done'])], # 只统计已确认或完成的订单
fields=['partner_id'],
groupby=['partner_id']
)
result = []
for item in data:
partner_name = item['partner_id'][1] if item['partner_id'] else '未知客户'
result.append({
'customer': partner_name,
'order_count': item['partner_id_count'],
'customer_id': item['partner_id'][0] if item['partner_id'] else None
})
# 按订单数量降序排序
result.sort(key=lambda x: x['order_count'], reverse=True)

d、通过方法,通过方法本质上与代码相同。

方法实现如下
@api.model
def get_test_data(self, extra_context):
"""
get test data from data source
"""
data = [
{ 'product': 'Matcha Latte', '2015': 43.3, '2016': 85.8, '2017': 93.7 },
{ 'product': 'Milk Tea', '2015': 83.1, '2016': 73.4, '2017': 55.1 },
{ 'product': 'Cheese Cocoa', '2015': 86.4, '2016': 65.2, '2017': 82.5 },
{ 'product': 'Walnut Brownie', '2015': 72.4, '2016': 53.9, '2017': 39.1 }]
return data
这种方式适合一些特别复杂的场景,如需要多种数据聚合时。
d、通过json。
此种方式最为简单,只需要填写json数据便可

同样也需要配置字段

e、通过http接口。

接口实现
# -*- coding: utf-8 -*-
from odoo import http
from odoo.http import request
import json
class TestHttpAPIController(http.Controller):
"""
Test HTTP API Controller for testing HTTP data source
"""
@http.route('/api/test/users', type='http', auth='public', methods=['GET'], csrf=False)
def get_test_users(self, **kwargs):
"""
Test endpoint - Get users list
Returns sample user data
"""
data = {
'status': 'success',
'data': [
{'id': 1, 'name': 'John Doe', 'email': 'john@example.com', 'age': 30, 'department': 'IT'},
{'id': 2, 'name': 'Jane Smith', 'email': 'jane@example.com', 'age': 28, 'department': 'HR'},
{'id': 3, 'name': 'Bob Johnson', 'email': 'bob@example.com', 'age': 35, 'department': 'Sales'},
{'id': 4, 'name': 'Alice Brown', 'email': 'alice@example.com', 'age': 32, 'department': 'IT'},
{'id': 5, 'name': 'Charlie Wilson', 'email': 'charlie@example.com', 'age': 29, 'department': 'Marketing'},
],
'total': 5
}
return request.make_response(
json.dumps(data),
headers=[('Content-Type', 'application/json')]
)
字段配置如下:

外部数据
虽然我们建议在ODOO体系内使用,便的确存在访问外部数据库的情况,外部数据库可以通过三种方式解决
(1)、在odoo内通过代码连接第三方数据库,读取相关数据。
(2)、通过fdw映射数据库到odoo内。
(3)、通过接下来介绍的外部数据库获取。
1、打开数据库菜单。

2、创建数据库链接。

填写数据库信息

配置完成以后,点击测试按扭确认是否能正常链接。
3、同步数据表。由于ai需要知道数据表结构,所以需要同步数据表信息。

勾选要同步的表,如果表不是特别多可以全部同步,如果太多则最好勾选使用到的表,避免信息过多。同步完成以后便可以使用外部数据库。在编辑区拖入一个图表,进入配置窗口,选择sql以及外部数据源

编写sql语句,也可以通过ai生成,对于复杂的调用,可以在数据库一侧编写函数,通过查询函数实现复杂逻辑,sql函数如何写不在本系统考虑范围

如,本例子为,"查询客户的订单数量,限制为前5名", 字段配置如下:

模板
大屏中需要展示的内容往往不止图表和表格,很多时候往往有更多的自定义内容,这个时候便需要使用到模板,由于在odoo体系,所以绑定为qweb模板,不清楚qweb模板语法请参考这个地址。具体使用如下:
1、拖动一个qweb模板到界面中。
与图表相同,点击编辑按扭进行配置, 配置界面与图表相同
同样,配置数据源之后,脚本里调用render_template渲染模板
render_template传递的参数如果是一个数组,在模板中通过datas获取,如果是一个字典则直接通过访问,如传递的是{'name': 'dashboard'}则在模板中可以直接访问name变量,模板如下:此时,需要将数据和模板绑定在一起,这样从后端取回来的数据才能显示到界面, 此时,需要按照qweb的语法将数据绑定到模板下,数据在上下文的datas中,也可以通过下面的方式获得。
<div class="card shadow-sm border">
<div class="card-body d-flex flex-column align-items-center text-center p-4">
<!-- 比特币 SVG 图标(替换原图片) -->
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="currentColor" class="mb-3 rounded-circle border-2 border-light">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-11h2v6h-2zm0 8h2v2h-2z"/>
</svg>
<!-- 标题 -->
<h3 class="text-dark mb-1 fw-bold fs-5">Bitcoin</h3>
<!-- 描述 -->
<p class="text-muted mb-3 fw-medium fs-7">
Bitcoin is up 88% in 2021 despite turbulent markets
</p>
<!-- 分隔线 -->
<hr class="w-100 my-3" style="border-top: 1px dashed #dee2e6;" />
<!-- 价格与涨幅 -->
<div class="text-center w-100">
<h3 class="text-dark mb-1 fw-bold fs-4">$50,289.45</h3>
<p class="text-muted mb-0 fw-medium fs-7">
Bitcoin
<span class="text-muted fs-8">(BTC)</span>
<span class="text-success ms-2">
+2.5%
<i class="bi bi-arrow-up"></i>
</span>
</p>
</div>
<!-- 购买按钮 -->
<button type="button" class="btn btn-success mt-4 px-4 py-2 fw-medium">
<i class="bi bi-cart-plus me-1"></i> Buy
</button>
</div>
</div>
<t t-set="config" t-value="this.get_config()" />
<t t-set="data_source" t-value="config.get_data_source(0)" />
<t t-set="records" t-value="data_source.get_raw_datas()" />
以取得今日的销售订单为例,同时和昨日进行对比,配置如下

注意,这里由于要做对比,所以要取得上一周期的数据,所以也要做周期相关的配置,字段配置如下图。点击预览获取字段信息


这里ai会自动对数据进行绑定。当然,也可以自行修改qweb,代码如下
<t t-set="data_source" t-value="config.get_data_source(0)"/>
<t t-set="current_data" t-value="data_source.get_raw_datas()"/>
<t t-set="current_total" t-value="current_data.reduce((sum, record) => sum + record.amount_total, 0)"/>
<t t-set="prev_data_source" t-value="data_source.get_previous_data_source()"/>
<t t-set="prev_total" t-value="prev_data_source ? prev_data_source.get_raw_datas().reduce((sum, record) => sum + record.amount_total, 0) : 0"/>
<t t-set="change_percent" t-value="prev_total ? ((current_total - prev_total) / prev_total * 100) : 0"/>
<div class="card shadow-sm border">
<div class="card-body d-flex flex-column align-items-center text-center p-4">
<!-- 比特币 SVG 图标(替换原图片) -->
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="currentColor" class="mb-3 rounded-circle border-2 border-light">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-11h2v6h-2zm0 8h2v2h-2z"/>
</svg>
<!-- 标题 -->
<h3 class="text-dark mb-1 fw-bold fs-5">Total Sales</h3>
<!-- 描述 -->
<p class="text-muted mb-3 fw-medium fs-7">
<t t-esc="current_data.length"/> orders in current period
</p>
<!-- 分隔线 -->
<hr class="w-100 my-3" style="border-top: 1px dashed #dee2e6;" />
<!-- 价格与涨幅 -->
<div class="text-center w-100">
<h3 class="text-dark mb-1 fw-bold fs-4">
$<t t-esc="current_total.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2})"/>
</h3>
<p class="text-muted mb-0 fw-medium fs-7">
Sales Total
<span t-att-class="change_percent >= 0 ? 'text-success' : 'text-danger'" class="ms-2">
<t t-esc="(change_percent >= 0 ? '+' : '') + change_percent.toFixed(1) + '%'"/>
<i t-att-class="change_percent >= 0 ? 'bi bi-arrow-up' : 'bi bi-arrow-down'"></i>
</span>
</p>
</div>
<!-- 购买按钮 -->
<button type="button" class="btn btn-success mt-4 px-4 py-2 fw-medium">
<i class="bi bi-cart-plus me-1"></i> View Details
</button>
</div>
</div>
<t t-set="data_source" t-value="config.get_data_source(0)"/>
<t t-set="current_data" t-value="data_source.get_raw_datas()"/>
<t t-set="current_total" t-value="current_data.reduce((sum, record) => sum + record.amount_total, 0)"/>
<t t-set="prev_data_source" t-value="data_source.get_previous_data_source()"/>
<t t-set="prev_total" t-value="prev_data_source ? prev_data_source.get_raw_datas().reduce((sum, record) => sum + record.amount_total, 0) : 0"/>
<t t-set="change_percent" t-value="prev_total ? ((current_total - prev_total) / prev_total * 100) : 0"/>
此部份调用api获取第一个数据和对应的上一周期数据源,然后对数据进行处理之后展示。
图表
图表是看板中的重要组成部份,我们支持多种图表,大体分为系统固定图表和自定义图表,具体区别为,固定图表已经将脚本模式化,自定义图表需要将数据绑定到脚本,不过有ai辅助其实很简单,具体操作步骤如下:
(1)、拖动一个图表到界面中。区块会默认显示图表

(2)、点击编辑按扭配置数据,如何配置和之前数据源部份配置相同。

这里以城市为例进行分组。配置完成以后调击查询和预览,界面显示效果如图。如果要进行调整,可以在脚本页面使用ai进行调整,如:

效果如下:

当然,也还可以进行其它调整,最终字段配置中可以设置字段别名,如_count可以显示为数量

当然,也可以使用AI进行调整。也可以选择多个维度,并且可以不同方式显示,效果如下

其它图表设置大体相同。不再一一讲解。
自定义图表
虽然系统带了一些图表,但实际上看起来来够炫酷,同时,不管系统有再多的素材,总有不满足的时候,这个时候我们就可以利用第三方的资源,具体操作如下:
(1)、拖动一个自定义图表到编辑区。

(2)、点击编辑按扭配置数据源。配置数据源参考数据源部份

这里统计客户订单排名,字段选择客户并分组,点击查询,字段配置如下:

(3)、绑定脚本。点击切入到脚本分页。点开ai助手。

点击第一个绑定数据图标或自行输入

ai处理完成以后,点击预览,效果如下

这个时候发现文字和bar距离太远,需要近一些,同时只显示前5条就可以了,所以

再次预览,效果如下:

保存后效果如下

在引入ai以后,整体变得简单明了。同时,我们也可以从第三方引入更多自定久的图表,以https://www.isqqw.com/这个网站为便,我们从中挑选一个喜欢的图表,然后进行相应的配置。
搜索
搜索是看板的一个重要功能,看板支持全局搜索和局部搜索,具体操作如下:
1、拖入一个搜索组到界面中。

搜索组具有如下选项:

(1)、类型。全局还是还是局部,如果是全局则会对所有区块都发送消息,如果是局部则要选择区块。
(2)、立即,如果是立即,搜索项发生变化时立即就会搜索。否则需要点按扭以后才能进行。
(3)、加载上次搜索,也就是退出以后,下次进入时还能加载之前的搜索。
拖入组以后,拖入一个输入项,如下:

选项如下:

选项如下:
(1)、key,这个比较重要,这个作为这个项的标识,用于对应数据源中的字段。
(2)、标签,可以在这里修改,也可以在界面上双击修改。
(3)、是否显示标签。
(4)、是否显示操作符。如文本可能是等于,也可能是包含。
(5)、与&或,与其它项的组合方式。
(6)、是否立即生效。
(7)、默认值。
(8)、搜索时,是否传入到参数中。动态设置参数的值。
(9)、默认操作符。

此处我们使用这个配置,key设置为city。文本样式为靠右。

设置好了以后需要对数据源进行配置,选中图表,进入编辑

设置city的search key为city, 当然,只要能对应上,什么名字都可以



这里便只有点击搜索的时候才能生效。搜索按扭可以是应用,也可以是重置,重置需要设置类型为重置。

如此便实现了搜索与数据源绑定。
定时器
很多场景下,我们都需要对数据进行定时更新,这个时候便可以使用定时器功能,可以设置全局定时器,也可以设置局部定时器,同时,也支持多个定时器。使用方法如下:

拖动一个定时器容器到界面上,这个容器只为了便于管理,没有特别的配置,然拖入定时器。

定时器拖入以后设置定时器,

属性分别为:
(1)、间隔,每隔多时间发送一次定时消息。
(2)、目标,如果为空则为全局,如果指定则只给特定区块发送消息。
(3)、消息,默认消息为区块重载,如果有特殊诉求使用特殊名称。不用更改,只是为了给后面升级预留空间。
(4)、描述。
配置好以后,每隔一段时间,区块就会重新加载信息并刷新。
下钻
下钻也是个常见功能,如元素点击时跳转到相应的记录。看板中有两种下钻方式
(1)、跳转到系统的列表视图。
(2)、下钻到别的区块。
下面对两者分别介绍,选择一个图表,然后打开事件页,添加一个click事件的脚本
(1)、默认方式。

选择以后自动带入选择的脚本

保存。这个时候点击柱子

此时会跳转到相应的列表记录

(2)、下钻到其它配置。
同样,在界面中选中一个图表,点击下钻按扭:

这个时候弹出下钻的配置界面,下面以客户的销售订单为例

点击几下钻取,设置上下关联

变量设置为
API
设计一个看板之前实际上要做的事情就是进行布局,前边我们已经讲过容器、行、栏及卡片,主要通过这几个进行布局。布局主要通过添加行
API
设计一个看板之前实际上要做的事情就是进行布局,前边我们已经讲过容器、行、栏及卡片,主要通过这几个进行布局。布局主要通过添加行
API
设计一个看板之前实际上要做的事情就是进行布局,前边我们已经讲过容器、行、栏及卡片,主要通过这几个进行布局。布局主要通过添加行



