扫码阅读
手机扫码阅读

Odoo丨如何使用Odoo集成ECharts ?

328 2023-09-22


Odoo

神州数码云基地

在 Odoo 上的尝试、调研与分享



本期内容

Odoo集成ECharts

Odoo框架中自带的视图非常丰富,能给我们展示的数据关系和标准的流程体系。但是在实际的业务场景中,除了能将数据关系和流程体系展示出来,我们希望能够以更直观更美观更具科技感的形式的展示多维度的业务数据,以便给决策者提供依据。


故此数据可视化的应用场景也开始变得更加多样且视觉要求更高,下面就给大家介绍一下Odoo如何集成ECharts,在Odoo上实现数据的可视化场景

ECharts介绍

ECharts,一个使用 JavaScript 实现的开源可视化库。可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器,底层依赖轻量级的矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭,Echarts作为国内的优秀可视化库,兼容大部分场景,很容易进行定制化开发,所以选择使用Echarts

更多详细的内容,可查看官方文档 ⬇

https://echarts.apache.org/zh/index.html

如何使用Odoo

集成ECharts

页面效果

我们希望使用 Echarts 来做活动分布和活动统计方面的相关展示,以下就是我们的最终效果。

Odoo集成ECharts

Step 1 :

下载ECharts源码到本地

echarts源码:

https://github.com/apache/echarts/blob/5.3.0/dist/echarts.min.js

Step 2 :

下载中国地图源码到本地

China.js源码:

https://github.com/apache/echarts/tree/master/test/data/map/js

还有中国各省份地图和世界地图,请按需下载。

Step 3 :

将ECharts集成到Odoo中

将 ECharts.min.j s和 China.js 放到对应模块的 static/js 中,并在 template.xml 中引入这两个js。

ECharts使用

Step 1 :

在menu.xml中创建一个地图菜单

Step 2 :

在action.xml中绑定地图菜单的action

Step 3:

创建QWeb页面

"1.0" encoding="utf-8" ?><template> "quotation_map_page">  
"padding: 5px 10px 0 10px;">
"center" style="width:100%; height:58vh;background-color: #f7f9ff;display: flex;border-radius: 20px;">
"map" style="width: 40%; height: 80%;margin-top: 20px;">
"activeFlows" style="width: 10%; height: 70%;margin-left: 40px;margin-top: 40px;">
"innerbox"> "padding: 10px;background-color: white;border-radius: 6px;overflow-y: auto;margin-bottom: 0;"> "image-click"> "/xc_order/static/description/1.jpg" style="height: 100%;vertical-align: baseline;width: 100%;border-radius: 4px;"/> "image-click"> "/xc_order/static/description/2.jpg" style="height: 100%;vertical-align: baseline;width: 100%;border-radius: 4px;"/> "image-click"> "/xc_order/static/description/3.jpg" style="height: 100%;vertical-align: baseline;width: 100%;border-radius: 4px;"/> "image-click"> "/xc_order/static/description/4.png" style="height: 100%;vertical-align: baseline;width: 100%;border-radius: 4px;"/>
"activeContent" style="width: 40%; height: 80%;margin-left: 40px;margin-top: 20px;"> "activePhoto" src="/xc_order/static/description/4.png" style="height: 100%;vertical-align: baseline;width: 100%;border-radius: 8px;"/>
"text-align: center;color: #5784fd">活动现场照片
"footer" style="display: flex;align-items: center;border-radius: 20px;">
"left" style="width:27%; height:32vh;background-color: #f7f9ff;margin-top:10px; display: flex;">
"pie2" style="width: 50%; height:100%">
"current" style="width:36%; height:32vh;background-color: #f7f9ff;margin-top:10px;margin-left: 10px">
"bar" style="width: 100%; height:100%">
"right" style="width:36%; height:32vh;background-color: #f7f9ff;margin-top:10px;margin-left: 10px">
"line" style="width: 100%; height:100%">
template>

Step 4 :

创建对应js和css

可以通过option进行echarts配置,详情请看ECharts官网-配置项手册下载ECharts源码到本地。

