zStack 扩展开发流程-zstack-dashboard部分
来源:互联网 发布:php支付宝sdk下载 编辑:程序博客网 时间:2024/06/10 00:34
本流程是基于开源项目zstack的扩展开发流程。以一个具体业务为例进行说明
目标
添加一个新的业务模块:公有云账户管理。实现效果为在界面的左边计算选项添加一个账户管理。在账户管理中可以添加、删除账户信息。
流程
前端zstack-dashboard
在前端主要是界面UI的开发,以及相关API的设计。
一、创建html文件
编辑位置:[zStack-dashboard/zstack_dashboard/static/templates]
在此路径下添加需要添加的文件夹,命名为pubAccount。文件夹下面创建pubAccount.html文件。此文件为主界面的显示文件。createPubAccount.html,为创建账户信息的显示界面。
pubAccount.html
<div style="display: none"> <div z-create-pubaccount="winNewPubAccount" z-options="optionsCreateCluster"></div> //!!!!!这里的命名需要注意,z-create-pubaccount需要与js部分的命名一直 <div z-search="search" z-options="optionsSearch"></div> </div> <div> <h3 class="z-h3">账户管理</h3> <div class="btn-group-sm z-btn-bar"> <button type="button" class="btn btn-default btn-sm" ng-click="funcRefresh()"> <i class="fa fa-refresh"></i> </button> <button type="button" class="btn btn-default btn-sm" ng-click="funcSearch(search)"> <i class="fa fa-search"></i> </button> <div z-sort-by z-options="optionsSortBy"></div> <button z-popover="popoverFilterBy" type="button" id="vmInstanceFilter" z-content-id="vmInstanceFilterContent" class="btn btn-default btn-sm" ng-click="filterBy.open(popoverFilterBy)"> <i class="fa fa-filter"></i><span> {{filterBy.getButtonName()}}</span> </button> <div class="btn-group" > <button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown" > 添加账户信息<span class="caret"></span> </button> <ul class="dropdown-menu" role="menu"> <li><a href ng-click="funcCreatePubAccount(winNewPubAccount)" >添加云厂商信息</a></li> //!!!!功能函数在js部分实现,传入参数命名和上面的一样 <li class="divider"></li> </ul> </div> <div id="vmInstanceFilterContent" style="display: none"> <form class="form"> <div class="form-group"> <label for="fieldList" class="z-block-label">{{"vm.vm.FILTER BY" | translate}}</label> <select id="fieldList" kendo-drop-down-list k-options="filterBy.fieldList" ng-model="filterBy.field"></select> </div> <div class="form-group"> <label class="z-block-label" for="valueList">{{"vm.vm.VALUE" | translate}}</label> <select kendo-drop-down-list id="valueList" ng-disabled="filterBy.isValueListDisabled()" k-options="filterBy.valueList" ng-model="filterBy.value"></select> </div> <button type="button" class="btn btn-sm btn-primary" ng-click="filterBy.confirm(popoverFilterBy)">{{"vm.vm.Confirm" | translate}}</button> </form> </div> <div class="btn-group" ng-show="funcIsActionShow()"> <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" ng-disabled="funcIsActionDisabled()"> {{"vm.vm.Action" | translate}} <span class="caret"></span> </button> <ul class="dropdown-menu" role="menu"> <li><a href ng-click="action.stop()" ng-show="action.isActionShow('stop')">修改</a></li> <li class="divider"></li> <li><a href style="color:red" ng-click="funcDeletepubAccount(pubAccountDelete)" ng-show="action.isActionShow('delete')">{{"vm.vm.Delete" | translate}}</a></li> </ul> </div> </div> <div kendo-grid="pubAccountGrid" k-options="oPubAccountGrid.options" z-grid-double-click="funcGridDoubleClick" class="z-flat-table"></div> //!!!此处是js部分的,描述表格信息的,k-options需要和js部分一致 <p class="z-hint">{{"vm.vm.HINT1" | translate}}</p> <p class="z-hint">{{"vm.vm.HINT2" | translate}}</p> </div>
createPubAccount.html
<div kendo-window="winCreatePubAccount__" k-visible="false" k-options="winCreatePubAccountOptions__"> //修改window参数为js部分 <div class="row"> <div class="col-sm-15"> <div class="tab-content"> <div id="createClusterInfo" class="tab-pane active"> <div class="alert alert-warning col-sm-21" ng-show="!infoPage.hasPubCloudType()"> 没有已经注册的云类型 </div> <h4 class="z-win-h4">账户管理</h4> <form class="form"> <div class="form-group col-sm-24"> <label for="PubCloudType">云厂商</label> <select id="PubCloudType" kendo-drop-down-list k-options="PubCloudTypeList" class="z-win-dropdown" ng-model="infoPage.PubCloudType"></select> </div> <div class="form-group col-lg-18"> <p class="z-hint">请根据该类型资源所需的必填项进行填写</p> <label for="name">用户名</label> <input class="form-control" type="text" id="name" placeholder="(Required) max length of 255 characters" ng-model="modelCreateZone.name" required data-message="name is required"> </div> <div class="form-group col-lg-18"> <label for="name">密码</label> <input class="form-control" type="text" id="name" placeholder="(Required) max length of 255 characters" ng-model="modelCreateZone.name" required data-message="name is required"> </div> <div class="form-group col-lg-18"> <label for="name">accesskeyID</label> <input class="form-control" type="text" id="name" placeholder="(Required) max length of 255 characters" ng-model="modelCreateZone.name" required data-message="name is required"> </div> <div class="form-group col-lg-18"> <label for="name">accesskeyKey</label> <input class="form-control" type="text" id="name" placeholder="(Required) max length of 255 characters" ng-model="modelCreateZone.name" required data-message="name is required"> </div> <div class="form-group col-lg-18"> <label for="name">token</label> <input class="form-control" type="text" id="name" placeholder="(Required) max length of 255 characters" ng-model="modelCreateZone.name" required data-message="name is required"> </div> <div class="form-group col-lg-18"> <label for="description">{{"zone.zone.DESCRIPTION" | translate}}</label> <textarea class="form-control" rows="5" id="description" placeholder="(Optional) max length of 2048 characters" ng-model="modelCreateZone.description"></textarea> </div> </form> </div> <div class="form-group col-sm-18"> <button type="button" class="btn btn-default" ng-click="button.previousClick()" ng-disabled="!button.canPreviousProceed()">{{"cluster.createCluster.Previous" | translate}}</button> <button type="button" class="btn btn-primary" ng-disabled="!button.canNextProceed()" ng-click="button.nextClick()">{{button.nextButtonName()}}</button> </div> </div> </div> <div class="col-sm-7 z-wizard-bar"> <ul class="nav"> <!-- 注意根据具体有几个页面进行修改--> <li class="active"><a data-target="#createClusterInfo" ng-click="button.pageClick('createClusterInfo')">{{"cluster.createCluster.CLUSTER INFO" | translate}}</a></li> </ul> </div> </div></div>
二、添加JS部分
编辑文件:[vStack-dashboard/zstack_dashboard/static/app/app.js]
js部分需要实现angularJS的代码.
var MPubAccount;(function (MPubAccount) { var PubAccount = (function (_super) { __extends(PubAccount, _super); function PubAccount() { _super.apply(this, arguments); } PubAccount.prototype.progressOn = function () { this.inProgress = true; }; PubAccount.prototype.progressOff = function () { this.inProgress = false; }; PubAccount.prototype.isInProgress = function () { return this.inProgress; }; PubAccount.prototype.isEnableShow = function () { return this.state == 'Disabled'; }; PubAccount.prototype.isDisableShow = function () { return this.state == 'Enabled'; }; PubAccount.prototype.stateLabel = function () { if (this.state == 'Enabled') { return 'label label-success'; } else if (this.state == 'Disabled') { return 'label label-danger'; } else { return 'label label-default'; } }; PubAccount.prototype.gridColumnLabel = function () { if (this.state == 'Enabled') { return 'z-color-box-green'; } else if (this.state == 'Disabled') { return 'z-color-box-red'; } };//描述在账户管理中有哪些数据 PubAccount.prototype.updateObservableObject = function (inv) { // self : ObservableObject var self = this; self.set('name', inv.name); self.set('description', inv.description); self.set('hypervisorType', inv.hypervisorType); self.set('state', inv.state); self.set('createDate', inv.createDate); self.set('lastOpDate', inv.lastOpDate); self.set('accesskey', inv.accesskey); }; return PubAccount; }(ApiHeader.PubAccountInventory)); //!!!!PubAccountInventory需要在前面创建 MPubAccount.PubAccount = PubAccount; var PubAccountManager = (function () { function PubAccountManager(api, $rootScope) { this.api = api; this.$rootScope = $rootScope; } PubAccountManager.prototype.setSortBy = function (sortBy) { this.sortBy = sortBy; }; PubAccountManager.prototype.wrap = function (pubAccount) { return new kendo.data.ObservableObject(pubAccount); }; PubAccountManager.prototype.create = function (pubAccount, done) { var _this = this; var msg = new ApiHeader.APICreatePubAccountMsg(); msg.name = pubAccount.name; msg.description = pubAccount.description; msg.pubCloudTyoe = pubAccount.pubCloudTyoe; this.api.asyncApi(msg, function (ret) { var c = new PubAccount(); angular.extend(c, ret.inventory); done(_this.wrap(c)); _this.$rootScope.$broadcast(MRoot.Events.NOTIFICATION, { msg: Utils.sprintf('Created new pubAccount: {0}', c.name), link: Utils.sprintf('/#/pubAccount', c.uuid) }); }); }; PubAccountManager.prototype.query = function (qobj, callback) { var _this = this; var msg = new ApiHeader.APIQueryPubAccountMsg(); //!!!!APIQueryPubAccountMsg需要在前面创建 msg.count = qobj.count === true; msg.start = qobj.start; msg.limit = qobj.limit; msg.replyWithCount = true; msg.conditions = qobj.conditions ? qobj.conditions : []; if (Utils.notNullnotUndefined(this.sortBy) && this.sortBy.isValid()) { msg.sortBy = this.sortBy.field; msg.sortDirection = this.sortBy.direction; } this.api.syncApi(msg, function (ret) { var clusters = []; ret.inventories.forEach(function (inv) { var c = new PubAccount(); angular.extend(c, inv); clusters.push(_this.wrap(c)); }); callback(clusters, ret.total); }); }; PubAccountManager.prototype.delete = function (pubAccount, done) { var _this = this; pubAccount.progressOn(); var msg = new ApiHeader.APIDeletePubAccountMsg(); //!!!!APIDeletePubAccountMsg需要在前面创建 msg.uuid = pubAccount.uuid; this.api.asyncApi(msg, function (ret) { pubAccount.progressOff(); done(ret); _this.$rootScope.$broadcast(MRoot.Events.NOTIFICATION, { msg: Utils.sprintf('Deleted cluster: {0}', pubAccount.name) }); }); }; PubAccountManager.$inject = ['Api', '$rootScope']; return PubAccountManager; }()); MPubAccount.PubAccountManager = PubAccountManager; var PubAccountModel = (function () { function PubAccountModel() { this.current = new PubAccount(); } PubAccountModel.prototype.resetCurrent = function () { this.current = null; }; PubAccountModel.prototype.setCurrent = function ($scope, PubAccount) { this.current = PubAccount; }; return PubAccountModel; }()); MPubAccount.PubAccountModel = PubAccountModel; var oPubAccountGrid = (function (_super) { __extends(oPubAccountGrid, _super); function oPubAccountGrid($scope, pubAccountMgr) { _super.call(this); this.pubAccountMgr = pubAccountMgr; _super.prototype.init.call(this, $scope, $scope.pubAccountGrid); //描述表格格式 this.options.columns = [ { field: 'username', title: 'username', width: '15%', template: '<a href="/\\#/cluster/{{dataItem.uuid}}">{{dataItem.name}}</a>' }, { field: 'accesskey', title: 'accesskey', width: '15%', template: '<a href="/\\#/cluster/{{dataItem.uuid}}">{{dataItem.name}}</a>' }, { field: 'token', title: 'token', width: '15%' }, { field: 'description', title: 'description', width: '25%' }, { field: 'state', title: 'state', width: '15%', template: '<span class="{{dataItem.stateLabel()}}">{{dataItem.state}}</span>' }, { field: 'uuid', title: '{{"cluster.ts.UUID" | translate}}', width: '30%' } ]; this.options.dataSource.transport.read = function (options) { var qobj = new ApiHeader.QueryObject(); qobj.limit = options.data.take; qobj.start = options.data.pageSize * (options.data.page - 1); pubAccountMgr.query(qobj, function (pubAccounts, total) { options.success({ data: pubAccounts, total: total }); }); }; } return oPubAccountGrid; }(Utils.OGrid)); var Action = (function () { function Action($scope, pubAccountMgr) { this.$scope = $scope; this.pubAccountMgr = pubAccountMgr; } Action.prototype.enable = function () { this.pubAccountMgr.enable(this.$scope.model.current); }; Action.prototype.disable = function () { this.pubAccountMgr.disable(this.$scope.model.current); }; return Action; }()); var FilterBy = (function () { function FilterBy($scope, hypervisorTypes) { var _this = this; this.$scope = $scope; this.hypervisorTypes = hypervisorTypes; this.fieldList = { dataSource: new kendo.data.DataSource({ data: [ { name: '{{"cluster.ts.None" | translate}}', value: FilterBy.NONE }, { name: '{{"cluster.ts.State" | translate}}', value: FilterBy.STATE }, { name: '{{"cluster.ts.Hypervisor" | translate}}', value: FilterBy.HYPERVISOR } ] }), dataTextField: 'name', dataValueField: 'value' }; this.valueList = { dataSource: new kendo.data.DataSource({ data: [] }) }; this.field = FilterBy.NONE; $scope.$watch(function () { return _this.field; }, function () { if (_this.field == FilterBy.NONE) { _this.valueList.dataSource.data([]); _this.value = null; } else if (_this.field == FilterBy.STATE) { _this.valueList.dataSource.data(['Enabled', 'Disabled']); } else if (_this.field == FilterBy.HYPERVISOR) { _this.valueList.dataSource.data(_this.hypervisorTypes); } }); } FilterBy.prototype.confirm = function (popover) { console.log(JSON.stringify(this.toKendoFilter())); this.$scope.oPubAccountGrid.setFilter(this.toKendoFilter()); this.name = !Utils.notNullnotUndefined(this.value) ? null : Utils.sprintf('{0}:{1}', this.field, this.value); popover.toggle(); }; FilterBy.prototype.open = function (popover) { popover.toggle(); }; FilterBy.prototype.isValueListDisabled = function () { return !Utils.notNullnotUndefined(this.value); }; FilterBy.prototype.getButtonName = function () { return this.name; }; FilterBy.prototype.toKendoFilter = function () { if (!Utils.notNullnotUndefined(this.value)) { return null; } return { field: this.field, operator: 'eq', value: this.value }; }; FilterBy.NONE = 'none'; FilterBy.STATE = 'state'; FilterBy.HYPERVISOR = 'hypervisorType'; return FilterBy; }()); var Controller = (function () { function Controller($scope, pubAccountMgr, $location) { //!!!根据具体的业务传入参数 this.$scope = $scope; this.pubAccountMgr = pubAccountMgr; this.$location = $location; $scope.model = new PubAccountModel(); $scope.oPubAccountGrid = new oPubAccountGrid($scope, pubAccountMgr); $scope.action = new Action($scope, pubAccountMgr); $scope.optionsSortBy = { fields: [ { name: '{{"cluster.ts.Name" | translate}}', value: 'name' }, { name: '{{"cluster.ts.Description" | translate}}', value: 'Description' }, { name: '{{"cluster.ts.State" | translate}}', value: 'state' }, { name: '{{"cluster.ts.Hypervisor" | translate}}', value: 'hypervisorType' }, { name: '{{"cluster.ts.Created Date" | translate}}', value: 'createDate' }, { name: '{{"cluster.ts.Last Updated Date" | translate}}', value: 'lastOpDate' } ], done: function (ret) { pubAccountMgr.setSortBy(ret); $scope.oPubAccountGrid.refresh(); } }; $scope.optionsSearch = { fields: ApiHeader.ClusterInventoryQueryable, name: 'CLUSTER', schema: { state: { type: Directive.SearchBoxSchema.VALUE_TYPE_LIST, list: ['Enabled', 'Disabled'] }, hypervisorType: { type: Directive.SearchBoxSchema.VALUE_TYPE_LIST, list: this.hypervisorTypes }, createDate: { type: Directive.SearchBoxSchema.VALUE_TYPE_TIMESTAMP }, lastOpDate: { type: Directive.SearchBoxSchema.VALUE_TYPE_TIMESTAMP } }, done: function (ret) { var qobj = new ApiHeader.QueryObject(); qobj.conditions = ret; pubAccountMgr.query(qobj, function (clusters, total) { $scope.oPubAccountGrid.refresh(clusters); }); } }; $scope.filterBy = new FilterBy($scope, this.hypervisorTypes); $scope.funcSearch = function (win) { win.open(); }; $scope.funcCreatePubAccount = function (win) { //!!!!创建窗口函数,和html页面一致 win.open(); }; $scope.funcDeletePubAccount = function (win) { $scope.deletePubAccount.open(); }; $scope.optionsDeletePubAccount = { title: 'DELETE PubAccount', description: 'Are you sure?', confirm: function () { pubAccountMgr.delete($scope.model.current, function (ret) { $scope.oPubAccountGrid.deleteCurrent(); }); } }; $scope.funcRefresh = function () { $scope.oPubAccountGrid.refresh(); }; $scope.funcIsActionShow = function () { return !Utils.isEmptyObject($scope.model.current); }; $scope.funcIsActionDisabled = function () { return Utils.notNullnotUndefined($scope.model.current) && $scope.model.current.isInProgress(); }; $scope.optionsCreatePubAccount= { done: function (cluster) { $scope.oPubAccountGrid.add(cluster); } }; } Controller.$inject = ['$scope', 'PubAccountManager', '$location']; return Controller; }()); MPubAccount.Controller = Controller; var CreatePubAccountOptions = (function () { function CreatePubAccountOptions() { } return CreatePubAccountOptions; }()); MPubAccount.CreatePubAccountOptions = CreatePubAccountOptions; var CreatePubAccount = (function () { function CreatePubAccount(api, pubAccountMgr) { var _this = this; this.api = api; this.pubAccountMgr = pubAccountMgr; this.scope = true; this.link = function ($scope, $element, $attrs, $ctrl, $transclude) { var instanceName = $attrs.zCreatePubaccount; //!!!!!与html部分一致 var parentScope = $scope.$parent; parentScope[instanceName] = _this; _this.options = new CreatePubAccountOptions(); //注意修改 var optionName = $attrs.zOptions; if (angular.isDefined(optionName)) { _this.options = parentScope[optionName]; $scope.$watch(function () { return parentScope[optionName]; }, function () { _this.options = parentScope[optionName]; }); } var infoPage = $scope.infoPage = { activeState: true, name: null, description: null, accesskey: null, canMoveToPrevious: function () { return false; }, hasPubCloudType: function () { //注意修改 return $scope.PubCloudTypeList.dataSource.data().length > 0; }, canMoveToNext: function () { return true; }, show: function () { this.getAnchorElement().tab('show'); }, getAnchorElement: function () { return $('.nav a[data-target="#createPubAccountInfo"]'); }, active: function () { this.activeState = true; }, isActive: function () { return this.activeState; }, getPageName: function () { return 'createPubAccountInfo'; }, reset: function () { this.name = Utils.shortHashName("PubAccount"); this.PubCloudType = null; this.description = null; this.username = null; this.password = null; this.accesskey = null; this.accessID = null; this.token = null; this.activeState = false; } }; var mediator = $scope.mediator = { currentPage: infoPage, movedToPage: function (page) { $scope.mediator.currentPage = page; }, finishButtonName: function () { return "Create"; }, finish: function () { var resultCluster; var chain = new Utils.Chain(); chain.then(function () { pubAccountMgr.create(infoPage, function (ret) { resultCluster = ret; chain.next(); }); }).done(function () { if (Utils.notNullnotUndefined(_this.options.done)) { _this.options.done(resultCluster); } $scope.winCreatePubAccount__.close(); //注意修改 }).start(); } }; $scope.button = new Utils.WizardButton([ infoPage //注意修改 ], mediator); $scope.PubCloudTypeList = { //注意修改 dataSource: new kendo.data.DataSource({ data: [] }), dataTextField: "type", dataValueField: "type" }; $scope.winCreatePubAccountOptions__ = { //注意修改 width: "700px", //height: "518px", animation: false, modal: true, draggable: false, resizable: false }; _this.$scope = $scope; }; this.restrict = 'EA'; this.replace = true; this.templateUrl = '/static/templates/account/createPubAccount.html'; //注意修改 } CreatePubAccount.prototype.open = function () { var _this = this; var win = this.$scope.winCreatePubAccount__; //注意修改 this.$scope.button.reset(); var chain = new Utils.Chain(); chain.then(function () { chain.next();// _this.api.getPubCloudType(function (pubcloudTypes) {// var types = [];// angular.forEach(pubcloudTypes, function (item) {// types.push({ type: item });// });// _this.$scope.PubCloudTypeList.dataSource.data(new kendo.data.ObservableArray(types));// _this.$scope.model.pubCloudTypes = pubcloudTypes[0];// chain.next();// }); }).done(function () { win.center(); win.open(); }).start(); }; return CreatePubAccount; }()); MPubAccount.CreatePubAccount = CreatePubAccount;})(MPubAccount || (MPubAccount = {}));//注意修改angular.module('root').factory('PubAccountManager', ['Api', '$rootScope', function (api, $rootScope) { return new MPubAccount.PubAccountManager(api, $rootScope); }]).directive('zCreatePubaccount', ['Api', 'PubAccountManager', function (api, PubAccountManager) { return new MPubAccount.CreatePubAccount(api, PubAccountManager); }]).config(['$routeProvider', function (route) { route.when('/pubAccount', { templateUrl: '/static/templates/account/account.html', controller: 'MPubAccount.Controller', }); }]);
三、添加API
编辑文件:【zStack-dashboard/zstack_dashboard/api_messages.py】
在这个文件中将每个在js中所新添加的api放到这里
关于java部分请查看zStack 扩展开发流程-zstack-java部分
0 0
- zStack 扩展开发流程-zstack-dashboard部分
- zStack 扩展开发流程-zstack-java部分
- ZStack
- ZStack
- Zstack Zmain流程
- ZStack启动流程
- ZStack 虚拟路由器工作流程
- zigbee Zstack 开发主要步骤
- zigbee Zstack 开发主要步骤
- zstack(二)zstack二次开发
- ZSTACK协议栈--OSAL主循环流程
- ZStack协议按键处理流程分析
- TI-ZStack(一)Key事件流程
- 06 ZStack的task工作流程分析
- zstack相关
- 接触ZStack
- zstack串口
- ZigBee,ZStack
- Java 使用jxl类库以流的方式实现Excel导入导出
- 设计模式篇
- PHP分页技术原理
- 如何安装NumPy函数库
- NO.10 HTML继续开车
- zStack 扩展开发流程-zstack-dashboard部分
- CSS 框模型概述
- [转载]如何做到有扎实的 Java 基础
- 由n个人做成一排,按顺时针由1开始编号。然后由第一个人开始报数,数到m的人出局。求最后剩下的人的编号。
- hping网络安全工具的安装及使用
- 康托展开 & 康托逆展开
- LINUX 应用编程函数自学手册
- 你应该知道的RPC原理
- Opencv图片识别,问题及结果