logo资料库

基于HTML5WebGL的3D仓储管理系统.pdf

第1页 / 共21页
第2页 / 共21页
第3页 / 共21页
第4页 / 共21页
第5页 / 共21页
第6页 / 共21页
第7页 / 共21页
第8页 / 共21页
资料共21页,剩余部分请下载后查看
基于基于HTML5WebGL的的3D仓储管理系统 仓储管理系统 仓储管理系统(WMS)是一个实时的计算机软件系统,它能够按照运作的业务规则和运算法则,对信息、资源、行为、存货 和分销运作进行更完美地管理,使其最大化满足有效产出和精确性的要求。从财务软件、进销存软件CIMS,从MRP、MRPII 到ERP,代表了中国企业从粗放型管理走向集约管理的要求,竞争的激烈和对成本的要求使得管理对象表现为:整和上游、 企业本身、下游一体化供应链的信息和资源。而仓库,尤其是制造业中的仓库,作为链上的节点,不同链节上的库存观不同, 在物流供应链的管理中,不再把库存作为维持生产和销售的措施,而将其作为一种供应链的平衡机制,其作用主要是协调整个 供应链。但现代企业同时又面临着许多不确定因素,无论他们来自分供方还是来自生产或客户,对企业来说处理好库存管理与 不确定性关系的唯一办法是加强企业之间信息的交流和共享,增加库存决策信息的透明性、可靠性和实时性。而这,正是 WMS所要帮助企业解决的问题。 WMS软件和进销存管理软件的最大区别在于:进销存软件的目标是针对于特定对象(如仓库)的商品、单据流动,是对于仓 库作业结果的记录、核对和管理——报警、报表、结果分析,比如记录商品出入库的时间、经手人等;而WMS软件则除了管 理仓库作业的结果记录、核对和管理外最大的功能是对仓库作业过程的指导和规范:即不但对结果进行处理,更是通过对作业 动作的指导和规范保证作业的准确性、速度和相关记录数据的自动登记(入计算机系统),增加仓库的效率、管理透明度、真 实度降低成本比如通过无线终端指导操作员给某定单发货:当操作员提出发货请求时,终端提示操作员应到哪个具体的仓库货 位取出指定数量的那几种商品,扫描货架和商品条码核对是否正确,然后送到接货区,录入运输单位信息,完成出货任务,重 要的是包括出货时间、操作员、货物种类、数量、产品序列号、承运单位等信息在货物装车的同时已经通过无线方式传输到了 计算机信息中心数据库。 由于市场需求量较大,我们来好好解析今天这个例子。 本例地址:http://www.hightopo.com/demo/... 动图如下: 可以在 http://download.csdn.net/down... 下载代码。具体运行代码请参考 readme.html。 这个例子是采用 es6 的模块化的方式部署的。打开 index.html 进入 lib/index.js,源码是在 src 文件夹中,我们直接进 src/view 下的 index.js 在顶部加载其他模块中含有 export 接口的模块:
import sidebar from './sidebar.js'; import header from './header.js'; import BorderLayout from './common/BorderLayout.js'; import shelfPane from './common/shelfPane.js'; import chartPane from './common/chartPane.js'; import graph3dView from './3d/index'; 我们将页面上的每个部分分开来放在不同的 js 文件中,就是上面加载的 js export 的部分,根层容器 BorderLayout(整体最外 层的 div),整张图上的部分都是基于 borderLayout 的。 最外层容器 BorderLayout 是在 src/view/common 下的 BorderLayout.js 中自定义的类,其中 ht.Default.def(className, superClass, methods) 是 HT 中封装的自定义类的函数,其中 className 为自定义类名, superClass 为要继承的父 类,methods 为方法和变量声明,要使用这个方法要先在外部定义这个函数变量,通过 functionName.superClass.constructor.call(this) 方法继承。BorderLayout 自定义类继承了 ht.ui.drawable.BorderLayout 布局 组件,此布局器将自身空间划分为上、下、左、右、中间五个区域,每个区域可以放置一个子组件。为了能正常交互,重写 getSplitterAt 函数将 splitterRect 的宽度修改为 10,以及为了调整左侧 splitterCanvas 的尺寸,以便挡住子组件而重写的 layoutSplitterCanvas 两个方法: let BorderLayout = function() { BorderLayout.superClass.constructor.call(this); this.setContinuous(true); this.setSplitterSize(0); }; ht.Default.def(BorderLayout, ht.ui.BorderLayout, {//自定义类 /** * splitter 宽度都为 0,为了能正常交互,重写此函数将 splitterRect 的宽 度修改为 10 * @override */ getSplitterAt: function (event) {//获取事件对象下分隔条所在的区域 var leftRect = this._leftSplitterRect, lp; if (leftRect) { leftRect = ht.Default.clone(leftRect); leftRect.width = 10; leftRect.x -= 5; if (event instanceof Event) lp = this.lp(event); else lp = event; if (ht.Default.containsPoint(leftRect, lp)) return 'left'; } return BorderLayout.superClass.getSplitterAt.call(this, event); }, /** * 调整左侧 splitterCanvas 的尺寸,以便挡住子组件 * @override */ layoutSplitterCanvas: function(canvas, x, y, width, height, region) { if (region === 'left') { canvas.style.pointerEvents = ''; canvas.style.display = 'block'; ht.Default.setCanvas(canvas, 10, height); canvas.style.left = this.getContentLeft() + this.tx() + x - 5 + 'px'; canvas.style.top = this.getContentTop() + this.ty() + y + 'px'; } else { BorderLayout.superClass.layoutSplitterCanvas.call(this, canvas, x, y, width, height, region); } } }); export default BorderLayout; 左侧栏 sidebar,分为 8 个部分:顶部 logo、货位统计表格、进度条、分割线、货物表格、图表、管理组、问题反馈按钮等。
可以查看 src/view 下的 sidebar.js 文件,这个 js 文件中同样加载了 src/view/common 下的TreeHoverBackgroundDrawable.js 和 ProgressBarSelectBarDrawable.js 中的 TreeHoverBackgroundDrawable 和 ProgressBarSelectBarDrawable 变量,以及 src/controller 下的 sidebar.js 中的 controller 变量: import TreeHoverBackgroundDrawable from './common/TreeHoverBackgroundDrawable.js'; import ProgressBarSelectBarDrawable from './common/ProgressBarSelectBarDrawable.js'; import controller from '../controller/sidebar.js'; HT 封装了一个 ht.ui.VBoxLayout 函数,用来将子组件放置在同一垂直列中,我们可以将左侧栏要显示的部分都放到这个组件 中,这样所有的部分都是以垂直列排布:
let vBoxLayout = new ht.ui.VBoxLayout();//此布局器将子组件放置在同一 垂直列中; vBoxLayout.setBackground('#17191a'); 顶部 logo 是根据在 Label 标签上添加 icon 的方法来实现的,并将这个 topLabel 添加进垂直列 vBoxLayout 中: let topLabel = new ht.ui.Label(); //标签组件 topLabel.setText('Demo-logo');//设置文字内容 topLabel.setIcon('imgs/logo.json');//设置图标,可以是颜色或者图片等 topLabel.setIconWidth(41); topLabel.setIconHeight(37); topLabel.setTextFont('18px arial, sans-serif'); topLabel.setTextColor('#fff'); topLabel.setPreferredSize(1, 64);//组件自身最合适的尺寸 topLabel.setBackground('rgb(49,98,232)'); vBoxLayout.addView(topLabel, {//将子组件加到容器中 width: 'match_parent'//填满父容器 }); 对于“货位统计表格”,我们采用的是 HT 封装的 TreeTableView 组件,以树和表格的组合方式呈现 DataModel 中数据元素属 性及父子关系,并将这个“树表”添加进垂直列 vBoxLayout 中: let shelfTreeTable = new ht.ui.TreeTableView();//树表组件,以树和表格 的组合方式呈现 DataModel 中数据元素属性及父子关系 shelfTreeTable.setHoverBackgroundDrawable(new TreeHoverBackgroundDrawable('#1ceddf', 2));//设置 hover 状态下行选 中背景的 Drawable 对象 shelfTreeTable.setSelectBackgroundDrawable(new TreeHoverBackgroundDrawable('#1ceddf', 2));//设置行选中背景的 Drawable 对象 参数为“背景 shelfTreeTable.setBackground(null); shelfTreeTable.setIndent(20);//设置不同层次的缩进值 shelfTreeTable.setColumnLineVisible(false);//设置列线是否可见 shelfTreeTable.setRowLineVisible(false); shelfTreeTable.setExpandIcon('imgs/expand.json');//设置展开图标图 标,可以是颜色或者图片等 shelfTreeTable.setCollapseIcon('imgs/collapse.json');//设置合并图标图 标,可以是颜色或者图片等 shelfTreeTable.setPreferredSizeRowCountLimit();//设置计算 preferredSize 时要限制的数据行数 shelfTreeTable.setId('shelfTreeTable'); vBoxLayout.addView(shelfTreeTable, { width: 'match_parent', height: 'wrap_content',//组件自身首选高度 marginTop: 24, marginLeft: 4, marginRight: 4 }); 我们在设置“行选中”时背景传入了一个 TreeHoverBackgroundDrawable 对象,这个对象是在 srcviewcommon 下的 TreeHoverBackgroundDrawable.js 文件中定义的,其中 ht.Default.def(className, superClass, methods) 是 HT 中封装的自 定义类的函数,其中 className 为自定义类名, superClass 为要继承的父类,methods 为方法和变量声明,要使用这个方 法要先在外部定义这个函数变量,通过 functionName.superClass.constructor.call(this) 方法继承。 TreeHoverBackgroundDrawable 自定义类继承了 ht.ui.drawable.Drawable 组件用于绘制组件背景、图标等,只重写了 draw 和 getSerializableProperties 两个方法,我们在 draw 方法中重绘了 shelfTreeTable 的行选中背景色,并重载了 getSerializableProperties 序列化组件函数,并将 TreeHoverBackgroundDrawable 传入的参数作为 map 中新添加的属性:
let TreeHoverBackgroundDrawable = function(color, width) { TreeHoverBackgroundDrawable. superClass. constructor.call(this); this.setColor(color); this.setWidth(width); }; ht.Default.def(TreeHoverBackgroundDrawable, ht.ui.drawable.Drawable, { ms_ac: ['color', 'width'], draw: function(x, y, width, height, data, view, dom) { var self = this, g = view.getRootContext(dom), color = self.getColor(); g.beginPath(); g.fillStyle = color; g.rect(x, y, self.getWidth(), height); g.fill(); }, getSerializableProperties: function() { var parentProperties = TreeHoverBackgroundDrawable. superClass.getSerializableProperties. call(this); return addMethod(parentProperties, { color: 1, width: 1 }); } }); 记住要导出 TreeHoverBackgroundDrawable : export default TreeHoverBackgroundDrawable; HT 还封装了非常好用的 ht.ui.ProgressBar 组件,可直接绘制进度条: let progressBar = new ht.ui.ProgressBar(); progressBar.setId('progressBar'); progressBar.setBackground('#3b2a00');//设置组件的背景,可以是颜色 或者图片等 progressBar.setBar('rgba(0,0,0,0)');//设置进度条背景,可以是颜色或者 图片等 progressBar.setPadding(5); progressBar.setSelectBarDrawable(new ProgressBarSelectBarDrawable('#c58348', '#ffa866')); //设置前景(即进度 覆盖区域)的 Drawable 对象,可以是颜色或者图片等 progressBar.setValue(40);//设置当前进度值 progressBar.setBorderRadius(0); vBoxLayout.addView(progressBar, { marginTop: 24, width: 'match_parent', height: 28, marginBottom: 24, marginLeft: 14, marginRight: 14 }); 我们在 设置“前景”的时候传入了一个 ProgressBarSelectBarDrawable 对象,这个对象在 srcviewcommon 下的 ProgressBarSelectBarDrawable.js 中定义的。具体定义方法跟上面的 TreeHoverBackgroundDrawable 函数对象类似,这里 不再赘述。 分割线的制作最为简单,只要将一个矩形的高度设置为 1 即可,我们用 ht.ui.View() 组件来制作:
let separator = new ht.ui.View();//所有视图组件的基类,所有可视化组件 都必须从此类继承 separator.setBackground('#666'); vBoxLayout.addView(separator, { width: 'match_parent', height: 1, marginLeft: 14, marginRight: 14, marginBottom: 24 }); 货物表格的操作几乎和货位统计表格相同,这里不再赘述。 我们将一个 json 的图表文件当做图片传给图表的组件容器作为背景,也能很轻松地操作: let chartView = new ht.ui.View(); chartView.setBackground('imgs/chart.json'); vBoxLayout.addView(chartView, { width: 173, height: 179, align: 'center', marginBottom: 10 }); 管理组和顶部 logo 的定义方式类似,这里不再赘述。 问题反馈按钮,我们将这个部分用 HT 封装的 ht.ui.Button 组件来制作,并将这个部分添加进垂直列 vBoxLayout 中: let feedbackButton = new ht.ui.Button();//按钮类 feedbackButton.setId('feedbackButton'); feedbackButton.setText('问题反馈:service@hightopo.com'); feedbackButton.setIcon('imgs/em.json'); feedbackButton.setTextColor('#fff'); feedbackButton.setHoverTextColor( shelfTreeTable.getHoverLabelColor());//设置 hover 状态下文字颜色 feedbackButton.setActiveTextColor( feedbackButton.getHoverTextColor());//设置 active 状态下文字颜色 feedbackButton.setIconWidth(16); feedbackButton.setIconHeight(16); feedbackButton.setIconTextGap(10); feedbackButton.setAlign('left'); feedbackButton.setBackground(null); feedbackButton.setHoverBackground(null); feedbackButton.setActiveBackground(null); vBoxLayout.addView(feedbackButton, { width: 'match_parent', marginTop: 5, marginBottom: 10, marginLeft: 20 }); 视图部分做好了,在模块化开发中,controller 就是做交互的部分,shelfTreeTable 货位统计表格, cargoTreeTable 货物表 格, feedbackButton 问题反馈按钮, progressBar 进度条四个部分的交互都是在在 src/controller 下的 sidebar.js 中定义的。 通过 findViewById(id, recursive) 根据id查找子组件,recursive 表示是否递归查找。 shelfTreeTable 货位统计表格的数据绑定传输方式与 cargoTreeTable 货物表格类似,这里我们只对 shelfTreeTable 货位统计 表格的数据绑定进行解析。shelfTreeTable 一共有三列,其中不同的部分只有“已用”和“剩余”两个部分,所以我们只要将这两 个部分进行数据绑定即可,先创建两列:
let column = new ht.ui.Column();//列数据,用于定义表格组件的列信息 column.setName('used');//设置数据元素名称 column.setAccessType('attr');//在这里 name 为 used,采用 getAttr('used') 和 setAttr('used', 98) 的方式存取 set/getAttr 简写为 a column.setWidth(65); column.setAlign('center'); columnModel.add(column); column = new ht.ui.Column(); column.setName('remain'); column.setAccessType('attr'); column.setWidth(65); column.setAlign('center'); columnModel.add(column); 接着遍历 json 文件,将 json 文件中对应的 used、remain以及 labelColors 通过 set/getAttr 或 简写 a 的方式进行数据绑定: for (var i = 0; i < json.length; i++) { var row = json[i];//获取 json 中的属性 var data = new ht.Data(); data.setIcon(row.icon);//将 json 中的 icon 传过来 data.setName(row.name); data.a('used', row.used); data.a('remain', row.remain); data.a('labelColors', row.colors); data.setIcon(row.icon); treeTable.dm().add(data);//在树表组件的数据模型中添加这个data节点 var children = row.children; if (children) { for (var j = 0; j < children.length; j++) { var child = children[j]; var childData = new ht.Data(); childData.setName(child.name); childData.setIcon(child.icon); childData.a('used', child.used); childData.a('remain', child.remain); childData.a('labelColors', child.colors); childData.setParent(data); treeTable.dm().add(childData); } } } 最后在 controller 函数对象中调用 这个函数: initTreeTableDatas(shelfTreeTable, json);//json 为 ../model/shelf.json传 入 progressBar 进度条的变化是通过设置定时器改变 progressBar 的 value 值来动态改变的: setInterval(() => { if (progressBar.getValue() >= 100) { progressBar.setValue(0); } progressBar.setValue(progressBar.getValue() + 1); }, 50); feedbackButton 问题反馈按钮,通过增加 View 事件监听器来监听按钮的点击事件: feedbackButton.addViewListener(e => { if (e.kind === 'click') {//HT 自定义的事件属性,具体查看 http://hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html window.location.href = "mailto:service@www.hightopo.com";//当前页面 打开URL页面 } });
右侧根容器 splitLayout 直接用的分割组件 ht.ui.SplitLayout 进行分割布局: let splitLayout = new ht.ui.SplitLayout();//此布局器将自身空间划分为上、下两个区域或左、右两个区域,每个区域可以放置一 个子组件 splitLayout.setSplitterVisible(false); splitLayout.setPositionType('absoluteFirst'); splitLayout.setOrientation('v'); 右侧头部 header 这个 header 是从 src/view 下的 header.js 中获取的对象,为 ht.ui.RelativeLayout 相对定位布局器,分为 5 个部分: searchField 搜索框、titleLabel 主标题、temperatureLabel1 温度、humidityLabel1 湿度以及 airpressureLabel1 气压。 这里我们没有对“搜索框” searchField 进行数据绑定,以及搜索的功能,这只是一个样例,不涉及业务部分: let searchField = new ht.ui.TextField();//文本框组件 searchField.setBorder(new ht.ui.border.LineBorder(1, '#d8d8d8'));//在组 件的画布上绘制直线边框 searchField.setBorderRadius(12); searchField.setBackground(null); searchField.setIcon('imgs/search.json'); searchField.setIconPosition('left'); searchField.setPadding([2, 16, 2, 16]); searchField.setColor('rgb(138, 138, 138)'); searchField.setPlaceholder('Find everything...'); searchField.getView().className = 'search'; header.addView(searchField, { width: 180, marginLeft: 20, vAlign: 'middle' }); 对于 titleLabel 主标题比较简单,和温度、湿度以及气压类似,我就只说明一下主标题 titleLabel 的定义:
分享到:
收藏