(https://echarts.apache.org/zh/option.html#title)

odoo.define('quotation.pre.sale', function (require) { var framework = require("web.framework"); var session = require("web.session"); var crash_manager = require("web.CrashManager"); var AbstractAction = require('web.AbstractAction') var core = require('web.core') var map = AbstractAction.extend({ template: 'quotation_map_page',  start: function () { var self = this self.renderMap() self.renderPie() self.renderBar() self.renderLine() }, renderMap: function () { let self = this let option = { tooltip: { show: false }, geo: { map: "china", roam: false,// 一定要关闭拖拽 zoom: 1.23, center: [105, 36], // 调整地图位置 label: { normal: { show: false, //关闭省份名展示 fontSize: "10", color: "rgba(0,0,0,0.7)" }, emphasis: { show: false } }, itemStyle: { normal: { areaColor: "#0d0059", borderColor: "#389dff", borderWidth: 1, //设置外层边框 shadowBlur: 5, shadowOffsetY: 8, shadowOffsetX: 0, shadowColor: "#01012a" }, emphasis: { areaColor: "#184cff", shadowOffsetX: 0, shadowOffsetY: 0, shadowBlur: 5, borderWidth: 0, shadowColor: "rgba(0, 0, 0, 0.5)" } } }, series: [ { type: "map", map: "china", roam: false, zoom: 1.23, center: [105, 36], // geoIndex: 1, // aspectScale: 0.75, //长宽比 showLegendSymbol: false, // 存在legend时显示 label: { normal: { show: false }, emphasis: { show: false, textStyle: { color: "#fff" } } }, itemStyle: { normal: { areaColor: "#0d0059", borderColor: "#389dff", borderWidth: 0.5 }, emphasis: { areaColor: "#17008d", shadowOffsetX: 0, shadowOffsetY: 0, shadowBlur: 5, borderWidth: 0, shadowColor: "rgba(0, 0, 0, 0.5)" } } } ] }; var dataValue = this.dealWithData(); var data1 = dataValue.splice(0, 6); var options = { series: [ { type: "map", map: "china", roam: false, zoom: 1.23, center: [105, 36], // geoIndex: 1, // aspectScale: 0.75, //长宽比 showLegendSymbol: false, // 存在legend时显示 label: { normal: { show: false }, emphasis: { show: false } }, itemStyle: { normal: { areaColor: "#0d0059", borderColor: "#389dff", borderWidth: 0.5 }, emphasis: { areaColor: "#17008d", shadowOffsetX: 0, shadowOffsetY: 0, shadowBlur: 5, borderWidth: 0, shadowColor: "rgba(0, 0, 0, 0.5)" } } }, { name: "", type: "scatter", coordinateSystem: "geo", data: dataValue, //   symbolSize: function(val) { //     return val[2] / 10; //   }, symbol: "circle", symbolSize: 8, hoverSymbolSize: 10, tooltip: { formatter(value) { return value.data.name + "
" + "设备数:" + "22"; }, show: true }, encode: { value: 2 }, label: { formatter: "{b}", position: "right", show: false }, itemStyle: { color: "#0efacc" }, emphasis: { label: { show: false } } }, { name: "人数", type: "effectScatter", coordinateSystem: "geo", data: data1, symbolSize: 15, tooltip: { show: true }, encode: { value: 2 }, showEffectOn: "render", rippleEffect: { brushType: "stroke", color: "#0efacc", period: 9, scale: 5 }, hoverAnimation: true, label: { formatter: "{b}", position: "bottom", show: true }, itemStyle: { color: "#0efacc", shadowBlur: 2, shadowColor: "#333" }, zlevel: 1 } ] };  $(document).ready(() => { this.myEchart = echarts.init(document.getElementById('map')); this.myEchart.setOption(options); this.myEchart.setOption(option); this.myEchart.on('click', self.selectCity.bind(self)) // $('.image-click').on('click', this.changeImage.bind(this)) $(".image-click").on('click', self.changeImage.bind(self)); }); }, selectCity: function (ev){ console.log(ev.name)  }, changeImage: function (ev){ let imageSrc = $($(ev.target)[0]).attr('src') $('#activePhoto').attr('src', imageSrc)  }, dealWithData: function () { var data = [ { name: '北京', value: 1400 }, { name: '上海', value: 1000 }, { name: '深圳', value: 700 }, { name: '武汉', value: 999 }, { name: '成都', value: 400 }, ] var geoCoordMap = { 北京: [116.46, 39.92], 上海: [121.48, 31.22], 深圳: [114.07, 22.62], 武汉: [114.31, 30.52], 成都: [104.06, 30.67], }; var res = []; // for (var key in geoCoordMap) { //     data.push({name: key, value: geoCoordMap[key]}); // } for (var i = 0; i < data.length; i++) { var geoCoord = geoCoordMap[data[i].name]; if (geoCoord) { res.push({ name: data[i].name, value: geoCoord.concat(data[i].value) }); } } return res; }, renderPie: function () { let option2 = { title: { text: '活动类型', // subtext: 'Fake Data', left: 'center' }, color:['#1bfff1', '#5a87fd', '#5afdaf','#ffae63'], tooltip: { trigger: 'item' }, legend: { // orient: 'vertical', top:'bottom' }, series: [ { // name: 'Access From', type: 'pie', radius: '50%', data: [ {value: 30, name: '市场活动'}, {value: 40, name: '签约活动'}, {value: 15, name: '技术大会'}, {value: 15, name: '员工培训'}, ], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } ] }; $(document).ready(function () { this.myEchart2 = echarts.init(document.getElementById('pie2')); this.myEchart2.setOption(option2); }); }, renderBar: function () { let option = { title: { text: '活动数量统计', // subtext: 'Fake Data' left: 'center' }, color:['#1bfff1', '#5a87fd'], tooltip: { trigger: 'axis' }, legend: { data: ['内部活动', '外部活动'], top:'bottom' }, toolbox: { show: false, feature: { // dataView: {show: true, readOnly: false}, // magicType: {show: true, type: ['line', 'bar']}, // restore: {show: true}, // saveAsImage: {show: true} } }, calculable: true, xAxis: [ { type: 'category', // prettier-ignore data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] } ], yAxis: [ { type: 'value' } ], series: [ { name: '内部活动', type: 'bar', data: [ 200, 270, 320, 250, 380, 300, 200, 100, 50, 120, 170,200 ] }, { name: '外部活动', type: 'bar', data: [ 100, 170, 120, 250, 280, 200, 400, 200, 250, 220, 70,200 ] } ] }; $(document).ready(function () { this.myEchart = echarts.init(document.getElementById('bar')); this.myEchart.setOption(option); }); }, renderLine: function () { let option = { title: { text: '活动关注度', // subtext: 'Fake Data', left: 'center' }, // color:['#1bfff1', '#5a87fd'], xAxis: { type: 'category', data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] }, yAxis: { type: 'value' }, series: [ { data: [150, 230, 224, 218, 135, 147, 260,200, 250, 100, 230,50], type: 'line', symbolSize: 3,//拐点大小 smooth:false, itemStyle: { normal : { color:'#5a87fd', lineStyle:{ color:'#1bfff1' } } } } ] }; $(document).ready(function () { this.myEchart = echarts.init(document.getElementById('line')); this.myEchart.setOption(option); }); } })  core.action_registry.add('quotation.map.page', map); return map;}) 

Step 5 :

将新建的xml和js文件引入,升级模块后,进入对应菜单

完成以上步骤就实现在 Odoo 上集成 ECharts 的整个过程和使用方式。

从步骤来看整体还是比较简单的,大家赶紧在Odoo中操作起来吧!

简单几步就实现了

在Odoo上集成ECharts

感兴趣可以去试试

如果你有更好的办法或疑问

欢迎加入社群一起讨论哦⬇


本期作者

丁涛

原文链接: http://mp.weixin.qq.com/s?__biz=Mzg5MzUyOTgwMQ==&mid=2247518643&idx=1&sn=eea777c74d3a65f68c652e782d3c1c42&chksm=c02fb215f7583b03374c35c6770ef81275c0c86b2b2b8abeb886dcff83281748d5a2e889fffb#rd